blob: 8f6545a95983a244bdaf479a6b1183102a07be28 [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",
William M. Brackee0b9822007-03-07 08:15:01 +0000201 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000202 NULL
203};
204static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205#ifndef LIBXML_THREAD_ENABLED
206/*
207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
209 */
210static int xmlXPathDisableOptimizer = 0;
211#endif
212
Owen Taylor3473f882001-02-23 17:55:21 +0000213/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000214 * *
215 * Error handling routines *
216 * *
217 ************************************************************************/
218
Daniel Veillard24505b02005-07-28 23:49:35 +0000219/**
220 * XP_ERRORNULL:
221 * @X: the error code
222 *
223 * Macro to raise an XPath error and return NULL.
224 */
225#define XP_ERRORNULL(X) \
226 { xmlXPathErr(ctxt, X); return(NULL); }
227
William M. Brack08171912003-12-29 02:52:11 +0000228/*
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000231static const char *xmlXPathErrorMessages[] = {
232 "Ok\n",
233 "Number encoding\n",
234 "Unfinished literal\n",
235 "Start of literal\n",
236 "Expected $ for variable reference\n",
237 "Undefined variable\n",
238 "Invalid predicate\n",
239 "Invalid expression\n",
240 "Missing closing curly brace\n",
241 "Unregistered function\n",
242 "Invalid operand\n",
243 "Invalid type\n",
244 "Invalid number of arguments\n",
245 "Invalid context size\n",
246 "Invalid context position\n",
247 "Memory allocation error\n",
248 "Syntax error\n",
249 "Resource error\n",
250 "Sub resource error\n",
251 "Undefined namespace prefix\n",
252 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000253 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000254 "Invalid or incomplete context\n",
255 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000256};
William M. Brackcd65bc92005-01-06 09:39:18 +0000257#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
258 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259/**
260 * xmlXPathErrMemory:
261 * @ctxt: an XPath context
262 * @extra: extra informations
263 *
264 * Handle a redefinition of attribute error
265 */
266static void
267xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268{
269 if (ctxt != NULL) {
270 if (extra) {
271 xmlChar buf[200];
272
273 xmlStrPrintf(buf, 200,
274 BAD_CAST "Memory allocation failed : %s\n",
275 extra);
276 ctxt->lastError.message = (char *) xmlStrdup(buf);
277 } else {
278 ctxt->lastError.message = (char *)
279 xmlStrdup(BAD_CAST "Memory allocation failed\n");
280 }
281 ctxt->lastError.domain = XML_FROM_XPATH;
282 ctxt->lastError.code = XML_ERR_NO_MEMORY;
283 if (ctxt->error != NULL)
284 ctxt->error(ctxt->userData, &ctxt->lastError);
285 } else {
286 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000287 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 NULL, NULL, XML_FROM_XPATH,
289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290 extra, NULL, NULL, 0, 0,
291 "Memory allocation failed : %s\n", extra);
292 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000293 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000294 NULL, NULL, XML_FROM_XPATH,
295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296 NULL, NULL, NULL, 0, 0,
297 "Memory allocation failed\n");
298 }
299}
300
301/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000302 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000303 * @ctxt: an XPath parser context
304 * @extra: extra informations
305 *
306 * Handle a redefinition of attribute error
307 */
308static void
309xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000311 if (ctxt == NULL)
312 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000313 else {
314 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000315 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000316 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000317}
318
319/**
320 * xmlXPathErr:
321 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000322 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000324 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000325 */
326void
327xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328{
William M. Brackcd65bc92005-01-06 09:39:18 +0000329 if ((error < 0) || (error > MAXERRNO))
330 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000331 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000332 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000333 NULL, NULL, XML_FROM_XPATH,
334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335 XML_ERR_ERROR, NULL, 0,
336 NULL, NULL, NULL, 0, 0,
337 xmlXPathErrorMessages[error]);
338 return;
339 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000340 ctxt->error = error;
341 if (ctxt->context == NULL) {
342 __xmlRaiseError(NULL, NULL, NULL,
343 NULL, NULL, XML_FROM_XPATH,
344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345 XML_ERR_ERROR, NULL, 0,
346 (const char *) ctxt->base, NULL, NULL,
347 ctxt->cur - ctxt->base, 0,
348 xmlXPathErrorMessages[error]);
349 return;
350 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000351
352 /* cleanup current last error */
353 xmlResetError(&ctxt->context->lastError);
354
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000355 ctxt->context->lastError.domain = XML_FROM_XPATH;
356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000358 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361 ctxt->context->lastError.node = ctxt->context->debugNode;
362 if (ctxt->context->error != NULL) {
363 ctxt->context->error(ctxt->context->userData,
364 &ctxt->context->lastError);
365 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000366 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000367 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369 XML_ERR_ERROR, NULL, 0,
370 (const char *) ctxt->base, NULL, NULL,
371 ctxt->cur - ctxt->base, 0,
372 xmlXPathErrorMessages[error]);
373 }
374
375}
376
377/**
378 * xmlXPatherror:
379 * @ctxt: the XPath Parser context
380 * @file: the file name
381 * @line: the line number
382 * @no: the error number
383 *
384 * Formats an error message.
385 */
386void
387xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388 int line ATTRIBUTE_UNUSED, int no) {
389 xmlXPathErr(ctxt, no);
390}
391
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000392/************************************************************************
393 * *
394 * Utilities *
395 * *
396 ************************************************************************/
397
398/**
399 * xsltPointerList:
400 *
401 * Pointer-list for various purposes.
402 */
403typedef struct _xmlPointerList xmlPointerList;
404typedef xmlPointerList *xmlPointerListPtr;
405struct _xmlPointerList {
406 void **items;
407 int number;
408 int size;
409};
410/*
411* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412* and here, we should make the functions public.
413*/
414static int
415xmlPointerListAddSize(xmlPointerListPtr list,
416 void *item,
417 int initialSize)
418{
419 if (list->items == NULL) {
420 if (initialSize <= 0)
421 initialSize = 1;
422 list->items = (void **) xmlMalloc(
423 initialSize * sizeof(void *));
424 if (list->items == NULL) {
425 xmlXPathErrMemory(NULL,
426 "xmlPointerListCreate: allocating item\n");
427 return(-1);
428 }
429 list->number = 0;
430 list->size = initialSize;
431 } else if (list->size <= list->number) {
432 list->size *= 2;
433 list->items = (void **) xmlRealloc(list->items,
434 list->size * sizeof(void *));
435 if (list->items == NULL) {
436 xmlXPathErrMemory(NULL,
437 "xmlPointerListCreate: re-allocating item\n");
438 list->size = 0;
439 return(-1);
440 }
441 }
442 list->items[list->number++] = item;
443 return(0);
444}
445
446/**
447 * xsltPointerListCreate:
448 *
449 * Creates an xsltPointerList structure.
450 *
451 * Returns a xsltPointerList structure or NULL in case of an error.
452 */
453static xmlPointerListPtr
454xmlPointerListCreate(int initialSize)
455{
456 xmlPointerListPtr ret;
457
458 ret = xmlMalloc(sizeof(xmlPointerList));
459 if (ret == NULL) {
460 xmlXPathErrMemory(NULL,
461 "xmlPointerListCreate: allocating item\n");
462 return (NULL);
463 }
464 memset(ret, 0, sizeof(xmlPointerList));
465 if (initialSize > 0) {
466 xmlPointerListAddSize(ret, NULL, initialSize);
467 ret->number = 0;
468 }
469 return (ret);
470}
471
472/**
473 * xsltPointerListFree:
474 *
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
477 */
478static void
479xmlPointerListFree(xmlPointerListPtr list)
480{
481 if (list == NULL)
482 return;
483 if (list->items != NULL)
484 xmlFree(list->items);
485 xmlFree(list);
486}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000487
488/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489 * *
490 * Parser Types *
491 * *
492 ************************************************************************/
493
494/*
495 * Types are private:
496 */
497
498typedef enum {
499 XPATH_OP_END=0,
500 XPATH_OP_AND,
501 XPATH_OP_OR,
502 XPATH_OP_EQUAL,
503 XPATH_OP_CMP,
504 XPATH_OP_PLUS,
505 XPATH_OP_MULT,
506 XPATH_OP_UNION,
507 XPATH_OP_ROOT,
508 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000509 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000510 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000511 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000512 XPATH_OP_VARIABLE,
513 XPATH_OP_FUNCTION,
514 XPATH_OP_ARG,
515 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000516 XPATH_OP_FILTER, /* 17 */
517 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000518#ifdef LIBXML_XPTR_ENABLED
519 ,XPATH_OP_RANGETO
520#endif
521} xmlXPathOp;
522
523typedef enum {
524 AXIS_ANCESTOR = 1,
525 AXIS_ANCESTOR_OR_SELF,
526 AXIS_ATTRIBUTE,
527 AXIS_CHILD,
528 AXIS_DESCENDANT,
529 AXIS_DESCENDANT_OR_SELF,
530 AXIS_FOLLOWING,
531 AXIS_FOLLOWING_SIBLING,
532 AXIS_NAMESPACE,
533 AXIS_PARENT,
534 AXIS_PRECEDING,
535 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000536 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000537} xmlXPathAxisVal;
538
539typedef enum {
540 NODE_TEST_NONE = 0,
541 NODE_TEST_TYPE = 1,
542 NODE_TEST_PI = 2,
543 NODE_TEST_ALL = 3,
544 NODE_TEST_NS = 4,
545 NODE_TEST_NAME = 5
546} xmlXPathTestVal;
547
548typedef enum {
549 NODE_TYPE_NODE = 0,
550 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000552 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553} xmlXPathTypeVal;
554
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000555#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000556
557typedef struct _xmlXPathStepOp xmlXPathStepOp;
558typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000560 xmlXPathOp op; /* The identifier of the operation */
561 int ch1; /* First child */
562 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000563 int value;
564 int value2;
565 int value3;
566 void *value4;
567 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000568 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000569 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000570 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000571};
572
573struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000574 int nbStep; /* Number of steps in this expression */
575 int maxStep; /* Maximum number of steps allocated */
576 xmlXPathStepOp *steps; /* ops for computation of this expression */
577 int last; /* index of last step in expression */
578 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000579 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000580#ifdef DEBUG_EVAL_COUNTS
581 int nb;
582 xmlChar *string;
583#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000584#ifdef XPATH_STREAMING
585 xmlPatternPtr stream;
586#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000587};
588
589/************************************************************************
590 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000591 * Forward declarations *
592 * *
593 ************************************************************************/
594static void
595xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596static void
597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598static int
599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600 xmlXPathStepOpPtr op, xmlNodePtr *first);
601static int
602xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000603 xmlXPathStepOpPtr op,
604 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000605
606/************************************************************************
607 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000608 * Parser Type functions *
609 * *
610 ************************************************************************/
611
612/**
613 * xmlXPathNewCompExpr:
614 *
615 * Create a new Xpath component
616 *
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000619static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000620xmlXPathNewCompExpr(void) {
621 xmlXPathCompExprPtr cur;
622
623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000625 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626 return(NULL);
627 }
628 memset(cur, 0, sizeof(xmlXPathCompExpr));
629 cur->maxStep = 10;
630 cur->nbStep = 0;
631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632 sizeof(xmlXPathStepOp));
633 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000634 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000635 xmlFree(cur);
636 return(NULL);
637 }
638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000640#ifdef DEBUG_EVAL_COUNTS
641 cur->nb = 0;
642#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000643 return(cur);
644}
645
646/**
647 * xmlXPathFreeCompExpr:
648 * @comp: an XPATH comp
649 *
650 * Free up the memory allocated by @comp
651 */
652void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000653xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000655 xmlXPathStepOpPtr op;
656 int i;
657
658 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000659 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000660 if (comp->dict == NULL) {
661 for (i = 0; i < comp->nbStep; i++) {
662 op = &comp->steps[i];
663 if (op->value4 != NULL) {
664 if (op->op == XPATH_OP_VALUE)
665 xmlXPathFreeObject(op->value4);
666 else
667 xmlFree(op->value4);
668 }
669 if (op->value5 != NULL)
670 xmlFree(op->value5);
671 }
672 } else {
673 for (i = 0; i < comp->nbStep; i++) {
674 op = &comp->steps[i];
675 if (op->value4 != NULL) {
676 if (op->op == XPATH_OP_VALUE)
677 xmlXPathFreeObject(op->value4);
678 }
679 }
680 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000681 }
682 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000683 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000685#ifdef DEBUG_EVAL_COUNTS
686 if (comp->string != NULL) {
687 xmlFree(comp->string);
688 }
689#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000690#ifdef XPATH_STREAMING
691 if (comp->stream != NULL) {
692 xmlFreePatternList(comp->stream);
693 }
694#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000695 if (comp->expr != NULL) {
696 xmlFree(comp->expr);
697 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000698
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000699 xmlFree(comp);
700}
701
702/**
703 * xmlXPathCompExprAdd:
704 * @comp: the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
707 * @op: an op
708 * @value: the first int value
709 * @value2: the second int value
710 * @value3: the third int value
711 * @value4: the first string value
712 * @value5: the second string value
713 *
William M. Brack08171912003-12-29 02:52:11 +0000714 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000715 *
716 * Returns -1 in case of failure, the index otherwise
717 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000718static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000719xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720 xmlXPathOp op, int value,
721 int value2, int value3, void *value4, void *value5) {
722 if (comp->nbStep >= comp->maxStep) {
723 xmlXPathStepOp *real;
724
725 comp->maxStep *= 2;
726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727 comp->maxStep * sizeof(xmlXPathStepOp));
728 if (real == NULL) {
729 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000730 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000731 return(-1);
732 }
733 comp->steps = real;
734 }
735 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000736 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000737 comp->steps[comp->nbStep].ch1 = ch1;
738 comp->steps[comp->nbStep].ch2 = ch2;
739 comp->steps[comp->nbStep].op = op;
740 comp->steps[comp->nbStep].value = value;
741 comp->steps[comp->nbStep].value2 = value2;
742 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000743 if ((comp->dict != NULL) &&
744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745 (op == XPATH_OP_COLLECT))) {
746 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000747 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000748 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000749 xmlFree(value4);
750 } else
751 comp->steps[comp->nbStep].value4 = NULL;
752 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000753 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000754 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000755 xmlFree(value5);
756 } else
757 comp->steps[comp->nbStep].value5 = NULL;
758 } else {
759 comp->steps[comp->nbStep].value4 = value4;
760 comp->steps[comp->nbStep].value5 = value5;
761 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000762 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000763 return(comp->nbStep++);
764}
765
Daniel Veillardf06307e2001-07-03 10:35:50 +0000766/**
767 * xmlXPathCompSwap:
768 * @comp: the compiled expression
769 * @op: operation index
770 *
771 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000772 */
773static void
774xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775 int tmp;
776
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000777#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000778 /*
779 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000780 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000781 * application
782 */
783 if (xmlXPathDisableOptimizer)
784 return;
785#endif
786
Daniel Veillardf06307e2001-07-03 10:35:50 +0000787 tmp = op->ch1;
788 op->ch1 = op->ch2;
789 op->ch2 = tmp;
790}
791
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000792#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
794 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000795#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
797 (op), (val), (val2), (val3), (val4), (val5))
798
799#define PUSH_LEAVE_EXPR(op, val, val2) \
800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802#define PUSH_UNARY_EXPR(op, ch, val, val2) \
803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000806xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
807 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000808
809/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000810 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000811 * XPath object cache structures *
812 * *
813 ************************************************************************/
814
815/* #define XP_DEFAULT_CACHE_ON */
816
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000817#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000818
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000819typedef struct _xmlXPathContextCache xmlXPathContextCache;
820typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000827 int maxNodeset;
828 int maxString;
829 int maxBoolean;
830 int maxNumber;
831 int maxMisc;
832#ifdef XP_DEBUG_OBJ_USAGE
833 int dbgCachedAll;
834 int dbgCachedNodeset;
835 int dbgCachedString;
836 int dbgCachedBool;
837 int dbgCachedNumber;
838 int dbgCachedPoint;
839 int dbgCachedRange;
840 int dbgCachedLocset;
841 int dbgCachedUsers;
842 int dbgCachedXSLTTree;
843 int dbgCachedUndefined;
844
845
846 int dbgReusedAll;
847 int dbgReusedNodeset;
848 int dbgReusedString;
849 int dbgReusedBool;
850 int dbgReusedNumber;
851 int dbgReusedPoint;
852 int dbgReusedRange;
853 int dbgReusedLocset;
854 int dbgReusedUsers;
855 int dbgReusedXSLTTree;
856 int dbgReusedUndefined;
857
858#endif
859};
860
861/************************************************************************
862 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000863 * Debugging related functions *
864 * *
865 ************************************************************************/
866
Owen Taylor3473f882001-02-23 17:55:21 +0000867#define STRANGE \
868 xmlGenericError(xmlGenericErrorContext, \
869 "Internal error at %s:%d\n", \
870 __FILE__, __LINE__);
871
872#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000873static void
874xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000875 int i;
876 char shift[100];
877
878 for (i = 0;((i < depth) && (i < 25));i++)
879 shift[2 * i] = shift[2 * i + 1] = ' ';
880 shift[2 * i] = shift[2 * i + 1] = 0;
881 if (cur == NULL) {
882 fprintf(output, shift);
883 fprintf(output, "Node is NULL !\n");
884 return;
885
886 }
887
888 if ((cur->type == XML_DOCUMENT_NODE) ||
889 (cur->type == XML_HTML_DOCUMENT_NODE)) {
890 fprintf(output, shift);
891 fprintf(output, " /\n");
892 } else if (cur->type == XML_ATTRIBUTE_NODE)
893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894 else
895 xmlDebugDumpOneNode(output, cur, depth);
896}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000897static void
898xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000899 xmlNodePtr tmp;
900 int i;
901 char shift[100];
902
903 for (i = 0;((i < depth) && (i < 25));i++)
904 shift[2 * i] = shift[2 * i + 1] = ' ';
905 shift[2 * i] = shift[2 * i + 1] = 0;
906 if (cur == NULL) {
907 fprintf(output, shift);
908 fprintf(output, "Node is NULL !\n");
909 return;
910
911 }
912
913 while (cur != NULL) {
914 tmp = cur;
915 cur = cur->next;
916 xmlDebugDumpOneNode(output, tmp, depth);
917 }
918}
Owen Taylor3473f882001-02-23 17:55:21 +0000919
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000920static void
921xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000922 int i;
923 char shift[100];
924
925 for (i = 0;((i < depth) && (i < 25));i++)
926 shift[2 * i] = shift[2 * i + 1] = ' ';
927 shift[2 * i] = shift[2 * i + 1] = 0;
928
929 if (cur == NULL) {
930 fprintf(output, shift);
931 fprintf(output, "NodeSet is NULL !\n");
932 return;
933
934 }
935
Daniel Veillard911f49a2001-04-07 15:39:35 +0000936 if (cur != NULL) {
937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938 for (i = 0;i < cur->nodeNr;i++) {
939 fprintf(output, shift);
940 fprintf(output, "%d", i + 1);
941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942 }
Owen Taylor3473f882001-02-23 17:55:21 +0000943 }
944}
945
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000946static void
947xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000948 int i;
949 char shift[100];
950
951 for (i = 0;((i < depth) && (i < 25));i++)
952 shift[2 * i] = shift[2 * i + 1] = ' ';
953 shift[2 * i] = shift[2 * i + 1] = 0;
954
955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956 fprintf(output, shift);
957 fprintf(output, "Value Tree is NULL !\n");
958 return;
959
960 }
961
962 fprintf(output, shift);
963 fprintf(output, "%d", i + 1);
964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965}
Owen Taylor3473f882001-02-23 17:55:21 +0000966#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000967static void
968xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000969 int i;
970 char shift[100];
971
972 for (i = 0;((i < depth) && (i < 25));i++)
973 shift[2 * i] = shift[2 * i + 1] = ' ';
974 shift[2 * i] = shift[2 * i + 1] = 0;
975
976 if (cur == NULL) {
977 fprintf(output, shift);
978 fprintf(output, "LocationSet is NULL !\n");
979 return;
980
981 }
982
983 for (i = 0;i < cur->locNr;i++) {
984 fprintf(output, shift);
985 fprintf(output, "%d : ", i + 1);
986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987 }
988}
Daniel Veillard017b1082001-06-21 11:20:21 +0000989#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000990
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000991/**
992 * xmlXPathDebugDumpObject:
993 * @output: the FILE * to dump the output
994 * @cur: the object to inspect
995 * @depth: indentation level
996 *
997 * Dump the content of the object for debugging purposes
998 */
999void
1000xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001001 int i;
1002 char shift[100];
1003
Daniel Veillarda82b1822004-11-08 16:24:57 +00001004 if (output == NULL) return;
1005
Owen Taylor3473f882001-02-23 17:55:21 +00001006 for (i = 0;((i < depth) && (i < 25));i++)
1007 shift[2 * i] = shift[2 * i + 1] = ' ';
1008 shift[2 * i] = shift[2 * i + 1] = 0;
1009
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001010
1011 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001012
1013 if (cur == NULL) {
1014 fprintf(output, "Object is empty (NULL)\n");
1015 return;
1016 }
1017 switch(cur->type) {
1018 case XPATH_UNDEFINED:
1019 fprintf(output, "Object is uninitialized\n");
1020 break;
1021 case XPATH_NODESET:
1022 fprintf(output, "Object is a Node Set :\n");
1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024 break;
1025 case XPATH_XSLT_TREE:
1026 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001028 break;
1029 case XPATH_BOOLEAN:
1030 fprintf(output, "Object is a Boolean : ");
1031 if (cur->boolval) fprintf(output, "true\n");
1032 else fprintf(output, "false\n");
1033 break;
1034 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001035 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001036 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001037 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001038 break;
1039 case -1:
1040 fprintf(output, "Object is a number : -Infinity\n");
1041 break;
1042 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001043 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001044 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001047 } else {
1048 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049 }
1050 }
Owen Taylor3473f882001-02-23 17:55:21 +00001051 break;
1052 case XPATH_STRING:
1053 fprintf(output, "Object is a string : ");
1054 xmlDebugDumpString(output, cur->stringval);
1055 fprintf(output, "\n");
1056 break;
1057 case XPATH_POINT:
1058 fprintf(output, "Object is a point : index %d in node", cur->index);
1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060 fprintf(output, "\n");
1061 break;
1062 case XPATH_RANGE:
1063 if ((cur->user2 == NULL) ||
1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065 fprintf(output, "Object is a collapsed range :\n");
1066 fprintf(output, shift);
1067 if (cur->index >= 0)
1068 fprintf(output, "index %d in ", cur->index);
1069 fprintf(output, "node\n");
1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071 depth + 1);
1072 } else {
1073 fprintf(output, "Object is a range :\n");
1074 fprintf(output, shift);
1075 fprintf(output, "From ");
1076 if (cur->index >= 0)
1077 fprintf(output, "index %d in ", cur->index);
1078 fprintf(output, "node\n");
1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080 depth + 1);
1081 fprintf(output, shift);
1082 fprintf(output, "To ");
1083 if (cur->index2 >= 0)
1084 fprintf(output, "index %d in ", cur->index2);
1085 fprintf(output, "node\n");
1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087 depth + 1);
1088 fprintf(output, "\n");
1089 }
1090 break;
1091 case XPATH_LOCATIONSET:
1092#if defined(LIBXML_XPTR_ENABLED)
1093 fprintf(output, "Object is a Location Set:\n");
1094 xmlXPathDebugDumpLocationSet(output,
1095 (xmlLocationSetPtr) cur->user, depth);
1096#endif
1097 break;
1098 case XPATH_USERS:
1099 fprintf(output, "Object is user defined\n");
1100 break;
1101 }
1102}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001103
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001104static void
1105xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001106 xmlXPathStepOpPtr op, int depth) {
1107 int i;
1108 char shift[100];
1109
1110 for (i = 0;((i < depth) && (i < 25));i++)
1111 shift[2 * i] = shift[2 * i + 1] = ' ';
1112 shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114 fprintf(output, shift);
1115 if (op == NULL) {
1116 fprintf(output, "Step is NULL\n");
1117 return;
1118 }
1119 switch (op->op) {
1120 case XPATH_OP_END:
1121 fprintf(output, "END"); break;
1122 case XPATH_OP_AND:
1123 fprintf(output, "AND"); break;
1124 case XPATH_OP_OR:
1125 fprintf(output, "OR"); break;
1126 case XPATH_OP_EQUAL:
1127 if (op->value)
1128 fprintf(output, "EQUAL =");
1129 else
1130 fprintf(output, "EQUAL !=");
1131 break;
1132 case XPATH_OP_CMP:
1133 if (op->value)
1134 fprintf(output, "CMP <");
1135 else
1136 fprintf(output, "CMP >");
1137 if (!op->value2)
1138 fprintf(output, "=");
1139 break;
1140 case XPATH_OP_PLUS:
1141 if (op->value == 0)
1142 fprintf(output, "PLUS -");
1143 else if (op->value == 1)
1144 fprintf(output, "PLUS +");
1145 else if (op->value == 2)
1146 fprintf(output, "PLUS unary -");
1147 else if (op->value == 3)
1148 fprintf(output, "PLUS unary - -");
1149 break;
1150 case XPATH_OP_MULT:
1151 if (op->value == 0)
1152 fprintf(output, "MULT *");
1153 else if (op->value == 1)
1154 fprintf(output, "MULT div");
1155 else
1156 fprintf(output, "MULT mod");
1157 break;
1158 case XPATH_OP_UNION:
1159 fprintf(output, "UNION"); break;
1160 case XPATH_OP_ROOT:
1161 fprintf(output, "ROOT"); break;
1162 case XPATH_OP_NODE:
1163 fprintf(output, "NODE"); break;
1164 case XPATH_OP_RESET:
1165 fprintf(output, "RESET"); break;
1166 case XPATH_OP_SORT:
1167 fprintf(output, "SORT"); break;
1168 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001172 const xmlChar *prefix = op->value4;
1173 const xmlChar *name = op->value5;
1174
1175 fprintf(output, "COLLECT ");
1176 switch (axis) {
1177 case AXIS_ANCESTOR:
1178 fprintf(output, " 'ancestors' "); break;
1179 case AXIS_ANCESTOR_OR_SELF:
1180 fprintf(output, " 'ancestors-or-self' "); break;
1181 case AXIS_ATTRIBUTE:
1182 fprintf(output, " 'attributes' "); break;
1183 case AXIS_CHILD:
1184 fprintf(output, " 'child' "); break;
1185 case AXIS_DESCENDANT:
1186 fprintf(output, " 'descendant' "); break;
1187 case AXIS_DESCENDANT_OR_SELF:
1188 fprintf(output, " 'descendant-or-self' "); break;
1189 case AXIS_FOLLOWING:
1190 fprintf(output, " 'following' "); break;
1191 case AXIS_FOLLOWING_SIBLING:
1192 fprintf(output, " 'following-siblings' "); break;
1193 case AXIS_NAMESPACE:
1194 fprintf(output, " 'namespace' "); break;
1195 case AXIS_PARENT:
1196 fprintf(output, " 'parent' "); break;
1197 case AXIS_PRECEDING:
1198 fprintf(output, " 'preceding' "); break;
1199 case AXIS_PRECEDING_SIBLING:
1200 fprintf(output, " 'preceding-sibling' "); break;
1201 case AXIS_SELF:
1202 fprintf(output, " 'self' "); break;
1203 }
1204 switch (test) {
1205 case NODE_TEST_NONE:
1206 fprintf(output, "'none' "); break;
1207 case NODE_TEST_TYPE:
1208 fprintf(output, "'type' "); break;
1209 case NODE_TEST_PI:
1210 fprintf(output, "'PI' "); break;
1211 case NODE_TEST_ALL:
1212 fprintf(output, "'all' "); break;
1213 case NODE_TEST_NS:
1214 fprintf(output, "'namespace' "); break;
1215 case NODE_TEST_NAME:
1216 fprintf(output, "'name' "); break;
1217 }
1218 switch (type) {
1219 case NODE_TYPE_NODE:
1220 fprintf(output, "'node' "); break;
1221 case NODE_TYPE_COMMENT:
1222 fprintf(output, "'comment' "); break;
1223 case NODE_TYPE_TEXT:
1224 fprintf(output, "'text' "); break;
1225 case NODE_TYPE_PI:
1226 fprintf(output, "'PI' "); break;
1227 }
1228 if (prefix != NULL)
1229 fprintf(output, "%s:", prefix);
1230 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001231 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001232 break;
1233
1234 }
1235 case XPATH_OP_VALUE: {
1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238 fprintf(output, "ELEM ");
1239 xmlXPathDebugDumpObject(output, object, 0);
1240 goto finish;
1241 }
1242 case XPATH_OP_VARIABLE: {
1243 const xmlChar *prefix = op->value5;
1244 const xmlChar *name = op->value4;
1245
1246 if (prefix != NULL)
1247 fprintf(output, "VARIABLE %s:%s", prefix, name);
1248 else
1249 fprintf(output, "VARIABLE %s", name);
1250 break;
1251 }
1252 case XPATH_OP_FUNCTION: {
1253 int nbargs = op->value;
1254 const xmlChar *prefix = op->value5;
1255 const xmlChar *name = op->value4;
1256
1257 if (prefix != NULL)
1258 fprintf(output, "FUNCTION %s:%s(%d args)",
1259 prefix, name, nbargs);
1260 else
1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262 break;
1263 }
1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001267#ifdef LIBXML_XPTR_ENABLED
1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001270 default:
1271 fprintf(output, "UNKNOWN %d\n", op->op); return;
1272 }
1273 fprintf(output, "\n");
1274finish:
1275 if (op->ch1 >= 0)
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277 if (op->ch2 >= 0)
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001280
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001281/**
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output: the FILE * for the output
1284 * @comp: the precompiled XPath expression
1285 * @depth: the indentation level.
1286 *
1287 * Dumps the tree of the compiled XPath expression.
1288 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001289void
1290xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001292 int i;
1293 char shift[100];
1294
Daniel Veillarda82b1822004-11-08 16:24:57 +00001295 if ((output == NULL) || (comp == NULL)) return;
1296
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001297 for (i = 0;((i < depth) && (i < 25));i++)
1298 shift[2 * i] = shift[2 * i + 1] = ' ';
1299 shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301 fprintf(output, shift);
1302
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001303 fprintf(output, "Compiled Expression : %d elements\n",
1304 comp->nbStep);
1305 i = comp->last;
1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001308
1309#ifdef XP_DEBUG_OBJ_USAGE
1310
1311/*
1312* XPath object usage related debugging variables.
1313*/
1314static int xmlXPathDebugObjCounterUndefined = 0;
1315static int xmlXPathDebugObjCounterNodeset = 0;
1316static int xmlXPathDebugObjCounterBool = 0;
1317static int xmlXPathDebugObjCounterNumber = 0;
1318static int xmlXPathDebugObjCounterString = 0;
1319static int xmlXPathDebugObjCounterPoint = 0;
1320static int xmlXPathDebugObjCounterRange = 0;
1321static int xmlXPathDebugObjCounterLocset = 0;
1322static int xmlXPathDebugObjCounterUsers = 0;
1323static int xmlXPathDebugObjCounterXSLTTree = 0;
1324static int xmlXPathDebugObjCounterAll = 0;
1325
1326static int xmlXPathDebugObjTotalUndefined = 0;
1327static int xmlXPathDebugObjTotalNodeset = 0;
1328static int xmlXPathDebugObjTotalBool = 0;
1329static int xmlXPathDebugObjTotalNumber = 0;
1330static int xmlXPathDebugObjTotalString = 0;
1331static int xmlXPathDebugObjTotalPoint = 0;
1332static int xmlXPathDebugObjTotalRange = 0;
1333static int xmlXPathDebugObjTotalLocset = 0;
1334static int xmlXPathDebugObjTotalUsers = 0;
1335static int xmlXPathDebugObjTotalXSLTTree = 0;
1336static int xmlXPathDebugObjTotalAll = 0;
1337
1338static int xmlXPathDebugObjMaxUndefined = 0;
1339static int xmlXPathDebugObjMaxNodeset = 0;
1340static int xmlXPathDebugObjMaxBool = 0;
1341static int xmlXPathDebugObjMaxNumber = 0;
1342static int xmlXPathDebugObjMaxString = 0;
1343static int xmlXPathDebugObjMaxPoint = 0;
1344static int xmlXPathDebugObjMaxRange = 0;
1345static int xmlXPathDebugObjMaxLocset = 0;
1346static int xmlXPathDebugObjMaxUsers = 0;
1347static int xmlXPathDebugObjMaxXSLTTree = 0;
1348static int xmlXPathDebugObjMaxAll = 0;
1349
1350/* REVISIT TODO: Make this static when committing */
1351static void
1352xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353{
1354 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001355 if (ctxt->cache != NULL) {
1356 xmlXPathContextCachePtr cache =
1357 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001358
1359 cache->dbgCachedAll = 0;
1360 cache->dbgCachedNodeset = 0;
1361 cache->dbgCachedString = 0;
1362 cache->dbgCachedBool = 0;
1363 cache->dbgCachedNumber = 0;
1364 cache->dbgCachedPoint = 0;
1365 cache->dbgCachedRange = 0;
1366 cache->dbgCachedLocset = 0;
1367 cache->dbgCachedUsers = 0;
1368 cache->dbgCachedXSLTTree = 0;
1369 cache->dbgCachedUndefined = 0;
1370
1371 cache->dbgReusedAll = 0;
1372 cache->dbgReusedNodeset = 0;
1373 cache->dbgReusedString = 0;
1374 cache->dbgReusedBool = 0;
1375 cache->dbgReusedNumber = 0;
1376 cache->dbgReusedPoint = 0;
1377 cache->dbgReusedRange = 0;
1378 cache->dbgReusedLocset = 0;
1379 cache->dbgReusedUsers = 0;
1380 cache->dbgReusedXSLTTree = 0;
1381 cache->dbgReusedUndefined = 0;
1382 }
1383 }
1384
1385 xmlXPathDebugObjCounterUndefined = 0;
1386 xmlXPathDebugObjCounterNodeset = 0;
1387 xmlXPathDebugObjCounterBool = 0;
1388 xmlXPathDebugObjCounterNumber = 0;
1389 xmlXPathDebugObjCounterString = 0;
1390 xmlXPathDebugObjCounterPoint = 0;
1391 xmlXPathDebugObjCounterRange = 0;
1392 xmlXPathDebugObjCounterLocset = 0;
1393 xmlXPathDebugObjCounterUsers = 0;
1394 xmlXPathDebugObjCounterXSLTTree = 0;
1395 xmlXPathDebugObjCounterAll = 0;
1396
1397 xmlXPathDebugObjTotalUndefined = 0;
1398 xmlXPathDebugObjTotalNodeset = 0;
1399 xmlXPathDebugObjTotalBool = 0;
1400 xmlXPathDebugObjTotalNumber = 0;
1401 xmlXPathDebugObjTotalString = 0;
1402 xmlXPathDebugObjTotalPoint = 0;
1403 xmlXPathDebugObjTotalRange = 0;
1404 xmlXPathDebugObjTotalLocset = 0;
1405 xmlXPathDebugObjTotalUsers = 0;
1406 xmlXPathDebugObjTotalXSLTTree = 0;
1407 xmlXPathDebugObjTotalAll = 0;
1408
1409 xmlXPathDebugObjMaxUndefined = 0;
1410 xmlXPathDebugObjMaxNodeset = 0;
1411 xmlXPathDebugObjMaxBool = 0;
1412 xmlXPathDebugObjMaxNumber = 0;
1413 xmlXPathDebugObjMaxString = 0;
1414 xmlXPathDebugObjMaxPoint = 0;
1415 xmlXPathDebugObjMaxRange = 0;
1416 xmlXPathDebugObjMaxLocset = 0;
1417 xmlXPathDebugObjMaxUsers = 0;
1418 xmlXPathDebugObjMaxXSLTTree = 0;
1419 xmlXPathDebugObjMaxAll = 0;
1420
1421}
1422
1423static void
1424xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425 xmlXPathObjectType objType)
1426{
1427 int isCached = 0;
1428
1429 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001430 if (ctxt->cache != NULL) {
1431 xmlXPathContextCachePtr cache =
1432 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001433
1434 isCached = 1;
1435
1436 cache->dbgReusedAll++;
1437 switch (objType) {
1438 case XPATH_UNDEFINED:
1439 cache->dbgReusedUndefined++;
1440 break;
1441 case XPATH_NODESET:
1442 cache->dbgReusedNodeset++;
1443 break;
1444 case XPATH_BOOLEAN:
1445 cache->dbgReusedBool++;
1446 break;
1447 case XPATH_NUMBER:
1448 cache->dbgReusedNumber++;
1449 break;
1450 case XPATH_STRING:
1451 cache->dbgReusedString++;
1452 break;
1453 case XPATH_POINT:
1454 cache->dbgReusedPoint++;
1455 break;
1456 case XPATH_RANGE:
1457 cache->dbgReusedRange++;
1458 break;
1459 case XPATH_LOCATIONSET:
1460 cache->dbgReusedLocset++;
1461 break;
1462 case XPATH_USERS:
1463 cache->dbgReusedUsers++;
1464 break;
1465 case XPATH_XSLT_TREE:
1466 cache->dbgReusedXSLTTree++;
1467 break;
1468 default:
1469 break;
1470 }
1471 }
1472 }
1473
1474 switch (objType) {
1475 case XPATH_UNDEFINED:
1476 if (! isCached)
1477 xmlXPathDebugObjTotalUndefined++;
1478 xmlXPathDebugObjCounterUndefined++;
1479 if (xmlXPathDebugObjCounterUndefined >
1480 xmlXPathDebugObjMaxUndefined)
1481 xmlXPathDebugObjMaxUndefined =
1482 xmlXPathDebugObjCounterUndefined;
1483 break;
1484 case XPATH_NODESET:
1485 if (! isCached)
1486 xmlXPathDebugObjTotalNodeset++;
1487 xmlXPathDebugObjCounterNodeset++;
1488 if (xmlXPathDebugObjCounterNodeset >
1489 xmlXPathDebugObjMaxNodeset)
1490 xmlXPathDebugObjMaxNodeset =
1491 xmlXPathDebugObjCounterNodeset;
1492 break;
1493 case XPATH_BOOLEAN:
1494 if (! isCached)
1495 xmlXPathDebugObjTotalBool++;
1496 xmlXPathDebugObjCounterBool++;
1497 if (xmlXPathDebugObjCounterBool >
1498 xmlXPathDebugObjMaxBool)
1499 xmlXPathDebugObjMaxBool =
1500 xmlXPathDebugObjCounterBool;
1501 break;
1502 case XPATH_NUMBER:
1503 if (! isCached)
1504 xmlXPathDebugObjTotalNumber++;
1505 xmlXPathDebugObjCounterNumber++;
1506 if (xmlXPathDebugObjCounterNumber >
1507 xmlXPathDebugObjMaxNumber)
1508 xmlXPathDebugObjMaxNumber =
1509 xmlXPathDebugObjCounterNumber;
1510 break;
1511 case XPATH_STRING:
1512 if (! isCached)
1513 xmlXPathDebugObjTotalString++;
1514 xmlXPathDebugObjCounterString++;
1515 if (xmlXPathDebugObjCounterString >
1516 xmlXPathDebugObjMaxString)
1517 xmlXPathDebugObjMaxString =
1518 xmlXPathDebugObjCounterString;
1519 break;
1520 case XPATH_POINT:
1521 if (! isCached)
1522 xmlXPathDebugObjTotalPoint++;
1523 xmlXPathDebugObjCounterPoint++;
1524 if (xmlXPathDebugObjCounterPoint >
1525 xmlXPathDebugObjMaxPoint)
1526 xmlXPathDebugObjMaxPoint =
1527 xmlXPathDebugObjCounterPoint;
1528 break;
1529 case XPATH_RANGE:
1530 if (! isCached)
1531 xmlXPathDebugObjTotalRange++;
1532 xmlXPathDebugObjCounterRange++;
1533 if (xmlXPathDebugObjCounterRange >
1534 xmlXPathDebugObjMaxRange)
1535 xmlXPathDebugObjMaxRange =
1536 xmlXPathDebugObjCounterRange;
1537 break;
1538 case XPATH_LOCATIONSET:
1539 if (! isCached)
1540 xmlXPathDebugObjTotalLocset++;
1541 xmlXPathDebugObjCounterLocset++;
1542 if (xmlXPathDebugObjCounterLocset >
1543 xmlXPathDebugObjMaxLocset)
1544 xmlXPathDebugObjMaxLocset =
1545 xmlXPathDebugObjCounterLocset;
1546 break;
1547 case XPATH_USERS:
1548 if (! isCached)
1549 xmlXPathDebugObjTotalUsers++;
1550 xmlXPathDebugObjCounterUsers++;
1551 if (xmlXPathDebugObjCounterUsers >
1552 xmlXPathDebugObjMaxUsers)
1553 xmlXPathDebugObjMaxUsers =
1554 xmlXPathDebugObjCounterUsers;
1555 break;
1556 case XPATH_XSLT_TREE:
1557 if (! isCached)
1558 xmlXPathDebugObjTotalXSLTTree++;
1559 xmlXPathDebugObjCounterXSLTTree++;
1560 if (xmlXPathDebugObjCounterXSLTTree >
1561 xmlXPathDebugObjMaxXSLTTree)
1562 xmlXPathDebugObjMaxXSLTTree =
1563 xmlXPathDebugObjCounterXSLTTree;
1564 break;
1565 default:
1566 break;
1567 }
1568 if (! isCached)
1569 xmlXPathDebugObjTotalAll++;
1570 xmlXPathDebugObjCounterAll++;
1571 if (xmlXPathDebugObjCounterAll >
1572 xmlXPathDebugObjMaxAll)
1573 xmlXPathDebugObjMaxAll =
1574 xmlXPathDebugObjCounterAll;
1575}
1576
1577static void
1578xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579 xmlXPathObjectType objType)
1580{
1581 int isCached = 0;
1582
1583 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001584 if (ctxt->cache != NULL) {
1585 xmlXPathContextCachePtr cache =
1586 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001587
1588 isCached = 1;
1589
1590 cache->dbgCachedAll++;
1591 switch (objType) {
1592 case XPATH_UNDEFINED:
1593 cache->dbgCachedUndefined++;
1594 break;
1595 case XPATH_NODESET:
1596 cache->dbgCachedNodeset++;
1597 break;
1598 case XPATH_BOOLEAN:
1599 cache->dbgCachedBool++;
1600 break;
1601 case XPATH_NUMBER:
1602 cache->dbgCachedNumber++;
1603 break;
1604 case XPATH_STRING:
1605 cache->dbgCachedString++;
1606 break;
1607 case XPATH_POINT:
1608 cache->dbgCachedPoint++;
1609 break;
1610 case XPATH_RANGE:
1611 cache->dbgCachedRange++;
1612 break;
1613 case XPATH_LOCATIONSET:
1614 cache->dbgCachedLocset++;
1615 break;
1616 case XPATH_USERS:
1617 cache->dbgCachedUsers++;
1618 break;
1619 case XPATH_XSLT_TREE:
1620 cache->dbgCachedXSLTTree++;
1621 break;
1622 default:
1623 break;
1624 }
1625
1626 }
1627 }
1628 switch (objType) {
1629 case XPATH_UNDEFINED:
1630 xmlXPathDebugObjCounterUndefined--;
1631 break;
1632 case XPATH_NODESET:
1633 xmlXPathDebugObjCounterNodeset--;
1634 break;
1635 case XPATH_BOOLEAN:
1636 xmlXPathDebugObjCounterBool--;
1637 break;
1638 case XPATH_NUMBER:
1639 xmlXPathDebugObjCounterNumber--;
1640 break;
1641 case XPATH_STRING:
1642 xmlXPathDebugObjCounterString--;
1643 break;
1644 case XPATH_POINT:
1645 xmlXPathDebugObjCounterPoint--;
1646 break;
1647 case XPATH_RANGE:
1648 xmlXPathDebugObjCounterRange--;
1649 break;
1650 case XPATH_LOCATIONSET:
1651 xmlXPathDebugObjCounterLocset--;
1652 break;
1653 case XPATH_USERS:
1654 xmlXPathDebugObjCounterUsers--;
1655 break;
1656 case XPATH_XSLT_TREE:
1657 xmlXPathDebugObjCounterXSLTTree--;
1658 break;
1659 default:
1660 break;
1661 }
1662 xmlXPathDebugObjCounterAll--;
1663}
1664
1665/* REVISIT TODO: Make this static when committing */
1666static void
1667xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668{
1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670 reqXSLTTree, reqUndefined;
1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675 int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677 reqAll = xmlXPathDebugObjTotalAll;
1678 reqNodeset = xmlXPathDebugObjTotalNodeset;
1679 reqString = xmlXPathDebugObjTotalString;
1680 reqBool = xmlXPathDebugObjTotalBool;
1681 reqNumber = xmlXPathDebugObjTotalNumber;
1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683 reqUndefined = xmlXPathDebugObjTotalUndefined;
1684
1685 printf("# XPath object usage:\n");
1686
1687 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001688 if (ctxt->cache != NULL) {
1689 xmlXPathContextCachePtr cache =
1690 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001691
1692 reAll = cache->dbgReusedAll;
1693 reqAll += reAll;
1694 reNodeset = cache->dbgReusedNodeset;
1695 reqNodeset += reNodeset;
1696 reString = cache->dbgReusedString;
1697 reqString += reString;
1698 reBool = cache->dbgReusedBool;
1699 reqBool += reBool;
1700 reNumber = cache->dbgReusedNumber;
1701 reqNumber += reNumber;
1702 reXSLTTree = cache->dbgReusedXSLTTree;
1703 reqXSLTTree += reXSLTTree;
1704 reUndefined = cache->dbgReusedUndefined;
1705 reqUndefined += reUndefined;
1706
1707 caAll = cache->dbgCachedAll;
1708 caBool = cache->dbgCachedBool;
1709 caNodeset = cache->dbgCachedNodeset;
1710 caString = cache->dbgCachedString;
1711 caNumber = cache->dbgCachedNumber;
1712 caXSLTTree = cache->dbgCachedXSLTTree;
1713 caUndefined = cache->dbgCachedUndefined;
1714
1715 if (cache->nodesetObjs)
1716 leftObjs -= cache->nodesetObjs->number;
1717 if (cache->stringObjs)
1718 leftObjs -= cache->stringObjs->number;
1719 if (cache->booleanObjs)
1720 leftObjs -= cache->booleanObjs->number;
1721 if (cache->numberObjs)
1722 leftObjs -= cache->numberObjs->number;
1723 if (cache->miscObjs)
1724 leftObjs -= cache->miscObjs->number;
1725 }
1726 }
1727
1728 printf("# all\n");
1729 printf("# total : %d\n", reqAll);
1730 printf("# left : %d\n", leftObjs);
1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1732 printf("# reused : %d\n", reAll);
1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1734
1735 printf("# node-sets\n");
1736 printf("# total : %d\n", reqNodeset);
1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1738 printf("# reused : %d\n", reNodeset);
1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741 printf("# strings\n");
1742 printf("# total : %d\n", reqString);
1743 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1744 printf("# reused : %d\n", reString);
1745 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1746
1747 printf("# booleans\n");
1748 printf("# total : %d\n", reqBool);
1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1750 printf("# reused : %d\n", reBool);
1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1752
1753 printf("# numbers\n");
1754 printf("# total : %d\n", reqNumber);
1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1756 printf("# reused : %d\n", reNumber);
1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759 printf("# XSLT result tree fragments\n");
1760 printf("# total : %d\n", reqXSLTTree);
1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762 printf("# reused : %d\n", reXSLTTree);
1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765 printf("# undefined\n");
1766 printf("# total : %d\n", reqUndefined);
1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1768 printf("# reused : %d\n", reUndefined);
1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771}
1772
1773#endif /* XP_DEBUG_OBJ_USAGE */
1774
Daniel Veillard017b1082001-06-21 11:20:21 +00001775#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001776
1777/************************************************************************
1778 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001779 * XPath object caching *
1780 * *
1781 ************************************************************************/
1782
1783/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001784 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001785 *
1786 * Create a new object cache
1787 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001788 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001789 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001790static xmlXPathContextCachePtr
1791xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001796 if (ret == NULL) {
1797 xmlXPathErrMemory(NULL, "creating object cache\n");
1798 return(NULL);
1799 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001801 ret->maxNodeset = 100;
1802 ret->maxString = 100;
1803 ret->maxBoolean = 100;
1804 ret->maxNumber = 100;
1805 ret->maxMisc = 100;
1806 return(ret);
1807}
1808
1809static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001810xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001811{
1812 int i;
1813 xmlXPathObjectPtr obj;
1814
1815 if (list == NULL)
1816 return;
1817
1818 for (i = 0; i < list->number; i++) {
1819 obj = list->items[i];
1820 /*
1821 * Note that it is already assured that we don't need to
1822 * look out for namespace nodes in the node-set.
1823 */
1824 if (obj->nodesetval != NULL) {
1825 if (obj->nodesetval->nodeTab != NULL)
1826 xmlFree(obj->nodesetval->nodeTab);
1827 xmlFree(obj->nodesetval);
1828 }
1829 xmlFree(obj);
1830#ifdef XP_DEBUG_OBJ_USAGE
1831 xmlXPathDebugObjCounterAll--;
1832#endif
1833 }
1834 xmlPointerListFree(list);
1835}
1836
1837static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001838xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001839{
1840 if (cache == NULL)
1841 return;
1842 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001843 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001844 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001851 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001852 xmlFree(cache);
1853}
1854
1855/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001856 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001857 *
1858 * @ctxt: the XPath context
1859 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001860 * @value: a value with semantics dependant on @options
1861 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001862 *
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001865 * to be reused.
1866 * @options:
1867 * 0: This will set the XPath object caching:
1868 * @value:
1869 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001870 * to be cached per slot
1871 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001872 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001874 *
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876 */
1877int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001878xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879 int active,
1880 int value,
1881 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001882{
1883 if (ctxt == NULL)
1884 return(-1);
1885 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001886 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001887
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001888 if (ctxt->cache == NULL) {
1889 ctxt->cache = xmlXPathNewCache();
1890 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001891 return(-1);
1892 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001893 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001894 if (options == 0) {
1895 if (value < 0)
1896 value = 100;
1897 cache->maxNodeset = value;
1898 cache->maxString = value;
1899 cache->maxNumber = value;
1900 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001901 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001902 }
1903 } else if (ctxt->cache != NULL) {
1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001906 }
1907 return(0);
1908}
1909
1910/**
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val: the NodePtr value
1914 *
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 *
1918 * Returns the created or reused object.
1919 */
1920static xmlXPathObjectPtr
1921xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001923 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924 xmlXPathContextCachePtr cache =
1925 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001926
1927 if ((cache->miscObjs != NULL) &&
1928 (cache->miscObjs->number != 0))
1929 {
1930 xmlXPathObjectPtr ret;
1931
1932 ret = (xmlXPathObjectPtr)
1933 cache->miscObjs->items[--cache->miscObjs->number];
1934 ret->type = XPATH_NODESET;
1935 ret->nodesetval = val;
1936#ifdef XP_DEBUG_OBJ_USAGE
1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938#endif
1939 return(ret);
1940 }
1941 }
1942
1943 return(xmlXPathWrapNodeSet(val));
1944
1945}
1946
1947/**
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val: the xmlChar * value
1951 *
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1954 *
1955 * Returns the created or reused object.
1956 */
1957static xmlXPathObjectPtr
1958xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001960 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001962
1963 if ((cache->stringObjs != NULL) &&
1964 (cache->stringObjs->number != 0))
1965 {
1966
1967 xmlXPathObjectPtr ret;
1968
1969 ret = (xmlXPathObjectPtr)
1970 cache->stringObjs->items[--cache->stringObjs->number];
1971 ret->type = XPATH_STRING;
1972 ret->stringval = val;
1973#ifdef XP_DEBUG_OBJ_USAGE
1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975#endif
1976 return(ret);
1977 } else if ((cache->miscObjs != NULL) &&
1978 (cache->miscObjs->number != 0))
1979 {
1980 xmlXPathObjectPtr ret;
1981 /*
1982 * Fallback to misc-cache.
1983 */
1984 ret = (xmlXPathObjectPtr)
1985 cache->miscObjs->items[--cache->miscObjs->number];
1986
1987 ret->type = XPATH_STRING;
1988 ret->stringval = val;
1989#ifdef XP_DEBUG_OBJ_USAGE
1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991#endif
1992 return(ret);
1993 }
1994 }
1995 return(xmlXPathWrapString(val));
1996}
1997
1998/**
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val: the NodePtr value
2002 *
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2006 *
2007 * Returns the created or reused object.
2008 */
2009static xmlXPathObjectPtr
2010xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002012 if ((ctxt != NULL) && (ctxt->cache)) {
2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002014
2015 if ((cache->nodesetObjs != NULL) &&
2016 (cache->nodesetObjs->number != 0))
2017 {
2018 xmlXPathObjectPtr ret;
2019 /*
2020 * Use the nodset-cache.
2021 */
2022 ret = (xmlXPathObjectPtr)
2023 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024 ret->type = XPATH_NODESET;
2025 ret->boolval = 0;
2026 if (val) {
2027 if ((ret->nodesetval->nodeMax == 0) ||
2028 (val->type == XML_NAMESPACE_DECL))
2029 {
2030 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031 } else {
2032 ret->nodesetval->nodeTab[0] = val;
2033 ret->nodesetval->nodeNr = 1;
2034 }
2035 }
2036#ifdef XP_DEBUG_OBJ_USAGE
2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038#endif
2039 return(ret);
2040 } else if ((cache->miscObjs != NULL) &&
2041 (cache->miscObjs->number != 0))
2042 {
2043 xmlXPathObjectPtr ret;
2044 /*
2045 * Fallback to misc-cache.
2046 */
2047
2048 ret = (xmlXPathObjectPtr)
2049 cache->miscObjs->items[--cache->miscObjs->number];
2050
2051 ret->type = XPATH_NODESET;
2052 ret->boolval = 0;
2053 ret->nodesetval = xmlXPathNodeSetCreate(val);
2054#ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056#endif
2057 return(ret);
2058 }
2059 }
2060 return(xmlXPathNewNodeSet(val));
2061}
2062
2063/**
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val: the char * value
2067 *
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 *
2071 * Returns the created or reused object.
2072 */
2073static xmlXPathObjectPtr
2074xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002076 if ((ctxt != NULL) && (ctxt->cache)) {
2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002078
2079 if ((cache->stringObjs != NULL) &&
2080 (cache->stringObjs->number != 0))
2081 {
2082 xmlXPathObjectPtr ret;
2083
2084 ret = (xmlXPathObjectPtr)
2085 cache->stringObjs->items[--cache->stringObjs->number];
2086
2087 ret->type = XPATH_STRING;
2088 ret->stringval = xmlStrdup(BAD_CAST val);
2089#ifdef XP_DEBUG_OBJ_USAGE
2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091#endif
2092 return(ret);
2093 } else if ((cache->miscObjs != NULL) &&
2094 (cache->miscObjs->number != 0))
2095 {
2096 xmlXPathObjectPtr ret;
2097
2098 ret = (xmlXPathObjectPtr)
2099 cache->miscObjs->items[--cache->miscObjs->number];
2100
2101 ret->type = XPATH_STRING;
2102 ret->stringval = xmlStrdup(BAD_CAST val);
2103#ifdef XP_DEBUG_OBJ_USAGE
2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105#endif
2106 return(ret);
2107 }
2108 }
2109 return(xmlXPathNewCString(val));
2110}
2111
2112/**
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val: the xmlChar * value
2116 *
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 *
2120 * Returns the created or reused object.
2121 */
2122static xmlXPathObjectPtr
2123xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002125 if ((ctxt != NULL) && (ctxt->cache)) {
2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002127
2128 if ((cache->stringObjs != NULL) &&
2129 (cache->stringObjs->number != 0))
2130 {
2131 xmlXPathObjectPtr ret;
2132
2133 ret = (xmlXPathObjectPtr)
2134 cache->stringObjs->items[--cache->stringObjs->number];
2135 ret->type = XPATH_STRING;
2136 if (val != NULL)
2137 ret->stringval = xmlStrdup(val);
2138 else
2139 ret->stringval = xmlStrdup((const xmlChar *)"");
2140#ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142#endif
2143 return(ret);
2144 } else if ((cache->miscObjs != NULL) &&
2145 (cache->miscObjs->number != 0))
2146 {
2147 xmlXPathObjectPtr ret;
2148
2149 ret = (xmlXPathObjectPtr)
2150 cache->miscObjs->items[--cache->miscObjs->number];
2151
2152 ret->type = XPATH_STRING;
2153 if (val != NULL)
2154 ret->stringval = xmlStrdup(val);
2155 else
2156 ret->stringval = xmlStrdup((const xmlChar *)"");
2157#ifdef XP_DEBUG_OBJ_USAGE
2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159#endif
2160 return(ret);
2161 }
2162 }
2163 return(xmlXPathNewString(val));
2164}
2165
2166/**
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val: the boolean value
2170 *
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 *
2174 * Returns the created or reused object.
2175 */
2176static xmlXPathObjectPtr
2177xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002179 if ((ctxt != NULL) && (ctxt->cache)) {
2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002181
2182 if ((cache->booleanObjs != NULL) &&
2183 (cache->booleanObjs->number != 0))
2184 {
2185 xmlXPathObjectPtr ret;
2186
2187 ret = (xmlXPathObjectPtr)
2188 cache->booleanObjs->items[--cache->booleanObjs->number];
2189 ret->type = XPATH_BOOLEAN;
2190 ret->boolval = (val != 0);
2191#ifdef XP_DEBUG_OBJ_USAGE
2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193#endif
2194 return(ret);
2195 } else if ((cache->miscObjs != NULL) &&
2196 (cache->miscObjs->number != 0))
2197 {
2198 xmlXPathObjectPtr ret;
2199
2200 ret = (xmlXPathObjectPtr)
2201 cache->miscObjs->items[--cache->miscObjs->number];
2202
2203 ret->type = XPATH_BOOLEAN;
2204 ret->boolval = (val != 0);
2205#ifdef XP_DEBUG_OBJ_USAGE
2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207#endif
2208 return(ret);
2209 }
2210 }
2211 return(xmlXPathNewBoolean(val));
2212}
2213
2214/**
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val: the double value
2218 *
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 *
2222 * Returns the created or reused object.
2223 */
2224static xmlXPathObjectPtr
2225xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002227 if ((ctxt != NULL) && (ctxt->cache)) {
2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002229
2230 if ((cache->numberObjs != NULL) &&
2231 (cache->numberObjs->number != 0))
2232 {
2233 xmlXPathObjectPtr ret;
2234
2235 ret = (xmlXPathObjectPtr)
2236 cache->numberObjs->items[--cache->numberObjs->number];
2237 ret->type = XPATH_NUMBER;
2238 ret->floatval = val;
2239#ifdef XP_DEBUG_OBJ_USAGE
2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241#endif
2242 return(ret);
2243 } else if ((cache->miscObjs != NULL) &&
2244 (cache->miscObjs->number != 0))
2245 {
2246 xmlXPathObjectPtr ret;
2247
2248 ret = (xmlXPathObjectPtr)
2249 cache->miscObjs->items[--cache->miscObjs->number];
2250
2251 ret->type = XPATH_NUMBER;
2252 ret->floatval = val;
2253#ifdef XP_DEBUG_OBJ_USAGE
2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255#endif
2256 return(ret);
2257 }
2258 }
2259 return(xmlXPathNewFloat(val));
2260}
2261
2262/**
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val: an XPath object
2266 *
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2269 *
2270 * Returns a created or reused object, the old one is freed (cached)
2271 * (or the operation is done directly on @val)
2272 */
2273
2274static xmlXPathObjectPtr
2275xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276 xmlChar *res = NULL;
2277
2278 if (val == NULL)
2279 return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281 switch (val->type) {
2282 case XPATH_UNDEFINED:
2283#ifdef DEBUG_EXPR
2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285#endif
2286 break;
2287 case XPATH_NODESET:
2288 case XPATH_XSLT_TREE:
2289 res = xmlXPathCastNodeSetToString(val->nodesetval);
2290 break;
2291 case XPATH_STRING:
2292 return(val);
2293 case XPATH_BOOLEAN:
2294 res = xmlXPathCastBooleanToString(val->boolval);
2295 break;
2296 case XPATH_NUMBER:
2297 res = xmlXPathCastNumberToString(val->floatval);
2298 break;
2299 case XPATH_USERS:
2300 case XPATH_POINT:
2301 case XPATH_RANGE:
2302 case XPATH_LOCATIONSET:
2303 TODO;
2304 break;
2305 }
2306 xmlXPathReleaseObject(ctxt, val);
2307 if (res == NULL)
2308 return(xmlXPathCacheNewCString(ctxt, ""));
2309 return(xmlXPathCacheWrapString(ctxt, res));
2310}
2311
2312/**
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val: the original object
2316 *
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2319 *
2320 * Returns a created or reused created object.
2321 */
2322static xmlXPathObjectPtr
2323xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324{
2325 if (val == NULL)
2326 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002327
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002328 if (XP_HAS_CACHE(ctxt)) {
2329 switch (val->type) {
2330 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002331 return(xmlXPathCacheWrapNodeSet(ctxt,
2332 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002333 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002335 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002337 case XPATH_NUMBER:
2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339 default:
2340 break;
2341 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002342 }
2343 return(xmlXPathObjectCopy(val));
2344}
2345
2346/**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val: an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 * is done directly on @val)
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359 xmlXPathObjectPtr ret;
2360
2361 if (val == NULL)
2362 return(xmlXPathCacheNewBoolean(ctxt, 0));
2363 if (val->type == XPATH_BOOLEAN)
2364 return(val);
2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366 xmlXPathReleaseObject(ctxt, val);
2367 return(ret);
2368}
2369
2370/**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val: an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 * is done directly on @val)
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383 xmlXPathObjectPtr ret;
2384
2385 if (val == NULL)
2386 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387 if (val->type == XPATH_NUMBER)
2388 return(val);
2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390 xmlXPathReleaseObject(ctxt, val);
2391 return(ret);
2392}
2393
2394/************************************************************************
2395 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002396 * Parser stacks related functions and macros *
2397 * *
2398 ************************************************************************/
2399
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002400/**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002408xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002409valuePop(xmlXPathParserContextPtr ctxt)
2410{
2411 xmlXPathObjectPtr ret;
2412
Daniel Veillarda82b1822004-11-08 16:24:57 +00002413 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002414 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002415 ctxt->valueNr--;
2416 if (ctxt->valueNr > 0)
2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418 else
2419 ctxt->value = NULL;
2420 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002421 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002422 return (ret);
2423}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002424/**
2425 * valuePush:
2426 * @ctxt: an XPath evaluation context
2427 * @value: the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002430 *
2431 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002432 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002433int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002436 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002437 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002438 xmlXPathObjectPtr *tmp;
2439
2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002443 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445 return (0);
2446 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002447 ctxt->valueMax *= 2;
2448 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002449 }
2450 ctxt->valueTab[ctxt->valueNr] = value;
2451 ctxt->value = value;
2452 return (ctxt->valueNr++);
2453}
Owen Taylor3473f882001-02-23 17:55:21 +00002454
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002455/**
2456 * xmlXPathPopBoolean:
2457 * @ctxt: an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464int
2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466 xmlXPathObjectPtr obj;
2467 int ret;
2468
2469 obj = valuePop(ctxt);
2470 if (obj == NULL) {
2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472 return(0);
2473 }
William M. Brack08171912003-12-29 02:52:11 +00002474 if (obj->type != XPATH_BOOLEAN)
2475 ret = xmlXPathCastToBoolean(obj);
2476 else
2477 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002478 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002479 return(ret);
2480}
2481
2482/**
2483 * xmlXPathPopNumber:
2484 * @ctxt: an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491double
2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493 xmlXPathObjectPtr obj;
2494 double ret;
2495
2496 obj = valuePop(ctxt);
2497 if (obj == NULL) {
2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499 return(0);
2500 }
William M. Brack08171912003-12-29 02:52:11 +00002501 if (obj->type != XPATH_NUMBER)
2502 ret = xmlXPathCastToNumber(obj);
2503 else
2504 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002505 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002506 return(ret);
2507}
2508
2509/**
2510 * xmlXPathPopString:
2511 * @ctxt: an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518xmlChar *
2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520 xmlXPathObjectPtr obj;
2521 xmlChar * ret;
2522
2523 obj = valuePop(ctxt);
2524 if (obj == NULL) {
2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526 return(NULL);
2527 }
William M. Brack08171912003-12-29 02:52:11 +00002528 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002529 /* TODO: needs refactoring somewhere else */
2530 if (obj->stringval == ret)
2531 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002532 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002533 return(ret);
2534}
2535
2536/**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt: an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545xmlNodeSetPtr
2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547 xmlXPathObjectPtr obj;
2548 xmlNodeSetPtr ret;
2549
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002550 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002551 if (ctxt->value == NULL) {
2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553 return(NULL);
2554 }
2555 if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 xmlXPathSetTypeError(ctxt);
2557 return(NULL);
2558 }
2559 obj = valuePop(ctxt);
2560 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002561#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002562 /* to fix memory leak of not clearing obj->user */
2563 if (obj->boolval && obj->user != NULL)
2564 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002565#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002566 obj->nodesetval = NULL;
2567 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002568 return(ret);
2569}
2570
2571/**
2572 * xmlXPathPopExternal:
2573 * @ctxt: an XPath parser context
2574 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002575 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580void *
2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582 xmlXPathObjectPtr obj;
2583 void * ret;
2584
Daniel Veillarda82b1822004-11-08 16:24:57 +00002585 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587 return(NULL);
2588 }
2589 if (ctxt->value->type != XPATH_USERS) {
2590 xmlXPathSetTypeError(ctxt);
2591 return(NULL);
2592 }
2593 obj = valuePop(ctxt);
2594 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002595 obj->user = NULL;
2596 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002597 return(ret);
2598}
2599
Owen Taylor3473f882001-02-23 17:55:21 +00002600/*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 * CUR returns the current xmlChar value, i.e. a 8 bit value
2608 * in ISO-Latin or UTF-8.
2609 * This should be used internally by the parser
2610 * only to compare to ASCII values otherwise it would break when
2611 * running with UTF-8 encoding.
2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2613 * to compare on ASCII based substring.
2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 * strings within the parser.
2616 * CURRENT Returns the current char value, with the full decoding of
2617 * UTF-8 if we are using this mode. It returns an int.
2618 * NEXT Skip to the next character, this does the proper decoding
2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 * It returns the pointer to the current xmlChar.
2621 */
2622
2623#define CUR (*ctxt->cur)
2624#define SKIP(val) ctxt->cur += (val)
2625#define NXT(val) ctxt->cur[(val)]
2626#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629#define COPY_BUF(l,b,i,v) \
2630 if (l == 1) b[i++] = (xmlChar) v; \
2631 else i += xmlCopyChar(l,&b[i],v)
2632
2633#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002634
2635#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638#define CURRENT (*ctxt->cur)
2639#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2640
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002641
2642#ifndef DBL_DIG
2643#define DBL_DIG 16
2644#endif
2645#ifndef DBL_EPSILON
2646#define DBL_EPSILON 1E-9
2647#endif
2648
2649#define UPPER_DOUBLE 1E9
2650#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002651#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002652
2653#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002654#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002655#define EXPONENT_DIGITS (3 + 2)
2656
2657/**
2658 * xmlXPathFormatNumber:
2659 * @number: number to format
2660 * @buffer: output buffer
2661 * @buffersize: size of output buffer
2662 *
2663 * Convert the number into a string representation.
2664 */
2665static void
2666xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667{
Daniel Veillardcda96922001-08-21 10:56:31 +00002668 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002669 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002670 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002671 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002672 break;
2673 case -1:
2674 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002675 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002676 break;
2677 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002678 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002679 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002680 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002681 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002682 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002683 } else if (number == ((int) number)) {
2684 char work[30];
2685 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002686 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687
2688 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002689 if (value == 0) {
2690 *ptr++ = '0';
2691 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002692 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002693 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002694 while ((*cur) && (ptr - buffer < buffersize)) {
2695 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002696 }
2697 }
2698 if (ptr - buffer < buffersize) {
2699 *ptr = 0;
2700 } else if (buffersize > 0) {
2701 ptr--;
2702 *ptr = 0;
2703 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002704 } else {
William M. Brackca797882007-05-11 14:45:53 +00002705 /*
2706 For the dimension of work,
2707 DBL_DIG is number of significant digits
2708 EXPONENT is only needed for "scientific notation"
2709 3 is sign, decimal point, and terminating zero
2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711 Note that this dimension is slightly (a few characters)
2712 larger than actually necessary.
2713 */
2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002715 int integer_place, fraction_place;
2716 char *ptr;
2717 char *after_fraction;
2718 double absolute_value;
2719 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002720
Bjorn Reese70a9da52001-04-21 16:57:29 +00002721 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002722
Bjorn Reese70a9da52001-04-21 16:57:29 +00002723 /*
2724 * First choose format - scientific or regular floating point.
2725 * In either case, result is in work, and after_fraction points
2726 * just past the fractional part.
2727 */
2728 if ( ((absolute_value > UPPER_DOUBLE) ||
2729 (absolute_value < LOWER_DOUBLE)) &&
2730 (absolute_value != 0.0) ) {
2731 /* Use scientific notation */
2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002734 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002735 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002736 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002737
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002738 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002739 else {
2740 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002741 if (absolute_value > 0.0) {
2742 integer_place = (int)log10(absolute_value);
2743 if (integer_place > 0)
2744 fraction_place = DBL_DIG - integer_place - 1;
2745 else
2746 fraction_place = DBL_DIG - integer_place;
2747 } else {
2748 fraction_place = 1;
2749 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002750 size = snprintf(work, sizeof(work), "%0.*f",
2751 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002752 }
2753
Bjorn Reese70a9da52001-04-21 16:57:29 +00002754 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002755 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002756 ptr = after_fraction;
2757 while (*(--ptr) == '0')
2758 ;
2759 if (*ptr != '.')
2760 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002761 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002762
2763 /* Finally copy result back to caller */
2764 size = strlen(work) + 1;
2765 if (size > buffersize) {
2766 work[buffersize - 1] = 0;
2767 size = buffersize;
2768 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002769 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002770 }
2771 break;
2772 }
2773}
2774
Owen Taylor3473f882001-02-23 17:55:21 +00002775
2776/************************************************************************
2777 * *
2778 * Routines to handle NodeSets *
2779 * *
2780 ************************************************************************/
2781
2782/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002783 * xmlXPathOrderDocElems:
2784 * @doc: an input document
2785 *
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002791 *
William M. Brack08171912003-12-29 02:52:11 +00002792 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002793 * of error.
2794 */
2795long
2796xmlXPathOrderDocElems(xmlDocPtr doc) {
2797 long count = 0;
2798 xmlNodePtr cur;
2799
2800 if (doc == NULL)
2801 return(-1);
2802 cur = doc->children;
2803 while (cur != NULL) {
2804 if (cur->type == XML_ELEMENT_NODE) {
2805 cur->content = (void *) (-(++count));
2806 if (cur->children != NULL) {
2807 cur = cur->children;
2808 continue;
2809 }
2810 }
2811 if (cur->next != NULL) {
2812 cur = cur->next;
2813 continue;
2814 }
2815 do {
2816 cur = cur->parent;
2817 if (cur == NULL)
2818 break;
2819 if (cur == (xmlNodePtr) doc) {
2820 cur = NULL;
2821 break;
2822 }
2823 if (cur->next != NULL) {
2824 cur = cur->next;
2825 break;
2826 }
2827 } while (cur != NULL);
2828 }
2829 return(count);
2830}
2831
2832/**
Owen Taylor3473f882001-02-23 17:55:21 +00002833 * xmlXPathCmpNodes:
2834 * @node1: the first node
2835 * @node2: the second node
2836 *
2837 * Compare two nodes w.r.t document order
2838 *
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002840 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002841 */
2842int
2843xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002845 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002847 xmlNodePtr cur, root;
2848
2849 if ((node1 == NULL) || (node2 == NULL))
2850 return(-2);
2851 /*
2852 * a couple of optimizations which will avoid computations in most cases
2853 */
William M. Brackee0b9822007-03-07 08:15:01 +00002854 if (node1 == node2) /* trivial case */
2855 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002856 if (node1->type == XML_ATTRIBUTE_NODE) {
2857 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002858 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002859 node1 = node1->parent;
2860 }
2861 if (node2->type == XML_ATTRIBUTE_NODE) {
2862 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002863 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002864 node2 = node2->parent;
2865 }
2866 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002867 if (attr1 == attr2) {
2868 /* not required, but we keep attributes in order */
2869 if (attr1 != 0) {
2870 cur = attrNode2->prev;
2871 while (cur != NULL) {
2872 if (cur == attrNode1)
2873 return (1);
2874 cur = cur->prev;
2875 }
2876 return (-1);
2877 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002878 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002879 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002880 if (attr2 == 1)
2881 return(1);
2882 return(-1);
2883 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002884 if ((node1->type == XML_NAMESPACE_DECL) ||
2885 (node2->type == XML_NAMESPACE_DECL))
2886 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002887 if (node1 == node2->prev)
2888 return(1);
2889 if (node1 == node2->next)
2890 return(-1);
2891
2892 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002893 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002894 */
2895 if ((node1->type == XML_ELEMENT_NODE) &&
2896 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002897 (0 > (long) node1->content) &&
2898 (0 > (long) node2->content) &&
2899 (node1->doc == node2->doc)) {
2900 long l1, l2;
2901
2902 l1 = -((long) node1->content);
2903 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002904 if (l1 < l2)
2905 return(1);
2906 if (l1 > l2)
2907 return(-1);
2908 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002909
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002910 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002911 * compute depth to root
2912 */
2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914 if (cur == node1)
2915 return(1);
2916 depth2++;
2917 }
2918 root = cur;
2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920 if (cur == node2)
2921 return(-1);
2922 depth1++;
2923 }
2924 /*
2925 * Distinct document (or distinct entities :-( ) case.
2926 */
2927 if (root != cur) {
2928 return(-2);
2929 }
2930 /*
2931 * get the nearest common ancestor.
2932 */
2933 while (depth1 > depth2) {
2934 depth1--;
2935 node1 = node1->parent;
2936 }
2937 while (depth2 > depth1) {
2938 depth2--;
2939 node2 = node2->parent;
2940 }
2941 while (node1->parent != node2->parent) {
2942 node1 = node1->parent;
2943 node2 = node2->parent;
2944 /* should not happen but just in case ... */
2945 if ((node1 == NULL) || (node2 == NULL))
2946 return(-2);
2947 }
2948 /*
2949 * Find who's first.
2950 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002951 if (node1 == node2->prev)
2952 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 if (node1 == node2->next)
2954 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002955 /*
2956 * Speedup using document order if availble.
2957 */
2958 if ((node1->type == XML_ELEMENT_NODE) &&
2959 (node2->type == XML_ELEMENT_NODE) &&
2960 (0 > (long) node1->content) &&
2961 (0 > (long) node2->content) &&
2962 (node1->doc == node2->doc)) {
2963 long l1, l2;
2964
2965 l1 = -((long) node1->content);
2966 l2 = -((long) node2->content);
2967 if (l1 < l2)
2968 return(1);
2969 if (l1 > l2)
2970 return(-1);
2971 }
2972
Owen Taylor3473f882001-02-23 17:55:21 +00002973 for (cur = node1->next;cur != NULL;cur = cur->next)
2974 if (cur == node2)
2975 return(1);
2976 return(-1); /* assume there is no sibling list corruption */
2977}
2978
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002979#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002980/**
2981 * xmlXPathCmpNodesExt:
2982 * @node1: the first node
2983 * @node2: the second node
2984 *
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2987 *
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 * it's the same node, -1 otherwise
2990 */
2991static int
2992xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993 int depth1, depth2;
2994 int misc = 0, precedence1 = 0, precedence2 = 0;
2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002998
2999 if ((node1 == NULL) || (node2 == NULL))
3000 return(-2);
3001
3002 if (node1 == node2)
3003 return(0);
3004
3005 /*
3006 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003007 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003008 switch (node1->type) {
3009 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003010 if (node2->type == XML_ELEMENT_NODE) {
3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012 (0 > (long) node2->content) &&
3013 (node1->doc == node2->doc))
3014 {
3015 l1 = -((long) node1->content);
3016 l2 = -((long) node2->content);
3017 if (l1 < l2)
3018 return(1);
3019 if (l1 > l2)
3020 return(-1);
3021 } else
3022 goto turtle_comparison;
3023 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003024 break;
3025 case XML_ATTRIBUTE_NODE:
3026 precedence1 = 1; /* element is owner */
3027 miscNode1 = node1;
3028 node1 = node1->parent;
3029 misc = 1;
3030 break;
3031 case XML_TEXT_NODE:
3032 case XML_CDATA_SECTION_NODE:
3033 case XML_COMMENT_NODE:
3034 case XML_PI_NODE: {
3035 miscNode1 = node1;
3036 /*
3037 * Find nearest element node.
3038 */
3039 if (node1->prev != NULL) {
3040 do {
3041 node1 = node1->prev;
3042 if (node1->type == XML_ELEMENT_NODE) {
3043 precedence1 = 3; /* element in prev-sibl axis */
3044 break;
3045 }
3046 if (node1->prev == NULL) {
3047 precedence1 = 2; /* element is parent */
3048 /*
3049 * URGENT TODO: Are there any cases, where the
3050 * parent of such a node is not an element node?
3051 */
3052 node1 = node1->parent;
3053 break;
3054 }
3055 } while (1);
3056 } else {
3057 precedence1 = 2; /* element is parent */
3058 node1 = node1->parent;
3059 }
3060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3061 /*
3062 * Fallback for whatever case.
3063 */
3064 node1 = miscNode1;
3065 precedence1 = 0;
3066 } else
3067 misc = 1;
3068 }
3069 break;
3070 case XML_NAMESPACE_DECL:
3071 /*
3072 * TODO: why do we return 1 for namespace nodes?
3073 */
3074 return(1);
3075 default:
3076 break;
3077 }
3078 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003079 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003080 break;
3081 case XML_ATTRIBUTE_NODE:
3082 precedence2 = 1; /* element is owner */
3083 miscNode2 = node2;
3084 node2 = node2->parent;
3085 misc = 1;
3086 break;
3087 case XML_TEXT_NODE:
3088 case XML_CDATA_SECTION_NODE:
3089 case XML_COMMENT_NODE:
3090 case XML_PI_NODE: {
3091 miscNode2 = node2;
3092 if (node2->prev != NULL) {
3093 do {
3094 node2 = node2->prev;
3095 if (node2->type == XML_ELEMENT_NODE) {
3096 precedence2 = 3; /* element in prev-sibl axis */
3097 break;
3098 }
3099 if (node2->prev == NULL) {
3100 precedence2 = 2; /* element is parent */
3101 node2 = node2->parent;
3102 break;
3103 }
3104 } while (1);
3105 } else {
3106 precedence2 = 2; /* element is parent */
3107 node2 = node2->parent;
3108 }
3109 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3110 (0 <= (long) node1->content))
3111 {
3112 node2 = miscNode2;
3113 precedence2 = 0;
3114 } else
3115 misc = 1;
3116 }
3117 break;
3118 case XML_NAMESPACE_DECL:
3119 return(1);
3120 default:
3121 break;
3122 }
3123 if (misc) {
3124 if (node1 == node2) {
3125 if (precedence1 == precedence2) {
3126 /*
3127 * The ugly case; but normally there aren't many
3128 * adjacent non-element nodes around.
3129 */
3130 cur = miscNode2->prev;
3131 while (cur != NULL) {
3132 if (cur == miscNode1)
3133 return(1);
3134 if (cur->type == XML_ELEMENT_NODE)
3135 return(-1);
3136 cur = cur->prev;
3137 }
3138 return (-1);
3139 } else {
3140 /*
3141 * Evaluate based on higher precedence wrt to the element.
3142 * TODO: This assumes attributes are sorted before content.
3143 * Is this 100% correct?
3144 */
3145 if (precedence1 < precedence2)
3146 return(1);
3147 else
3148 return(-1);
3149 }
3150 }
3151 /*
3152 * Special case: One of the helper-elements is contained by the other.
3153 * <foo>
3154 * <node2>
3155 * <node1>Text-1(precedence1 == 2)</node1>
3156 * </node2>
3157 * Text-6(precedence2 == 3)
3158 * </foo>
3159 */
3160 if ((precedence2 == 3) && (precedence1 > 1)) {
3161 cur = node1->parent;
3162 while (cur) {
3163 if (cur == node2)
3164 return(1);
3165 cur = cur->parent;
3166 }
3167 }
3168 if ((precedence1 == 3) && (precedence2 > 1)) {
3169 cur = node2->parent;
3170 while (cur) {
3171 if (cur == node1)
3172 return(-1);
3173 cur = cur->parent;
3174 }
3175 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003176 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003177
3178 /*
3179 * Speedup using document order if availble.
3180 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003181 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003182 (node2->type == XML_ELEMENT_NODE) &&
3183 (0 > (long) node1->content) &&
3184 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003185 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003186
3187 l1 = -((long) node1->content);
3188 l2 = -((long) node2->content);
3189 if (l1 < l2)
3190 return(1);
3191 if (l1 > l2)
3192 return(-1);
3193 }
3194
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003195turtle_comparison:
3196
William M. Brack97ac8192007-06-06 17:19:24 +00003197 if (miscNode1 != NULL)
3198 node1 = miscNode1;
3199 if (miscNode2 != NULL)
3200 node2 = miscNode2;
3201
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003202 if (node1 == node2->prev)
3203 return(1);
3204 if (node1 == node2->next)
3205 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003206 /*
3207 * compute depth to root
3208 */
3209 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3210 if (cur == node1)
3211 return(1);
3212 depth2++;
3213 }
3214 root = cur;
3215 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3216 if (cur == node2)
3217 return(-1);
3218 depth1++;
3219 }
3220 /*
3221 * Distinct document (or distinct entities :-( ) case.
3222 */
3223 if (root != cur) {
3224 return(-2);
3225 }
3226 /*
3227 * get the nearest common ancestor.
3228 */
3229 while (depth1 > depth2) {
3230 depth1--;
3231 node1 = node1->parent;
3232 }
3233 while (depth2 > depth1) {
3234 depth2--;
3235 node2 = node2->parent;
3236 }
3237 while (node1->parent != node2->parent) {
3238 node1 = node1->parent;
3239 node2 = node2->parent;
3240 /* should not happen but just in case ... */
3241 if ((node1 == NULL) || (node2 == NULL))
3242 return(-2);
3243 }
3244 /*
3245 * Find who's first.
3246 */
3247 if (node1 == node2->prev)
3248 return(1);
3249 if (node1 == node2->next)
3250 return(-1);
3251 /*
3252 * Speedup using document order if availble.
3253 */
3254 if ((node1->type == XML_ELEMENT_NODE) &&
3255 (node2->type == XML_ELEMENT_NODE) &&
3256 (0 > (long) node1->content) &&
3257 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003258 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003259
3260 l1 = -((long) node1->content);
3261 l2 = -((long) node2->content);
3262 if (l1 < l2)
3263 return(1);
3264 if (l1 > l2)
3265 return(-1);
3266 }
3267
3268 for (cur = node1->next;cur != NULL;cur = cur->next)
3269 if (cur == node2)
3270 return(1);
3271 return(-1); /* assume there is no sibling list corruption */
3272}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003273#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003274
Owen Taylor3473f882001-02-23 17:55:21 +00003275/**
3276 * xmlXPathNodeSetSort:
3277 * @set: the node set
3278 *
3279 * Sort the node set in document order
3280 */
3281void
3282xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003283 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003284 xmlNodePtr tmp;
3285
3286 if (set == NULL)
3287 return;
3288
3289 /* Use Shell's sort to sort the node-set */
3290 len = set->nodeNr;
3291 for (incr = len / 2; incr > 0; incr /= 2) {
3292 for (i = incr; i < len; i++) {
3293 j = i - incr;
3294 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003295#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003296 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3297 set->nodeTab[j + incr]) == -1)
3298#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003299 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003300 set->nodeTab[j + incr]) == -1)
3301#endif
3302 {
Owen Taylor3473f882001-02-23 17:55:21 +00003303 tmp = set->nodeTab[j];
3304 set->nodeTab[j] = set->nodeTab[j + incr];
3305 set->nodeTab[j + incr] = tmp;
3306 j -= incr;
3307 } else
3308 break;
3309 }
3310 }
3311 }
3312}
3313
3314#define XML_NODESET_DEFAULT 10
3315/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003316 * xmlXPathNodeSetDupNs:
3317 * @node: the parent node of the namespace XPath node
3318 * @ns: the libxml namespace declaration node.
3319 *
3320 * Namespace node in libxml don't match the XPath semantic. In a node set
3321 * the namespace nodes are duplicated and the next pointer is set to the
3322 * parent node in the XPath semantic.
3323 *
3324 * Returns the newly created object.
3325 */
3326static xmlNodePtr
3327xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3328 xmlNsPtr cur;
3329
3330 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3331 return(NULL);
3332 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3333 return((xmlNodePtr) ns);
3334
3335 /*
3336 * Allocate a new Namespace and fill the fields.
3337 */
3338 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3339 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003340 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003341 return(NULL);
3342 }
3343 memset(cur, 0, sizeof(xmlNs));
3344 cur->type = XML_NAMESPACE_DECL;
3345 if (ns->href != NULL)
3346 cur->href = xmlStrdup(ns->href);
3347 if (ns->prefix != NULL)
3348 cur->prefix = xmlStrdup(ns->prefix);
3349 cur->next = (xmlNsPtr) node;
3350 return((xmlNodePtr) cur);
3351}
3352
3353/**
3354 * xmlXPathNodeSetFreeNs:
3355 * @ns: the XPath namespace node found in a nodeset.
3356 *
William M. Brack08171912003-12-29 02:52:11 +00003357 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003358 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003359 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003360 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003361void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003362xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3363 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3364 return;
3365
3366 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3367 if (ns->href != NULL)
3368 xmlFree((xmlChar *)ns->href);
3369 if (ns->prefix != NULL)
3370 xmlFree((xmlChar *)ns->prefix);
3371 xmlFree(ns);
3372 }
3373}
3374
3375/**
Owen Taylor3473f882001-02-23 17:55:21 +00003376 * xmlXPathNodeSetCreate:
3377 * @val: an initial xmlNodePtr, or NULL
3378 *
3379 * Create a new xmlNodeSetPtr of type double and of value @val
3380 *
3381 * Returns the newly created object.
3382 */
3383xmlNodeSetPtr
3384xmlXPathNodeSetCreate(xmlNodePtr val) {
3385 xmlNodeSetPtr ret;
3386
3387 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3388 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003389 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003390 return(NULL);
3391 }
3392 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3393 if (val != NULL) {
3394 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3395 sizeof(xmlNodePtr));
3396 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003397 xmlXPathErrMemory(NULL, "creating nodeset\n");
3398 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003399 return(NULL);
3400 }
3401 memset(ret->nodeTab, 0 ,
3402 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3403 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003404 if (val->type == XML_NAMESPACE_DECL) {
3405 xmlNsPtr ns = (xmlNsPtr) val;
3406
3407 ret->nodeTab[ret->nodeNr++] =
3408 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3409 } else
3410 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003411 }
3412 return(ret);
3413}
3414
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003415/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003416 * xmlXPathNodeSetCreateSize:
3417 * @size: the initial size of the set
3418 *
3419 * Create a new xmlNodeSetPtr of type double and of value @val
3420 *
3421 * Returns the newly created object.
3422 */
3423static xmlNodeSetPtr
3424xmlXPathNodeSetCreateSize(int size) {
3425 xmlNodeSetPtr ret;
3426
3427 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3428 if (ret == NULL) {
3429 xmlXPathErrMemory(NULL, "creating nodeset\n");
3430 return(NULL);
3431 }
3432 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3433 if (size < XML_NODESET_DEFAULT)
3434 size = XML_NODESET_DEFAULT;
3435 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3436 if (ret->nodeTab == NULL) {
3437 xmlXPathErrMemory(NULL, "creating nodeset\n");
3438 xmlFree(ret);
3439 return(NULL);
3440 }
3441 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3442 ret->nodeMax = size;
3443 return(ret);
3444}
3445
3446/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003447 * xmlXPathNodeSetContains:
3448 * @cur: the node-set
3449 * @val: the node
3450 *
3451 * checks whether @cur contains @val
3452 *
3453 * Returns true (1) if @cur contains @val, false (0) otherwise
3454 */
3455int
3456xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3457 int i;
3458
Daniel Veillarda82b1822004-11-08 16:24:57 +00003459 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003460 if (val->type == XML_NAMESPACE_DECL) {
3461 for (i = 0; i < cur->nodeNr; i++) {
3462 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3463 xmlNsPtr ns1, ns2;
3464
3465 ns1 = (xmlNsPtr) val;
3466 ns2 = (xmlNsPtr) cur->nodeTab[i];
3467 if (ns1 == ns2)
3468 return(1);
3469 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3470 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3471 return(1);
3472 }
3473 }
3474 } else {
3475 for (i = 0; i < cur->nodeNr; i++) {
3476 if (cur->nodeTab[i] == val)
3477 return(1);
3478 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003479 }
3480 return(0);
3481}
3482
3483/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 * xmlXPathNodeSetAddNs:
3485 * @cur: the initial node set
3486 * @node: the hosting node
3487 * @ns: a the namespace node
3488 *
3489 * add a new namespace node to an existing NodeSet
3490 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003491void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003492xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3493 int i;
3494
Daniel Veillarda82b1822004-11-08 16:24:57 +00003495
3496 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3497 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003498 (node->type != XML_ELEMENT_NODE))
3499 return;
3500
William M. Brack08171912003-12-29 02:52:11 +00003501 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003502 /*
William M. Brack08171912003-12-29 02:52:11 +00003503 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003504 */
3505 for (i = 0;i < cur->nodeNr;i++) {
3506 if ((cur->nodeTab[i] != NULL) &&
3507 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003508 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003509 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3510 return;
3511 }
3512
3513 /*
3514 * grow the nodeTab if needed
3515 */
3516 if (cur->nodeMax == 0) {
3517 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3518 sizeof(xmlNodePtr));
3519 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003520 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003521 return;
3522 }
3523 memset(cur->nodeTab, 0 ,
3524 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3525 cur->nodeMax = XML_NODESET_DEFAULT;
3526 } else if (cur->nodeNr == cur->nodeMax) {
3527 xmlNodePtr *temp;
3528
3529 cur->nodeMax *= 2;
3530 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3531 sizeof(xmlNodePtr));
3532 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003533 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003534 return;
3535 }
3536 cur->nodeTab = temp;
3537 }
3538 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3539}
3540
3541/**
Owen Taylor3473f882001-02-23 17:55:21 +00003542 * xmlXPathNodeSetAdd:
3543 * @cur: the initial node set
3544 * @val: a new xmlNodePtr
3545 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003546 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003547 */
3548void
3549xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3550 int i;
3551
Daniel Veillarda82b1822004-11-08 16:24:57 +00003552 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003553
Daniel Veillardef0b4502003-03-24 13:57:34 +00003554#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003555 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3556 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003557#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003558
William M. Brack08171912003-12-29 02:52:11 +00003559 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003560 /*
William M. Brack08171912003-12-29 02:52:11 +00003561 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003562 */
3563 for (i = 0;i < cur->nodeNr;i++)
3564 if (cur->nodeTab[i] == val) return;
3565
3566 /*
3567 * grow the nodeTab if needed
3568 */
3569 if (cur->nodeMax == 0) {
3570 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3571 sizeof(xmlNodePtr));
3572 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003573 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003574 return;
3575 }
3576 memset(cur->nodeTab, 0 ,
3577 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3578 cur->nodeMax = XML_NODESET_DEFAULT;
3579 } else if (cur->nodeNr == cur->nodeMax) {
3580 xmlNodePtr *temp;
3581
3582 cur->nodeMax *= 2;
3583 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3584 sizeof(xmlNodePtr));
3585 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003586 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003587 return;
3588 }
3589 cur->nodeTab = temp;
3590 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003591 if (val->type == XML_NAMESPACE_DECL) {
3592 xmlNsPtr ns = (xmlNsPtr) val;
3593
3594 cur->nodeTab[cur->nodeNr++] =
3595 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3596 } else
3597 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003598}
3599
3600/**
3601 * xmlXPathNodeSetAddUnique:
3602 * @cur: the initial node set
3603 * @val: a new xmlNodePtr
3604 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003605 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003606 * when we are sure the node is not already in the set.
3607 */
3608void
3609xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003610 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003611
Daniel Veillardef0b4502003-03-24 13:57:34 +00003612#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003613 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3614 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003615#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003616
William M. Brack08171912003-12-29 02:52:11 +00003617 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003618 /*
3619 * grow the nodeTab if needed
3620 */
3621 if (cur->nodeMax == 0) {
3622 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3623 sizeof(xmlNodePtr));
3624 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003625 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003626 return;
3627 }
3628 memset(cur->nodeTab, 0 ,
3629 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3630 cur->nodeMax = XML_NODESET_DEFAULT;
3631 } else if (cur->nodeNr == cur->nodeMax) {
3632 xmlNodePtr *temp;
3633
3634 cur->nodeMax *= 2;
3635 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3636 sizeof(xmlNodePtr));
3637 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003638 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003639 return;
3640 }
3641 cur->nodeTab = temp;
3642 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003643 if (val->type == XML_NAMESPACE_DECL) {
3644 xmlNsPtr ns = (xmlNsPtr) val;
3645
3646 cur->nodeTab[cur->nodeNr++] =
3647 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3648 } else
3649 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003650}
3651
3652/**
3653 * xmlXPathNodeSetMerge:
3654 * @val1: the first NodeSet or NULL
3655 * @val2: the second NodeSet
3656 *
3657 * Merges two nodesets, all nodes from @val2 are added to @val1
3658 * if @val1 is NULL, a new set is created and copied from @val2
3659 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003660 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003661 */
3662xmlNodeSetPtr
3663xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003664 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003665 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003666
3667 if (val2 == NULL) return(val1);
3668 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003669 val1 = xmlXPathNodeSetCreate(NULL);
3670#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003671 /*
3672 * TODO: The optimization won't work in every case, since
3673 * those nasty namespace nodes need to be added with
3674 * xmlXPathNodeSetDupNs() to the set; thus a pure
3675 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003676 * If there was a flag on the nodesetval, indicating that
3677 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003678 */
3679 /*
3680 * Optimization: Create an equally sized node-set
3681 * and memcpy the content.
3682 */
3683 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3684 if (val1 == NULL)
3685 return(NULL);
3686 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003687 if (val2->nodeNr == 1)
3688 *(val1->nodeTab) = *(val2->nodeTab);
3689 else {
3690 memcpy(val1->nodeTab, val2->nodeTab,
3691 val2->nodeNr * sizeof(xmlNodePtr));
3692 }
3693 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003694 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003695 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003696#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003697 }
3698
William M. Brack08171912003-12-29 02:52:11 +00003699 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003700 initNr = val1->nodeNr;
3701
3702 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003703 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003704 /*
William M. Brack08171912003-12-29 02:52:11 +00003705 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003706 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003707 skip = 0;
3708 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003709 n1 = val1->nodeTab[j];
3710 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003711 skip = 1;
3712 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003713 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3714 (n2->type == XML_NAMESPACE_DECL)) {
3715 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3716 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3717 ((xmlNsPtr) n2)->prefix)))
3718 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003719 skip = 1;
3720 break;
3721 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003722 }
3723 }
3724 if (skip)
3725 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003726
3727 /*
3728 * grow the nodeTab if needed
3729 */
3730 if (val1->nodeMax == 0) {
3731 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3732 sizeof(xmlNodePtr));
3733 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003734 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003735 return(NULL);
3736 }
3737 memset(val1->nodeTab, 0 ,
3738 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3739 val1->nodeMax = XML_NODESET_DEFAULT;
3740 } else if (val1->nodeNr == val1->nodeMax) {
3741 xmlNodePtr *temp;
3742
3743 val1->nodeMax *= 2;
3744 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3745 sizeof(xmlNodePtr));
3746 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003747 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003748 return(NULL);
3749 }
3750 val1->nodeTab = temp;
3751 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003752 if (n2->type == XML_NAMESPACE_DECL) {
3753 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003754
3755 val1->nodeTab[val1->nodeNr++] =
3756 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3757 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003758 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003759 }
3760
3761 return(val1);
3762}
3763
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003764#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003765/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003766 * xmlXPathNodeSetMergeUnique:
3767 * @val1: the first NodeSet or NULL
3768 * @val2: the second NodeSet
3769 *
3770 * Merges two nodesets, all nodes from @val2 are added to @val1
3771 * if @val1 is NULL, a new set is created and copied from @val2
3772 *
3773 * Returns @val1 once extended or NULL in case of error.
3774 */
3775static xmlNodeSetPtr
3776xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003777 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003778
3779 if (val2 == NULL) return(val1);
3780 if (val1 == NULL) {
3781 val1 = xmlXPathNodeSetCreate(NULL);
3782 }
3783
William M. Brack08171912003-12-29 02:52:11 +00003784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003785
3786 for (i = 0;i < val2->nodeNr;i++) {
3787 /*
3788 * grow the nodeTab if needed
3789 */
3790 if (val1->nodeMax == 0) {
3791 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 sizeof(xmlNodePtr));
3793 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003794 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003795 return(NULL);
3796 }
3797 memset(val1->nodeTab, 0 ,
3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 val1->nodeMax = XML_NODESET_DEFAULT;
3800 } else if (val1->nodeNr == val1->nodeMax) {
3801 xmlNodePtr *temp;
3802
3803 val1->nodeMax *= 2;
3804 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805 sizeof(xmlNodePtr));
3806 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003807 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003808 return(NULL);
3809 }
3810 val1->nodeTab = temp;
3811 }
3812 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3814
3815 val1->nodeTab[val1->nodeNr++] =
3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817 } else
3818 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3819 }
3820
3821 return(val1);
3822}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003823#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3824
3825/**
3826 * xmlXPathNodeSetMergeAndClear:
3827 * @set1: the first NodeSet or NULL
3828 * @set2: the second NodeSet
3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3830 *
3831 * Merges two nodesets, all nodes from @set2 are added to @set1
3832 * if @set1 is NULL, a new set is created and copied from @set2.
3833 * Checks for duplicate nodes. Clears set2.
3834 *
3835 * Returns @set1 once extended or NULL in case of error.
3836 */
3837static xmlNodeSetPtr
3838xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3839 int hasNullEntries)
3840{
3841 if ((set1 == NULL) && (hasNullEntries == 0)) {
3842 /*
3843 * Note that doing a memcpy of the list, namespace nodes are
3844 * just assigned to set1, since set2 is cleared anyway.
3845 */
3846 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3847 if (set1 == NULL)
3848 return(NULL);
3849 if (set2->nodeNr != 0) {
3850 memcpy(set1->nodeTab, set2->nodeTab,
3851 set2->nodeNr * sizeof(xmlNodePtr));
3852 set1->nodeNr = set2->nodeNr;
3853 }
3854 } else {
3855 int i, j, initNbSet1;
3856 xmlNodePtr n1, n2;
3857
3858 if (set1 == NULL)
3859 set1 = xmlXPathNodeSetCreate(NULL);
3860
3861 initNbSet1 = set1->nodeNr;
3862 for (i = 0;i < set2->nodeNr;i++) {
3863 n2 = set2->nodeTab[i];
3864 /*
3865 * Skip NULLed entries.
3866 */
3867 if (n2 == NULL)
3868 continue;
3869 /*
3870 * Skip duplicates.
3871 */
3872 for (j = 0; j < initNbSet1; j++) {
3873 n1 = set1->nodeTab[j];
3874 if (n1 == n2) {
3875 goto skip_node;
3876 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3877 (n2->type == XML_NAMESPACE_DECL))
3878 {
3879 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3880 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3881 ((xmlNsPtr) n2)->prefix)))
3882 {
3883 /*
3884 * Free the namespace node.
3885 */
3886 set2->nodeTab[i] = NULL;
3887 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3888 goto skip_node;
3889 }
3890 }
3891 }
3892 /*
3893 * grow the nodeTab if needed
3894 */
3895 if (set1->nodeMax == 0) {
3896 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3897 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3898 if (set1->nodeTab == NULL) {
3899 xmlXPathErrMemory(NULL, "merging nodeset\n");
3900 return(NULL);
3901 }
3902 memset(set1->nodeTab, 0,
3903 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3904 set1->nodeMax = XML_NODESET_DEFAULT;
3905 } else if (set1->nodeNr >= set1->nodeMax) {
3906 xmlNodePtr *temp;
3907
3908 set1->nodeMax *= 2;
3909 temp = (xmlNodePtr *) xmlRealloc(
3910 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3911 if (temp == NULL) {
3912 xmlXPathErrMemory(NULL, "merging nodeset\n");
3913 return(NULL);
3914 }
3915 set1->nodeTab = temp;
3916 }
3917 if (n2->type == XML_NAMESPACE_DECL) {
3918 xmlNsPtr ns = (xmlNsPtr) n2;
3919
3920 set1->nodeTab[set1->nodeNr++] =
3921 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3922 } else
3923 set1->nodeTab[set1->nodeNr++] = n2;
3924skip_node:
3925 {}
3926 }
3927 }
3928 set2->nodeNr = 0;
3929 return(set1);
3930}
3931
3932/**
3933 * xmlXPathNodeSetMergeAndClearNoDupls:
3934 * @set1: the first NodeSet or NULL
3935 * @set2: the second NodeSet
3936 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3937 *
3938 * Merges two nodesets, all nodes from @set2 are added to @set1
3939 * if @set1 is NULL, a new set is created and copied from @set2.
3940 * Doesn't chack for duplicate nodes. Clears set2.
3941 *
3942 * Returns @set1 once extended or NULL in case of error.
3943 */
3944static xmlNodeSetPtr
3945xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3946 int hasNullEntries)
3947{
3948 if (set2 == NULL)
3949 return(set1);
3950 if ((set1 == NULL) && (hasNullEntries == 0)) {
3951 /*
3952 * Note that doing a memcpy of the list, namespace nodes are
3953 * just assigned to set1, since set2 is cleared anyway.
3954 */
3955 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3956 if (set1 == NULL)
3957 return(NULL);
3958 if (set2->nodeNr != 0) {
3959 memcpy(set1->nodeTab, set2->nodeTab,
3960 set2->nodeNr * sizeof(xmlNodePtr));
3961 set1->nodeNr = set2->nodeNr;
3962 }
3963 } else {
3964 int i;
3965 xmlNodePtr n2;
3966
3967 if (set1 == NULL)
3968 set1 = xmlXPathNodeSetCreate(NULL);
3969
3970 for (i = 0;i < set2->nodeNr;i++) {
3971 n2 = set2->nodeTab[i];
3972 /*
3973 * Skip NULLed entries.
3974 */
3975 if (n2 == NULL)
3976 continue;
3977 if (set1->nodeMax == 0) {
3978 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3979 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3980 if (set1->nodeTab == NULL) {
3981 xmlXPathErrMemory(NULL, "merging nodeset\n");
3982 return(NULL);
3983 }
3984 memset(set1->nodeTab, 0,
3985 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3986 set1->nodeMax = XML_NODESET_DEFAULT;
3987 } else if (set1->nodeNr >= set1->nodeMax) {
3988 xmlNodePtr *temp;
3989
3990 set1->nodeMax *= 2;
3991 temp = (xmlNodePtr *) xmlRealloc(
3992 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3993 if (temp == NULL) {
3994 xmlXPathErrMemory(NULL, "merging nodeset\n");
3995 return(NULL);
3996 }
3997 set1->nodeTab = temp;
3998 }
3999 set1->nodeTab[set1->nodeNr++] = n2;
4000 }
4001 }
4002 set2->nodeNr = 0;
4003 return(set1);
4004}
Daniel Veillard75be0132002-03-13 10:03:35 +00004005
4006/**
Owen Taylor3473f882001-02-23 17:55:21 +00004007 * xmlXPathNodeSetDel:
4008 * @cur: the initial node set
4009 * @val: an xmlNodePtr
4010 *
4011 * Removes an xmlNodePtr from an existing NodeSet
4012 */
4013void
4014xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4015 int i;
4016
4017 if (cur == NULL) return;
4018 if (val == NULL) return;
4019
4020 /*
William M. Brack08171912003-12-29 02:52:11 +00004021 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004022 */
4023 for (i = 0;i < cur->nodeNr;i++)
4024 if (cur->nodeTab[i] == val) break;
4025
William M. Brack08171912003-12-29 02:52:11 +00004026 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004027#ifdef DEBUG
4028 xmlGenericError(xmlGenericErrorContext,
4029 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4030 val->name);
4031#endif
4032 return;
4033 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004034 if ((cur->nodeTab[i] != NULL) &&
4035 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4036 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004037 cur->nodeNr--;
4038 for (;i < cur->nodeNr;i++)
4039 cur->nodeTab[i] = cur->nodeTab[i + 1];
4040 cur->nodeTab[cur->nodeNr] = NULL;
4041}
4042
4043/**
4044 * xmlXPathNodeSetRemove:
4045 * @cur: the initial node set
4046 * @val: the index to remove
4047 *
4048 * Removes an entry from an existing NodeSet list.
4049 */
4050void
4051xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4052 if (cur == NULL) return;
4053 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004054 if ((cur->nodeTab[val] != NULL) &&
4055 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4056 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004057 cur->nodeNr--;
4058 for (;val < cur->nodeNr;val++)
4059 cur->nodeTab[val] = cur->nodeTab[val + 1];
4060 cur->nodeTab[cur->nodeNr] = NULL;
4061}
4062
4063/**
4064 * xmlXPathFreeNodeSet:
4065 * @obj: the xmlNodeSetPtr to free
4066 *
4067 * Free the NodeSet compound (not the actual nodes !).
4068 */
4069void
4070xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4071 if (obj == NULL) return;
4072 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004073 int i;
4074
William M. Brack08171912003-12-29 02:52:11 +00004075 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004076 for (i = 0;i < obj->nodeNr;i++)
4077 if ((obj->nodeTab[i] != NULL) &&
4078 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4079 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004080 xmlFree(obj->nodeTab);
4081 }
Owen Taylor3473f882001-02-23 17:55:21 +00004082 xmlFree(obj);
4083}
4084
4085/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004086 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004087 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004088 *
4089 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4090 * are feed), but does *not* free the list itself. Sets the length of the
4091 * list to 0.
4092 */
4093static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004094xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4095{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004096 if ((set == NULL) || (set->nodeNr <= 0))
4097 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004098 else if (hasNsNodes) {
4099 int i;
4100 xmlNodePtr node;
4101
4102 for (i = 0; i < set->nodeNr; i++) {
4103 node = set->nodeTab[i];
4104 if ((node != NULL) &&
4105 (node->type == XML_NAMESPACE_DECL))
4106 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4107 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004108 }
4109 set->nodeNr = 0;
4110}
4111
4112/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004113 * xmlXPathNodeSetClearFromPos:
4114 * @set: the node set to be cleared
4115 * @pos: the start position to clear from
4116 *
4117 * Clears the list from temporary XPath objects (e.g. namespace nodes
4118 * are feed) starting with the entry at @pos, but does *not* free the list
4119 * itself. Sets the length of the list to @pos.
4120 */
4121static void
4122xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4123{
4124 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4125 return;
4126 else if ((hasNsNodes)) {
4127 int i;
4128 xmlNodePtr node;
4129
4130 for (i = pos; i < set->nodeNr; i++) {
4131 node = set->nodeTab[i];
4132 if ((node != NULL) &&
4133 (node->type == XML_NAMESPACE_DECL))
4134 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4135 }
4136 }
4137 set->nodeNr = pos;
4138}
4139
4140/**
Owen Taylor3473f882001-02-23 17:55:21 +00004141 * xmlXPathFreeValueTree:
4142 * @obj: the xmlNodeSetPtr to free
4143 *
4144 * Free the NodeSet compound and the actual tree, this is different
4145 * from xmlXPathFreeNodeSet()
4146 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004147static void
Owen Taylor3473f882001-02-23 17:55:21 +00004148xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4149 int i;
4150
4151 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004152
4153 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004154 for (i = 0;i < obj->nodeNr;i++) {
4155 if (obj->nodeTab[i] != NULL) {
4156 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4157 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4158 } else {
4159 xmlFreeNodeList(obj->nodeTab[i]);
4160 }
4161 }
4162 }
Owen Taylor3473f882001-02-23 17:55:21 +00004163 xmlFree(obj->nodeTab);
4164 }
Owen Taylor3473f882001-02-23 17:55:21 +00004165 xmlFree(obj);
4166}
4167
4168#if defined(DEBUG) || defined(DEBUG_STEP)
4169/**
4170 * xmlGenericErrorContextNodeSet:
4171 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004172 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004173 *
4174 * Quick display of a NodeSet
4175 */
4176void
4177xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4178 int i;
4179
4180 if (output == NULL) output = xmlGenericErrorContext;
4181 if (obj == NULL) {
4182 fprintf(output, "NodeSet == NULL !\n");
4183 return;
4184 }
4185 if (obj->nodeNr == 0) {
4186 fprintf(output, "NodeSet is empty\n");
4187 return;
4188 }
4189 if (obj->nodeTab == NULL) {
4190 fprintf(output, " nodeTab == NULL !\n");
4191 return;
4192 }
4193 for (i = 0; i < obj->nodeNr; i++) {
4194 if (obj->nodeTab[i] == NULL) {
4195 fprintf(output, " NULL !\n");
4196 return;
4197 }
4198 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4199 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4200 fprintf(output, " /");
4201 else if (obj->nodeTab[i]->name == NULL)
4202 fprintf(output, " noname!");
4203 else fprintf(output, " %s", obj->nodeTab[i]->name);
4204 }
4205 fprintf(output, "\n");
4206}
4207#endif
4208
4209/**
4210 * xmlXPathNewNodeSet:
4211 * @val: the NodePtr value
4212 *
4213 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4214 * it with the single Node @val
4215 *
4216 * Returns the newly created object.
4217 */
4218xmlXPathObjectPtr
4219xmlXPathNewNodeSet(xmlNodePtr val) {
4220 xmlXPathObjectPtr ret;
4221
4222 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4223 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004224 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004225 return(NULL);
4226 }
4227 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4228 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004229 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004230 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004231 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004232#ifdef XP_DEBUG_OBJ_USAGE
4233 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4234#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004235 return(ret);
4236}
4237
4238/**
4239 * xmlXPathNewValueTree:
4240 * @val: the NodePtr value
4241 *
4242 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4243 * it with the tree root @val
4244 *
4245 * Returns the newly created object.
4246 */
4247xmlXPathObjectPtr
4248xmlXPathNewValueTree(xmlNodePtr val) {
4249 xmlXPathObjectPtr ret;
4250
4251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4252 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004253 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004254 return(NULL);
4255 }
4256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4257 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004258 ret->boolval = 1;
4259 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004260 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004261#ifdef XP_DEBUG_OBJ_USAGE
4262 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4263#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004264 return(ret);
4265}
4266
4267/**
4268 * xmlXPathNewNodeSetList:
4269 * @val: an existing NodeSet
4270 *
4271 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4272 * it with the Nodeset @val
4273 *
4274 * Returns the newly created object.
4275 */
4276xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004277xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4278{
Owen Taylor3473f882001-02-23 17:55:21 +00004279 xmlXPathObjectPtr ret;
4280 int i;
4281
4282 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004283 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004284 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004285 ret = xmlXPathNewNodeSet(NULL);
4286 else {
4287 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4288 for (i = 1; i < val->nodeNr; ++i)
4289 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4290 }
Owen Taylor3473f882001-02-23 17:55:21 +00004291
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004292 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004293}
4294
4295/**
4296 * xmlXPathWrapNodeSet:
4297 * @val: the NodePtr value
4298 *
4299 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4300 *
4301 * Returns the newly created object.
4302 */
4303xmlXPathObjectPtr
4304xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4305 xmlXPathObjectPtr ret;
4306
4307 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4308 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004309 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004310 return(NULL);
4311 }
4312 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4313 ret->type = XPATH_NODESET;
4314 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004315#ifdef XP_DEBUG_OBJ_USAGE
4316 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4317#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004318 return(ret);
4319}
4320
4321/**
4322 * xmlXPathFreeNodeSetList:
4323 * @obj: an existing NodeSetList object
4324 *
4325 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4326 * the list contrary to xmlXPathFreeObject().
4327 */
4328void
4329xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4330 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004331#ifdef XP_DEBUG_OBJ_USAGE
4332 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4333#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004334 xmlFree(obj);
4335}
4336
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004337/**
4338 * xmlXPathDifference:
4339 * @nodes1: a node-set
4340 * @nodes2: a node-set
4341 *
4342 * Implements the EXSLT - Sets difference() function:
4343 * node-set set:difference (node-set, node-set)
4344 *
4345 * Returns the difference between the two node sets, or nodes1 if
4346 * nodes2 is empty
4347 */
4348xmlNodeSetPtr
4349xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4350 xmlNodeSetPtr ret;
4351 int i, l1;
4352 xmlNodePtr cur;
4353
4354 if (xmlXPathNodeSetIsEmpty(nodes2))
4355 return(nodes1);
4356
4357 ret = xmlXPathNodeSetCreate(NULL);
4358 if (xmlXPathNodeSetIsEmpty(nodes1))
4359 return(ret);
4360
4361 l1 = xmlXPathNodeSetGetLength(nodes1);
4362
4363 for (i = 0; i < l1; i++) {
4364 cur = xmlXPathNodeSetItem(nodes1, i);
4365 if (!xmlXPathNodeSetContains(nodes2, cur))
4366 xmlXPathNodeSetAddUnique(ret, cur);
4367 }
4368 return(ret);
4369}
4370
4371/**
4372 * xmlXPathIntersection:
4373 * @nodes1: a node-set
4374 * @nodes2: a node-set
4375 *
4376 * Implements the EXSLT - Sets intersection() function:
4377 * node-set set:intersection (node-set, node-set)
4378 *
4379 * Returns a node set comprising the nodes that are within both the
4380 * node sets passed as arguments
4381 */
4382xmlNodeSetPtr
4383xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4384 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4385 int i, l1;
4386 xmlNodePtr cur;
4387
4388 if (xmlXPathNodeSetIsEmpty(nodes1))
4389 return(ret);
4390 if (xmlXPathNodeSetIsEmpty(nodes2))
4391 return(ret);
4392
4393 l1 = xmlXPathNodeSetGetLength(nodes1);
4394
4395 for (i = 0; i < l1; i++) {
4396 cur = xmlXPathNodeSetItem(nodes1, i);
4397 if (xmlXPathNodeSetContains(nodes2, cur))
4398 xmlXPathNodeSetAddUnique(ret, cur);
4399 }
4400 return(ret);
4401}
4402
4403/**
4404 * xmlXPathDistinctSorted:
4405 * @nodes: a node-set, sorted by document order
4406 *
4407 * Implements the EXSLT - Sets distinct() function:
4408 * node-set set:distinct (node-set)
4409 *
4410 * Returns a subset of the nodes contained in @nodes, or @nodes if
4411 * it is empty
4412 */
4413xmlNodeSetPtr
4414xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4415 xmlNodeSetPtr ret;
4416 xmlHashTablePtr hash;
4417 int i, l;
4418 xmlChar * strval;
4419 xmlNodePtr cur;
4420
4421 if (xmlXPathNodeSetIsEmpty(nodes))
4422 return(nodes);
4423
4424 ret = xmlXPathNodeSetCreate(NULL);
4425 l = xmlXPathNodeSetGetLength(nodes);
4426 hash = xmlHashCreate (l);
4427 for (i = 0; i < l; i++) {
4428 cur = xmlXPathNodeSetItem(nodes, i);
4429 strval = xmlXPathCastNodeToString(cur);
4430 if (xmlHashLookup(hash, strval) == NULL) {
4431 xmlHashAddEntry(hash, strval, strval);
4432 xmlXPathNodeSetAddUnique(ret, cur);
4433 } else {
4434 xmlFree(strval);
4435 }
4436 }
4437 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4438 return(ret);
4439}
4440
4441/**
4442 * xmlXPathDistinct:
4443 * @nodes: a node-set
4444 *
4445 * Implements the EXSLT - Sets distinct() function:
4446 * node-set set:distinct (node-set)
4447 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4448 * is called with the sorted node-set
4449 *
4450 * Returns a subset of the nodes contained in @nodes, or @nodes if
4451 * it is empty
4452 */
4453xmlNodeSetPtr
4454xmlXPathDistinct (xmlNodeSetPtr nodes) {
4455 if (xmlXPathNodeSetIsEmpty(nodes))
4456 return(nodes);
4457
4458 xmlXPathNodeSetSort(nodes);
4459 return(xmlXPathDistinctSorted(nodes));
4460}
4461
4462/**
4463 * xmlXPathHasSameNodes:
4464 * @nodes1: a node-set
4465 * @nodes2: a node-set
4466 *
4467 * Implements the EXSLT - Sets has-same-nodes function:
4468 * boolean set:has-same-node(node-set, node-set)
4469 *
4470 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4471 * otherwise
4472 */
4473int
4474xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475 int i, l;
4476 xmlNodePtr cur;
4477
4478 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4479 xmlXPathNodeSetIsEmpty(nodes2))
4480 return(0);
4481
4482 l = xmlXPathNodeSetGetLength(nodes1);
4483 for (i = 0; i < l; i++) {
4484 cur = xmlXPathNodeSetItem(nodes1, i);
4485 if (xmlXPathNodeSetContains(nodes2, cur))
4486 return(1);
4487 }
4488 return(0);
4489}
4490
4491/**
4492 * xmlXPathNodeLeadingSorted:
4493 * @nodes: a node-set, sorted by document order
4494 * @node: a node
4495 *
4496 * Implements the EXSLT - Sets leading() function:
4497 * node-set set:leading (node-set, node-set)
4498 *
4499 * Returns the nodes in @nodes that precede @node in document order,
4500 * @nodes if @node is NULL or an empty node-set if @nodes
4501 * doesn't contain @node
4502 */
4503xmlNodeSetPtr
4504xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4505 int i, l;
4506 xmlNodePtr cur;
4507 xmlNodeSetPtr ret;
4508
4509 if (node == NULL)
4510 return(nodes);
4511
4512 ret = xmlXPathNodeSetCreate(NULL);
4513 if (xmlXPathNodeSetIsEmpty(nodes) ||
4514 (!xmlXPathNodeSetContains(nodes, node)))
4515 return(ret);
4516
4517 l = xmlXPathNodeSetGetLength(nodes);
4518 for (i = 0; i < l; i++) {
4519 cur = xmlXPathNodeSetItem(nodes, i);
4520 if (cur == node)
4521 break;
4522 xmlXPathNodeSetAddUnique(ret, cur);
4523 }
4524 return(ret);
4525}
4526
4527/**
4528 * xmlXPathNodeLeading:
4529 * @nodes: a node-set
4530 * @node: a node
4531 *
4532 * Implements the EXSLT - Sets leading() function:
4533 * node-set set:leading (node-set, node-set)
4534 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4535 * is called.
4536 *
4537 * Returns the nodes in @nodes that precede @node in document order,
4538 * @nodes if @node is NULL or an empty node-set if @nodes
4539 * doesn't contain @node
4540 */
4541xmlNodeSetPtr
4542xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4543 xmlXPathNodeSetSort(nodes);
4544 return(xmlXPathNodeLeadingSorted(nodes, node));
4545}
4546
4547/**
4548 * xmlXPathLeadingSorted:
4549 * @nodes1: a node-set, sorted by document order
4550 * @nodes2: a node-set, sorted by document order
4551 *
4552 * Implements the EXSLT - Sets leading() function:
4553 * node-set set:leading (node-set, node-set)
4554 *
4555 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4556 * in document order, @nodes1 if @nodes2 is NULL or empty or
4557 * an empty node-set if @nodes1 doesn't contain @nodes2
4558 */
4559xmlNodeSetPtr
4560xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4561 if (xmlXPathNodeSetIsEmpty(nodes2))
4562 return(nodes1);
4563 return(xmlXPathNodeLeadingSorted(nodes1,
4564 xmlXPathNodeSetItem(nodes2, 1)));
4565}
4566
4567/**
4568 * xmlXPathLeading:
4569 * @nodes1: a node-set
4570 * @nodes2: a node-set
4571 *
4572 * Implements the EXSLT - Sets leading() function:
4573 * node-set set:leading (node-set, node-set)
4574 * @nodes1 and @nodes2 are sorted by document order, then
4575 * #exslSetsLeadingSorted is called.
4576 *
4577 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4578 * in document order, @nodes1 if @nodes2 is NULL or empty or
4579 * an empty node-set if @nodes1 doesn't contain @nodes2
4580 */
4581xmlNodeSetPtr
4582xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4583 if (xmlXPathNodeSetIsEmpty(nodes2))
4584 return(nodes1);
4585 if (xmlXPathNodeSetIsEmpty(nodes1))
4586 return(xmlXPathNodeSetCreate(NULL));
4587 xmlXPathNodeSetSort(nodes1);
4588 xmlXPathNodeSetSort(nodes2);
4589 return(xmlXPathNodeLeadingSorted(nodes1,
4590 xmlXPathNodeSetItem(nodes2, 1)));
4591}
4592
4593/**
4594 * xmlXPathNodeTrailingSorted:
4595 * @nodes: a node-set, sorted by document order
4596 * @node: a node
4597 *
4598 * Implements the EXSLT - Sets trailing() function:
4599 * node-set set:trailing (node-set, node-set)
4600 *
4601 * Returns the nodes in @nodes that follow @node in document order,
4602 * @nodes if @node is NULL or an empty node-set if @nodes
4603 * doesn't contain @node
4604 */
4605xmlNodeSetPtr
4606xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4607 int i, l;
4608 xmlNodePtr cur;
4609 xmlNodeSetPtr ret;
4610
4611 if (node == NULL)
4612 return(nodes);
4613
4614 ret = xmlXPathNodeSetCreate(NULL);
4615 if (xmlXPathNodeSetIsEmpty(nodes) ||
4616 (!xmlXPathNodeSetContains(nodes, node)))
4617 return(ret);
4618
4619 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004620 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004621 cur = xmlXPathNodeSetItem(nodes, i);
4622 if (cur == node)
4623 break;
4624 xmlXPathNodeSetAddUnique(ret, cur);
4625 }
William M. Brack97ac8192007-06-06 17:19:24 +00004626 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004627 return(ret);
4628}
4629
4630/**
4631 * xmlXPathNodeTrailing:
4632 * @nodes: a node-set
4633 * @node: a node
4634 *
4635 * Implements the EXSLT - Sets trailing() function:
4636 * node-set set:trailing (node-set, node-set)
4637 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4638 * is called.
4639 *
4640 * Returns the nodes in @nodes that follow @node in document order,
4641 * @nodes if @node is NULL or an empty node-set if @nodes
4642 * doesn't contain @node
4643 */
4644xmlNodeSetPtr
4645xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4646 xmlXPathNodeSetSort(nodes);
4647 return(xmlXPathNodeTrailingSorted(nodes, node));
4648}
4649
4650/**
4651 * xmlXPathTrailingSorted:
4652 * @nodes1: a node-set, sorted by document order
4653 * @nodes2: a node-set, sorted by document order
4654 *
4655 * Implements the EXSLT - Sets trailing() function:
4656 * node-set set:trailing (node-set, node-set)
4657 *
4658 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4659 * in document order, @nodes1 if @nodes2 is NULL or empty or
4660 * an empty node-set if @nodes1 doesn't contain @nodes2
4661 */
4662xmlNodeSetPtr
4663xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4664 if (xmlXPathNodeSetIsEmpty(nodes2))
4665 return(nodes1);
4666 return(xmlXPathNodeTrailingSorted(nodes1,
4667 xmlXPathNodeSetItem(nodes2, 0)));
4668}
4669
4670/**
4671 * xmlXPathTrailing:
4672 * @nodes1: a node-set
4673 * @nodes2: a node-set
4674 *
4675 * Implements the EXSLT - Sets trailing() function:
4676 * node-set set:trailing (node-set, node-set)
4677 * @nodes1 and @nodes2 are sorted by document order, then
4678 * #xmlXPathTrailingSorted is called.
4679 *
4680 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4681 * in document order, @nodes1 if @nodes2 is NULL or empty or
4682 * an empty node-set if @nodes1 doesn't contain @nodes2
4683 */
4684xmlNodeSetPtr
4685xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4686 if (xmlXPathNodeSetIsEmpty(nodes2))
4687 return(nodes1);
4688 if (xmlXPathNodeSetIsEmpty(nodes1))
4689 return(xmlXPathNodeSetCreate(NULL));
4690 xmlXPathNodeSetSort(nodes1);
4691 xmlXPathNodeSetSort(nodes2);
4692 return(xmlXPathNodeTrailingSorted(nodes1,
4693 xmlXPathNodeSetItem(nodes2, 0)));
4694}
4695
Owen Taylor3473f882001-02-23 17:55:21 +00004696/************************************************************************
4697 * *
4698 * Routines to handle extra functions *
4699 * *
4700 ************************************************************************/
4701
4702/**
4703 * xmlXPathRegisterFunc:
4704 * @ctxt: the XPath context
4705 * @name: the function name
4706 * @f: the function implementation or NULL
4707 *
4708 * Register a new function. If @f is NULL it unregisters the function
4709 *
4710 * Returns 0 in case of success, -1 in case of error
4711 */
4712int
4713xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4714 xmlXPathFunction f) {
4715 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4716}
4717
4718/**
4719 * xmlXPathRegisterFuncNS:
4720 * @ctxt: the XPath context
4721 * @name: the function name
4722 * @ns_uri: the function namespace URI
4723 * @f: the function implementation or NULL
4724 *
4725 * Register a new function. If @f is NULL it unregisters the function
4726 *
4727 * Returns 0 in case of success, -1 in case of error
4728 */
4729int
4730xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4731 const xmlChar *ns_uri, xmlXPathFunction f) {
4732 if (ctxt == NULL)
4733 return(-1);
4734 if (name == NULL)
4735 return(-1);
4736
4737 if (ctxt->funcHash == NULL)
4738 ctxt->funcHash = xmlHashCreate(0);
4739 if (ctxt->funcHash == NULL)
4740 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004741 if (f == NULL)
4742 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004743 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004744}
4745
4746/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004747 * xmlXPathRegisterFuncLookup:
4748 * @ctxt: the XPath context
4749 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004750 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004751 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004752 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004753 */
4754void
4755xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4756 xmlXPathFuncLookupFunc f,
4757 void *funcCtxt) {
4758 if (ctxt == NULL)
4759 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004760 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004761 ctxt->funcLookupData = funcCtxt;
4762}
4763
4764/**
Owen Taylor3473f882001-02-23 17:55:21 +00004765 * xmlXPathFunctionLookup:
4766 * @ctxt: the XPath context
4767 * @name: the function name
4768 *
4769 * Search in the Function array of the context for the given
4770 * function.
4771 *
4772 * Returns the xmlXPathFunction or NULL if not found
4773 */
4774xmlXPathFunction
4775xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004776 if (ctxt == NULL)
4777 return (NULL);
4778
4779 if (ctxt->funcLookupFunc != NULL) {
4780 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004781 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004782
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004783 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004784 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004785 if (ret != NULL)
4786 return(ret);
4787 }
Owen Taylor3473f882001-02-23 17:55:21 +00004788 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4789}
4790
4791/**
4792 * xmlXPathFunctionLookupNS:
4793 * @ctxt: the XPath context
4794 * @name: the function name
4795 * @ns_uri: the function namespace URI
4796 *
4797 * Search in the Function array of the context for the given
4798 * function.
4799 *
4800 * Returns the xmlXPathFunction or NULL if not found
4801 */
4802xmlXPathFunction
4803xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4804 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004805 xmlXPathFunction ret;
4806
Owen Taylor3473f882001-02-23 17:55:21 +00004807 if (ctxt == NULL)
4808 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004809 if (name == NULL)
4810 return(NULL);
4811
Thomas Broyerba4ad322001-07-26 16:55:21 +00004812 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004813 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004814
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004815 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004816 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004817 if (ret != NULL)
4818 return(ret);
4819 }
4820
4821 if (ctxt->funcHash == NULL)
4822 return(NULL);
4823
William M. Brackad0e67c2004-12-01 14:35:10 +00004824 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4825 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004826}
4827
4828/**
4829 * xmlXPathRegisteredFuncsCleanup:
4830 * @ctxt: the XPath context
4831 *
4832 * Cleanup the XPath context data associated to registered functions
4833 */
4834void
4835xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4836 if (ctxt == NULL)
4837 return;
4838
4839 xmlHashFree(ctxt->funcHash, NULL);
4840 ctxt->funcHash = NULL;
4841}
4842
4843/************************************************************************
4844 * *
William M. Brack08171912003-12-29 02:52:11 +00004845 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004846 * *
4847 ************************************************************************/
4848
4849/**
4850 * xmlXPathRegisterVariable:
4851 * @ctxt: the XPath context
4852 * @name: the variable name
4853 * @value: the variable value or NULL
4854 *
4855 * Register a new variable value. If @value is NULL it unregisters
4856 * the variable
4857 *
4858 * Returns 0 in case of success, -1 in case of error
4859 */
4860int
4861xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4862 xmlXPathObjectPtr value) {
4863 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4864}
4865
4866/**
4867 * xmlXPathRegisterVariableNS:
4868 * @ctxt: the XPath context
4869 * @name: the variable name
4870 * @ns_uri: the variable namespace URI
4871 * @value: the variable value or NULL
4872 *
4873 * Register a new variable value. If @value is NULL it unregisters
4874 * the variable
4875 *
4876 * Returns 0 in case of success, -1 in case of error
4877 */
4878int
4879xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4880 const xmlChar *ns_uri,
4881 xmlXPathObjectPtr value) {
4882 if (ctxt == NULL)
4883 return(-1);
4884 if (name == NULL)
4885 return(-1);
4886
4887 if (ctxt->varHash == NULL)
4888 ctxt->varHash = xmlHashCreate(0);
4889 if (ctxt->varHash == NULL)
4890 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004891 if (value == NULL)
4892 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4893 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004894 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4895 (void *) value,
4896 (xmlHashDeallocator)xmlXPathFreeObject));
4897}
4898
4899/**
4900 * xmlXPathRegisterVariableLookup:
4901 * @ctxt: the XPath context
4902 * @f: the lookup function
4903 * @data: the lookup data
4904 *
4905 * register an external mechanism to do variable lookup
4906 */
4907void
4908xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4909 xmlXPathVariableLookupFunc f, void *data) {
4910 if (ctxt == NULL)
4911 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004912 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004913 ctxt->varLookupData = data;
4914}
4915
4916/**
4917 * xmlXPathVariableLookup:
4918 * @ctxt: the XPath context
4919 * @name: the variable name
4920 *
4921 * Search in the Variable array of the context for the given
4922 * variable value.
4923 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004924 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004925 */
4926xmlXPathObjectPtr
4927xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4928 if (ctxt == NULL)
4929 return(NULL);
4930
4931 if (ctxt->varLookupFunc != NULL) {
4932 xmlXPathObjectPtr ret;
4933
4934 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4935 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004936 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004937 }
4938 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4939}
4940
4941/**
4942 * xmlXPathVariableLookupNS:
4943 * @ctxt: the XPath context
4944 * @name: the variable name
4945 * @ns_uri: the variable namespace URI
4946 *
4947 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004948 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004949 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004950 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004951 */
4952xmlXPathObjectPtr
4953xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4954 const xmlChar *ns_uri) {
4955 if (ctxt == NULL)
4956 return(NULL);
4957
4958 if (ctxt->varLookupFunc != NULL) {
4959 xmlXPathObjectPtr ret;
4960
4961 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4962 (ctxt->varLookupData, name, ns_uri);
4963 if (ret != NULL) return(ret);
4964 }
4965
4966 if (ctxt->varHash == NULL)
4967 return(NULL);
4968 if (name == NULL)
4969 return(NULL);
4970
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004971 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004972 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004973}
4974
4975/**
4976 * xmlXPathRegisteredVariablesCleanup:
4977 * @ctxt: the XPath context
4978 *
4979 * Cleanup the XPath context data associated to registered variables
4980 */
4981void
4982xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4983 if (ctxt == NULL)
4984 return;
4985
Daniel Veillard76d66f42001-05-16 21:05:17 +00004986 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004987 ctxt->varHash = NULL;
4988}
4989
4990/**
4991 * xmlXPathRegisterNs:
4992 * @ctxt: the XPath context
4993 * @prefix: the namespace prefix
4994 * @ns_uri: the namespace name
4995 *
4996 * Register a new namespace. If @ns_uri is NULL it unregisters
4997 * the namespace
4998 *
4999 * Returns 0 in case of success, -1 in case of error
5000 */
5001int
5002xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5003 const xmlChar *ns_uri) {
5004 if (ctxt == NULL)
5005 return(-1);
5006 if (prefix == NULL)
5007 return(-1);
5008
5009 if (ctxt->nsHash == NULL)
5010 ctxt->nsHash = xmlHashCreate(10);
5011 if (ctxt->nsHash == NULL)
5012 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005013 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005014 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005015 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005016 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005017 (xmlHashDeallocator)xmlFree));
5018}
5019
5020/**
5021 * xmlXPathNsLookup:
5022 * @ctxt: the XPath context
5023 * @prefix: the namespace prefix value
5024 *
5025 * Search in the namespace declaration array of the context for the given
5026 * namespace name associated to the given prefix
5027 *
5028 * Returns the value or NULL if not found
5029 */
5030const xmlChar *
5031xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5032 if (ctxt == NULL)
5033 return(NULL);
5034 if (prefix == NULL)
5035 return(NULL);
5036
5037#ifdef XML_XML_NAMESPACE
5038 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5039 return(XML_XML_NAMESPACE);
5040#endif
5041
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005042 if (ctxt->namespaces != NULL) {
5043 int i;
5044
5045 for (i = 0;i < ctxt->nsNr;i++) {
5046 if ((ctxt->namespaces[i] != NULL) &&
5047 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5048 return(ctxt->namespaces[i]->href);
5049 }
5050 }
Owen Taylor3473f882001-02-23 17:55:21 +00005051
5052 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5053}
5054
5055/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005056 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005057 * @ctxt: the XPath context
5058 *
5059 * Cleanup the XPath context data associated to registered variables
5060 */
5061void
5062xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5063 if (ctxt == NULL)
5064 return;
5065
Daniel Veillard42766c02002-08-22 20:52:17 +00005066 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005067 ctxt->nsHash = NULL;
5068}
5069
5070/************************************************************************
5071 * *
5072 * Routines to handle Values *
5073 * *
5074 ************************************************************************/
5075
William M. Brack08171912003-12-29 02:52:11 +00005076/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005077
5078/**
5079 * xmlXPathNewFloat:
5080 * @val: the double value
5081 *
5082 * Create a new xmlXPathObjectPtr of type double and of value @val
5083 *
5084 * Returns the newly created object.
5085 */
5086xmlXPathObjectPtr
5087xmlXPathNewFloat(double val) {
5088 xmlXPathObjectPtr ret;
5089
5090 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5091 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005092 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005093 return(NULL);
5094 }
5095 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5096 ret->type = XPATH_NUMBER;
5097 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005098#ifdef XP_DEBUG_OBJ_USAGE
5099 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5100#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005101 return(ret);
5102}
5103
5104/**
5105 * xmlXPathNewBoolean:
5106 * @val: the boolean value
5107 *
5108 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5109 *
5110 * Returns the newly created object.
5111 */
5112xmlXPathObjectPtr
5113xmlXPathNewBoolean(int val) {
5114 xmlXPathObjectPtr ret;
5115
5116 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5117 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005118 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005119 return(NULL);
5120 }
5121 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5122 ret->type = XPATH_BOOLEAN;
5123 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005124#ifdef XP_DEBUG_OBJ_USAGE
5125 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5126#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005127 return(ret);
5128}
5129
5130/**
5131 * xmlXPathNewString:
5132 * @val: the xmlChar * value
5133 *
5134 * Create a new xmlXPathObjectPtr of type string and of value @val
5135 *
5136 * Returns the newly created object.
5137 */
5138xmlXPathObjectPtr
5139xmlXPathNewString(const xmlChar *val) {
5140 xmlXPathObjectPtr ret;
5141
5142 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5143 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005144 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005145 return(NULL);
5146 }
5147 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5148 ret->type = XPATH_STRING;
5149 if (val != NULL)
5150 ret->stringval = xmlStrdup(val);
5151 else
5152 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005153#ifdef XP_DEBUG_OBJ_USAGE
5154 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5155#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005156 return(ret);
5157}
5158
5159/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005160 * xmlXPathWrapString:
5161 * @val: the xmlChar * value
5162 *
5163 * Wraps the @val string into an XPath object.
5164 *
5165 * Returns the newly created object.
5166 */
5167xmlXPathObjectPtr
5168xmlXPathWrapString (xmlChar *val) {
5169 xmlXPathObjectPtr ret;
5170
5171 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5172 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005173 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005174 return(NULL);
5175 }
5176 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5177 ret->type = XPATH_STRING;
5178 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005179#ifdef XP_DEBUG_OBJ_USAGE
5180 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5181#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005182 return(ret);
5183}
5184
5185/**
Owen Taylor3473f882001-02-23 17:55:21 +00005186 * xmlXPathNewCString:
5187 * @val: the char * value
5188 *
5189 * Create a new xmlXPathObjectPtr of type string and of value @val
5190 *
5191 * Returns the newly created object.
5192 */
5193xmlXPathObjectPtr
5194xmlXPathNewCString(const char *val) {
5195 xmlXPathObjectPtr ret;
5196
5197 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5198 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005199 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005200 return(NULL);
5201 }
5202 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5203 ret->type = XPATH_STRING;
5204 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005205#ifdef XP_DEBUG_OBJ_USAGE
5206 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5207#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005208 return(ret);
5209}
5210
5211/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005212 * xmlXPathWrapCString:
5213 * @val: the char * value
5214 *
5215 * Wraps a string into an XPath object.
5216 *
5217 * Returns the newly created object.
5218 */
5219xmlXPathObjectPtr
5220xmlXPathWrapCString (char * val) {
5221 return(xmlXPathWrapString((xmlChar *)(val)));
5222}
5223
5224/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005225 * xmlXPathWrapExternal:
5226 * @val: the user data
5227 *
5228 * Wraps the @val data into an XPath object.
5229 *
5230 * Returns the newly created object.
5231 */
5232xmlXPathObjectPtr
5233xmlXPathWrapExternal (void *val) {
5234 xmlXPathObjectPtr ret;
5235
5236 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5237 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005238 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005239 return(NULL);
5240 }
5241 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5242 ret->type = XPATH_USERS;
5243 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005244#ifdef XP_DEBUG_OBJ_USAGE
5245 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5246#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005247 return(ret);
5248}
5249
5250/**
Owen Taylor3473f882001-02-23 17:55:21 +00005251 * xmlXPathObjectCopy:
5252 * @val: the original object
5253 *
5254 * allocate a new copy of a given object
5255 *
5256 * Returns the newly created object.
5257 */
5258xmlXPathObjectPtr
5259xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5260 xmlXPathObjectPtr ret;
5261
5262 if (val == NULL)
5263 return(NULL);
5264
5265 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5266 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005267 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005268 return(NULL);
5269 }
5270 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005271#ifdef XP_DEBUG_OBJ_USAGE
5272 xmlXPathDebugObjUsageRequested(NULL, val->type);
5273#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005274 switch (val->type) {
5275 case XPATH_BOOLEAN:
5276 case XPATH_NUMBER:
5277 case XPATH_POINT:
5278 case XPATH_RANGE:
5279 break;
5280 case XPATH_STRING:
5281 ret->stringval = xmlStrdup(val->stringval);
5282 break;
5283 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005284#if 0
5285/*
5286 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5287 this previous handling is no longer correct, and can cause some serious
5288 problems (ref. bug 145547)
5289*/
Owen Taylor3473f882001-02-23 17:55:21 +00005290 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005291 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005292 xmlNodePtr cur, tmp;
5293 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005294
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005295 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005296 top = xmlNewDoc(NULL);
5297 top->name = (char *)
5298 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005299 ret->user = top;
5300 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005301 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005302 cur = val->nodesetval->nodeTab[0]->children;
5303 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005304 tmp = xmlDocCopyNode(cur, top, 1);
5305 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005306 cur = cur->next;
5307 }
5308 }
William M. Bracke9449c52004-07-11 14:41:20 +00005309
Daniel Veillard9adc0462003-03-24 18:39:54 +00005310 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005311 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005312 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005313 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005314 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005315#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005316 case XPATH_NODESET:
5317 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005318 /* Do not deallocate the copied tree value */
5319 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005320 break;
5321 case XPATH_LOCATIONSET:
5322#ifdef LIBXML_XPTR_ENABLED
5323 {
5324 xmlLocationSetPtr loc = val->user;
5325 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5326 break;
5327 }
5328#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005329 case XPATH_USERS:
5330 ret->user = val->user;
5331 break;
5332 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005333 xmlGenericError(xmlGenericErrorContext,
5334 "xmlXPathObjectCopy: unsupported type %d\n",
5335 val->type);
5336 break;
5337 }
5338 return(ret);
5339}
5340
5341/**
5342 * xmlXPathFreeObject:
5343 * @obj: the object to free
5344 *
5345 * Free up an xmlXPathObjectPtr object.
5346 */
5347void
5348xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5349 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005350 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005351 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005352#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005353 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005354 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005355 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005356 } else
5357#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005358 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005359 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005360 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005361 } else {
5362 if (obj->nodesetval != NULL)
5363 xmlXPathFreeNodeSet(obj->nodesetval);
5364 }
Owen Taylor3473f882001-02-23 17:55:21 +00005365#ifdef LIBXML_XPTR_ENABLED
5366 } else if (obj->type == XPATH_LOCATIONSET) {
5367 if (obj->user != NULL)
5368 xmlXPtrFreeLocationSet(obj->user);
5369#endif
5370 } else if (obj->type == XPATH_STRING) {
5371 if (obj->stringval != NULL)
5372 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005373 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005374#ifdef XP_DEBUG_OBJ_USAGE
5375 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5376#endif
5377 xmlFree(obj);
5378}
Owen Taylor3473f882001-02-23 17:55:21 +00005379
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005380/**
5381 * xmlXPathReleaseObject:
5382 * @obj: the xmlXPathObjectPtr to free or to cache
5383 *
5384 * Depending on the state of the cache this frees the given
5385 * XPath object or stores it in the cache.
5386 */
5387static void
5388xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5389{
5390#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5391 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5392 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5393
5394#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5395
5396 if (obj == NULL)
5397 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005398 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005399 xmlXPathFreeObject(obj);
5400 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005401 xmlXPathContextCachePtr cache =
5402 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005403
5404 switch (obj->type) {
5405 case XPATH_NODESET:
5406 case XPATH_XSLT_TREE:
5407 if (obj->nodesetval != NULL) {
5408 if (obj->boolval) {
5409 /*
5410 * It looks like the @boolval is used for
5411 * evaluation if this an XSLT Result Tree Fragment.
5412 * TODO: Check if this assumption is correct.
5413 */
5414 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5415 xmlXPathFreeValueTree(obj->nodesetval);
5416 obj->nodesetval = NULL;
5417 } else if ((obj->nodesetval->nodeMax <= 40) &&
5418 (XP_CACHE_WANTS(cache->nodesetObjs,
5419 cache->maxNodeset)))
5420 {
5421 XP_CACHE_ADD(cache->nodesetObjs, obj);
5422 goto obj_cached;
5423 } else {
5424 xmlXPathFreeNodeSet(obj->nodesetval);
5425 obj->nodesetval = NULL;
5426 }
5427 }
5428 break;
5429 case XPATH_STRING:
5430 if (obj->stringval != NULL)
5431 xmlFree(obj->stringval);
5432
5433 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5434 XP_CACHE_ADD(cache->stringObjs, obj);
5435 goto obj_cached;
5436 }
5437 break;
5438 case XPATH_BOOLEAN:
5439 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5440 XP_CACHE_ADD(cache->booleanObjs, obj);
5441 goto obj_cached;
5442 }
5443 break;
5444 case XPATH_NUMBER:
5445 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5446 XP_CACHE_ADD(cache->numberObjs, obj);
5447 goto obj_cached;
5448 }
5449 break;
5450#ifdef LIBXML_XPTR_ENABLED
5451 case XPATH_LOCATIONSET:
5452 if (obj->user != NULL) {
5453 xmlXPtrFreeLocationSet(obj->user);
5454 }
5455 goto free_obj;
5456#endif
5457 default:
5458 goto free_obj;
5459 }
5460
5461 /*
5462 * Fallback to adding to the misc-objects slot.
5463 */
5464 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5465 XP_CACHE_ADD(cache->miscObjs, obj);
5466 } else
5467 goto free_obj;
5468
5469obj_cached:
5470
5471#ifdef XP_DEBUG_OBJ_USAGE
5472 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5473#endif
5474
5475 if (obj->nodesetval != NULL) {
5476 xmlNodeSetPtr tmpset = obj->nodesetval;
5477
5478 /*
5479 * TODO: Due to those nasty ns-nodes, we need to traverse
5480 * the list and free the ns-nodes.
5481 * URGENT TODO: Check if it's actually slowing things down.
5482 * Maybe we shouldn't try to preserve the list.
5483 */
5484 if (tmpset->nodeNr > 1) {
5485 int i;
5486 xmlNodePtr node;
5487
5488 for (i = 0; i < tmpset->nodeNr; i++) {
5489 node = tmpset->nodeTab[i];
5490 if ((node != NULL) &&
5491 (node->type == XML_NAMESPACE_DECL))
5492 {
5493 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5494 }
5495 }
5496 } else if (tmpset->nodeNr == 1) {
5497 if ((tmpset->nodeTab[0] != NULL) &&
5498 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5499 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5500 }
5501 tmpset->nodeNr = 0;
5502 memset(obj, 0, sizeof(xmlXPathObject));
5503 obj->nodesetval = tmpset;
5504 } else
5505 memset(obj, 0, sizeof(xmlXPathObject));
5506
5507 return;
5508
5509free_obj:
5510 /*
5511 * Cache is full; free the object.
5512 */
5513 if (obj->nodesetval != NULL)
5514 xmlXPathFreeNodeSet(obj->nodesetval);
5515#ifdef XP_DEBUG_OBJ_USAGE
5516 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5517#endif
5518 xmlFree(obj);
5519 }
5520 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005521}
5522
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005523
5524/************************************************************************
5525 * *
5526 * Type Casting Routines *
5527 * *
5528 ************************************************************************/
5529
5530/**
5531 * xmlXPathCastBooleanToString:
5532 * @val: a boolean
5533 *
5534 * Converts a boolean to its string value.
5535 *
5536 * Returns a newly allocated string.
5537 */
5538xmlChar *
5539xmlXPathCastBooleanToString (int val) {
5540 xmlChar *ret;
5541 if (val)
5542 ret = xmlStrdup((const xmlChar *) "true");
5543 else
5544 ret = xmlStrdup((const xmlChar *) "false");
5545 return(ret);
5546}
5547
5548/**
5549 * xmlXPathCastNumberToString:
5550 * @val: a number
5551 *
5552 * Converts a number to its string value.
5553 *
5554 * Returns a newly allocated string.
5555 */
5556xmlChar *
5557xmlXPathCastNumberToString (double val) {
5558 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005559 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005560 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005561 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005562 break;
5563 case -1:
5564 ret = xmlStrdup((const xmlChar *) "-Infinity");
5565 break;
5566 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005567 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005568 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005569 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5570 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005571 } else {
5572 /* could be improved */
5573 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005574 xmlXPathFormatNumber(val, buf, 99);
5575 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005576 ret = xmlStrdup((const xmlChar *) buf);
5577 }
5578 }
5579 return(ret);
5580}
5581
5582/**
5583 * xmlXPathCastNodeToString:
5584 * @node: a node
5585 *
5586 * Converts a node to its string value.
5587 *
5588 * Returns a newly allocated string.
5589 */
5590xmlChar *
5591xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005592xmlChar *ret;
5593 if ((ret = xmlNodeGetContent(node)) == NULL)
5594 ret = xmlStrdup((const xmlChar *) "");
5595 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005596}
5597
5598/**
5599 * xmlXPathCastNodeSetToString:
5600 * @ns: a node-set
5601 *
5602 * Converts a node-set to its string value.
5603 *
5604 * Returns a newly allocated string.
5605 */
5606xmlChar *
5607xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5608 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5609 return(xmlStrdup((const xmlChar *) ""));
5610
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005611 if (ns->nodeNr > 1)
5612 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005613 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5614}
5615
5616/**
5617 * xmlXPathCastToString:
5618 * @val: an XPath object
5619 *
5620 * Converts an existing object to its string() equivalent
5621 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005622 * Returns the allocated string value of the object, NULL in case of error.
5623 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005624 */
5625xmlChar *
5626xmlXPathCastToString(xmlXPathObjectPtr val) {
5627 xmlChar *ret = NULL;
5628
5629 if (val == NULL)
5630 return(xmlStrdup((const xmlChar *) ""));
5631 switch (val->type) {
5632 case XPATH_UNDEFINED:
5633#ifdef DEBUG_EXPR
5634 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5635#endif
5636 ret = xmlStrdup((const xmlChar *) "");
5637 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005638 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005639 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005640 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5641 break;
5642 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005643 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005644 case XPATH_BOOLEAN:
5645 ret = xmlXPathCastBooleanToString(val->boolval);
5646 break;
5647 case XPATH_NUMBER: {
5648 ret = xmlXPathCastNumberToString(val->floatval);
5649 break;
5650 }
5651 case XPATH_USERS:
5652 case XPATH_POINT:
5653 case XPATH_RANGE:
5654 case XPATH_LOCATIONSET:
5655 TODO
5656 ret = xmlStrdup((const xmlChar *) "");
5657 break;
5658 }
5659 return(ret);
5660}
5661
5662/**
5663 * xmlXPathConvertString:
5664 * @val: an XPath object
5665 *
5666 * Converts an existing object to its string() equivalent
5667 *
5668 * Returns the new object, the old one is freed (or the operation
5669 * is done directly on @val)
5670 */
5671xmlXPathObjectPtr
5672xmlXPathConvertString(xmlXPathObjectPtr val) {
5673 xmlChar *res = NULL;
5674
5675 if (val == NULL)
5676 return(xmlXPathNewCString(""));
5677
5678 switch (val->type) {
5679 case XPATH_UNDEFINED:
5680#ifdef DEBUG_EXPR
5681 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5682#endif
5683 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005684 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005685 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005686 res = xmlXPathCastNodeSetToString(val->nodesetval);
5687 break;
5688 case XPATH_STRING:
5689 return(val);
5690 case XPATH_BOOLEAN:
5691 res = xmlXPathCastBooleanToString(val->boolval);
5692 break;
5693 case XPATH_NUMBER:
5694 res = xmlXPathCastNumberToString(val->floatval);
5695 break;
5696 case XPATH_USERS:
5697 case XPATH_POINT:
5698 case XPATH_RANGE:
5699 case XPATH_LOCATIONSET:
5700 TODO;
5701 break;
5702 }
5703 xmlXPathFreeObject(val);
5704 if (res == NULL)
5705 return(xmlXPathNewCString(""));
5706 return(xmlXPathWrapString(res));
5707}
5708
5709/**
5710 * xmlXPathCastBooleanToNumber:
5711 * @val: a boolean
5712 *
5713 * Converts a boolean to its number value
5714 *
5715 * Returns the number value
5716 */
5717double
5718xmlXPathCastBooleanToNumber(int val) {
5719 if (val)
5720 return(1.0);
5721 return(0.0);
5722}
5723
5724/**
5725 * xmlXPathCastStringToNumber:
5726 * @val: a string
5727 *
5728 * Converts a string to its number value
5729 *
5730 * Returns the number value
5731 */
5732double
5733xmlXPathCastStringToNumber(const xmlChar * val) {
5734 return(xmlXPathStringEvalNumber(val));
5735}
5736
5737/**
5738 * xmlXPathCastNodeToNumber:
5739 * @node: a node
5740 *
5741 * Converts a node to its number value
5742 *
5743 * Returns the number value
5744 */
5745double
5746xmlXPathCastNodeToNumber (xmlNodePtr node) {
5747 xmlChar *strval;
5748 double ret;
5749
5750 if (node == NULL)
5751 return(xmlXPathNAN);
5752 strval = xmlXPathCastNodeToString(node);
5753 if (strval == NULL)
5754 return(xmlXPathNAN);
5755 ret = xmlXPathCastStringToNumber(strval);
5756 xmlFree(strval);
5757
5758 return(ret);
5759}
5760
5761/**
5762 * xmlXPathCastNodeSetToNumber:
5763 * @ns: a node-set
5764 *
5765 * Converts a node-set to its number value
5766 *
5767 * Returns the number value
5768 */
5769double
5770xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5771 xmlChar *str;
5772 double ret;
5773
5774 if (ns == NULL)
5775 return(xmlXPathNAN);
5776 str = xmlXPathCastNodeSetToString(ns);
5777 ret = xmlXPathCastStringToNumber(str);
5778 xmlFree(str);
5779 return(ret);
5780}
5781
5782/**
5783 * xmlXPathCastToNumber:
5784 * @val: an XPath object
5785 *
5786 * Converts an XPath object to its number value
5787 *
5788 * Returns the number value
5789 */
5790double
5791xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5792 double ret = 0.0;
5793
5794 if (val == NULL)
5795 return(xmlXPathNAN);
5796 switch (val->type) {
5797 case XPATH_UNDEFINED:
5798#ifdef DEGUB_EXPR
5799 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5800#endif
5801 ret = xmlXPathNAN;
5802 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005803 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005804 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005805 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5806 break;
5807 case XPATH_STRING:
5808 ret = xmlXPathCastStringToNumber(val->stringval);
5809 break;
5810 case XPATH_NUMBER:
5811 ret = val->floatval;
5812 break;
5813 case XPATH_BOOLEAN:
5814 ret = xmlXPathCastBooleanToNumber(val->boolval);
5815 break;
5816 case XPATH_USERS:
5817 case XPATH_POINT:
5818 case XPATH_RANGE:
5819 case XPATH_LOCATIONSET:
5820 TODO;
5821 ret = xmlXPathNAN;
5822 break;
5823 }
5824 return(ret);
5825}
5826
5827/**
5828 * xmlXPathConvertNumber:
5829 * @val: an XPath object
5830 *
5831 * Converts an existing object to its number() equivalent
5832 *
5833 * Returns the new object, the old one is freed (or the operation
5834 * is done directly on @val)
5835 */
5836xmlXPathObjectPtr
5837xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5838 xmlXPathObjectPtr ret;
5839
5840 if (val == NULL)
5841 return(xmlXPathNewFloat(0.0));
5842 if (val->type == XPATH_NUMBER)
5843 return(val);
5844 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5845 xmlXPathFreeObject(val);
5846 return(ret);
5847}
5848
5849/**
5850 * xmlXPathCastNumberToBoolean:
5851 * @val: a number
5852 *
5853 * Converts a number to its boolean value
5854 *
5855 * Returns the boolean value
5856 */
5857int
5858xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005859 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005860 return(0);
5861 return(1);
5862}
5863
5864/**
5865 * xmlXPathCastStringToBoolean:
5866 * @val: a string
5867 *
5868 * Converts a string to its boolean value
5869 *
5870 * Returns the boolean value
5871 */
5872int
5873xmlXPathCastStringToBoolean (const xmlChar *val) {
5874 if ((val == NULL) || (xmlStrlen(val) == 0))
5875 return(0);
5876 return(1);
5877}
5878
5879/**
5880 * xmlXPathCastNodeSetToBoolean:
5881 * @ns: a node-set
5882 *
5883 * Converts a node-set to its boolean value
5884 *
5885 * Returns the boolean value
5886 */
5887int
5888xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5889 if ((ns == NULL) || (ns->nodeNr == 0))
5890 return(0);
5891 return(1);
5892}
5893
5894/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005895 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005896 * @val: an XPath object
5897 *
5898 * Converts an XPath object to its boolean value
5899 *
5900 * Returns the boolean value
5901 */
5902int
5903xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5904 int ret = 0;
5905
5906 if (val == NULL)
5907 return(0);
5908 switch (val->type) {
5909 case XPATH_UNDEFINED:
5910#ifdef DEBUG_EXPR
5911 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5912#endif
5913 ret = 0;
5914 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005915 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005916 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005917 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5918 break;
5919 case XPATH_STRING:
5920 ret = xmlXPathCastStringToBoolean(val->stringval);
5921 break;
5922 case XPATH_NUMBER:
5923 ret = xmlXPathCastNumberToBoolean(val->floatval);
5924 break;
5925 case XPATH_BOOLEAN:
5926 ret = val->boolval;
5927 break;
5928 case XPATH_USERS:
5929 case XPATH_POINT:
5930 case XPATH_RANGE:
5931 case XPATH_LOCATIONSET:
5932 TODO;
5933 ret = 0;
5934 break;
5935 }
5936 return(ret);
5937}
5938
5939
5940/**
5941 * xmlXPathConvertBoolean:
5942 * @val: an XPath object
5943 *
5944 * Converts an existing object to its boolean() equivalent
5945 *
5946 * Returns the new object, the old one is freed (or the operation
5947 * is done directly on @val)
5948 */
5949xmlXPathObjectPtr
5950xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5951 xmlXPathObjectPtr ret;
5952
5953 if (val == NULL)
5954 return(xmlXPathNewBoolean(0));
5955 if (val->type == XPATH_BOOLEAN)
5956 return(val);
5957 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5958 xmlXPathFreeObject(val);
5959 return(ret);
5960}
5961
Owen Taylor3473f882001-02-23 17:55:21 +00005962/************************************************************************
5963 * *
5964 * Routines to handle XPath contexts *
5965 * *
5966 ************************************************************************/
5967
5968/**
5969 * xmlXPathNewContext:
5970 * @doc: the XML document
5971 *
5972 * Create a new xmlXPathContext
5973 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005974 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005975 */
5976xmlXPathContextPtr
5977xmlXPathNewContext(xmlDocPtr doc) {
5978 xmlXPathContextPtr ret;
5979
5980 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5981 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005982 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005983 return(NULL);
5984 }
5985 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5986 ret->doc = doc;
5987 ret->node = NULL;
5988
5989 ret->varHash = NULL;
5990
5991 ret->nb_types = 0;
5992 ret->max_types = 0;
5993 ret->types = NULL;
5994
5995 ret->funcHash = xmlHashCreate(0);
5996
5997 ret->nb_axis = 0;
5998 ret->max_axis = 0;
5999 ret->axis = NULL;
6000
6001 ret->nsHash = NULL;
6002 ret->user = NULL;
6003
6004 ret->contextSize = -1;
6005 ret->proximityPosition = -1;
6006
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006007#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006008 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006009 xmlXPathFreeContext(ret);
6010 return(NULL);
6011 }
6012#endif
6013
6014 xmlXPathRegisterAllFunctions(ret);
6015
Owen Taylor3473f882001-02-23 17:55:21 +00006016 return(ret);
6017}
6018
6019/**
6020 * xmlXPathFreeContext:
6021 * @ctxt: the context to free
6022 *
6023 * Free up an xmlXPathContext
6024 */
6025void
6026xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006027 if (ctxt == NULL) return;
6028
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006029 if (ctxt->cache != NULL)
6030 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006031 xmlXPathRegisteredNsCleanup(ctxt);
6032 xmlXPathRegisteredFuncsCleanup(ctxt);
6033 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006034 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006035 xmlFree(ctxt);
6036}
6037
6038/************************************************************************
6039 * *
6040 * Routines to handle XPath parser contexts *
6041 * *
6042 ************************************************************************/
6043
6044#define CHECK_CTXT(ctxt) \
6045 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006046 __xmlRaiseError(NULL, NULL, NULL, \
6047 NULL, NULL, XML_FROM_XPATH, \
6048 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6049 __FILE__, __LINE__, \
6050 NULL, NULL, NULL, 0, 0, \
6051 "NULL context pointer\n"); \
6052 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006053 } \
6054
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006055#define CHECK_CTXT_NEG(ctxt) \
6056 if (ctxt == NULL) { \
6057 __xmlRaiseError(NULL, NULL, NULL, \
6058 NULL, NULL, XML_FROM_XPATH, \
6059 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6060 __FILE__, __LINE__, \
6061 NULL, NULL, NULL, 0, 0, \
6062 "NULL context pointer\n"); \
6063 return(-1); \
6064 } \
6065
Owen Taylor3473f882001-02-23 17:55:21 +00006066
6067#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006068 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6069 (ctxt->doc->children == NULL)) { \
6070 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006071 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006072 }
Owen Taylor3473f882001-02-23 17:55:21 +00006073
6074
6075/**
6076 * xmlXPathNewParserContext:
6077 * @str: the XPath expression
6078 * @ctxt: the XPath context
6079 *
6080 * Create a new xmlXPathParserContext
6081 *
6082 * Returns the xmlXPathParserContext just allocated.
6083 */
6084xmlXPathParserContextPtr
6085xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6086 xmlXPathParserContextPtr ret;
6087
6088 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6089 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006090 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006091 return(NULL);
6092 }
6093 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6094 ret->cur = ret->base = str;
6095 ret->context = ctxt;
6096
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006097 ret->comp = xmlXPathNewCompExpr();
6098 if (ret->comp == NULL) {
6099 xmlFree(ret->valueTab);
6100 xmlFree(ret);
6101 return(NULL);
6102 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006103 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6104 ret->comp->dict = ctxt->dict;
6105 xmlDictReference(ret->comp->dict);
6106 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006107
6108 return(ret);
6109}
6110
6111/**
6112 * xmlXPathCompParserContext:
6113 * @comp: the XPath compiled expression
6114 * @ctxt: the XPath context
6115 *
6116 * Create a new xmlXPathParserContext when processing a compiled expression
6117 *
6118 * Returns the xmlXPathParserContext just allocated.
6119 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006120static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006121xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6122 xmlXPathParserContextPtr ret;
6123
6124 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6125 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006126 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006127 return(NULL);
6128 }
6129 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6130
Owen Taylor3473f882001-02-23 17:55:21 +00006131 /* Allocate the value stack */
6132 ret->valueTab = (xmlXPathObjectPtr *)
6133 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006134 if (ret->valueTab == NULL) {
6135 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006136 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006137 return(NULL);
6138 }
Owen Taylor3473f882001-02-23 17:55:21 +00006139 ret->valueNr = 0;
6140 ret->valueMax = 10;
6141 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006142
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006143 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006144 ret->comp = comp;
6145
Owen Taylor3473f882001-02-23 17:55:21 +00006146 return(ret);
6147}
6148
6149/**
6150 * xmlXPathFreeParserContext:
6151 * @ctxt: the context to free
6152 *
6153 * Free up an xmlXPathParserContext
6154 */
6155void
6156xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6157 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006158 xmlFree(ctxt->valueTab);
6159 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006160 if (ctxt->comp != NULL) {
6161#ifdef XPATH_STREAMING
6162 if (ctxt->comp->stream != NULL) {
6163 xmlFreePatternList(ctxt->comp->stream);
6164 ctxt->comp->stream = NULL;
6165 }
6166#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006167 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006168 }
Owen Taylor3473f882001-02-23 17:55:21 +00006169 xmlFree(ctxt);
6170}
6171
6172/************************************************************************
6173 * *
6174 * The implicit core function library *
6175 * *
6176 ************************************************************************/
6177
Owen Taylor3473f882001-02-23 17:55:21 +00006178/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006179 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006180 * @node: a node pointer
6181 *
6182 * Function computing the beginning of the string value of the node,
6183 * used to speed up comparisons
6184 *
6185 * Returns an int usable as a hash
6186 */
6187static unsigned int
6188xmlXPathNodeValHash(xmlNodePtr node) {
6189 int len = 2;
6190 const xmlChar * string = NULL;
6191 xmlNodePtr tmp = NULL;
6192 unsigned int ret = 0;
6193
6194 if (node == NULL)
6195 return(0);
6196
Daniel Veillard9adc0462003-03-24 18:39:54 +00006197 if (node->type == XML_DOCUMENT_NODE) {
6198 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6199 if (tmp == NULL)
6200 node = node->children;
6201 else
6202 node = tmp;
6203
6204 if (node == NULL)
6205 return(0);
6206 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006207
6208 switch (node->type) {
6209 case XML_COMMENT_NODE:
6210 case XML_PI_NODE:
6211 case XML_CDATA_SECTION_NODE:
6212 case XML_TEXT_NODE:
6213 string = node->content;
6214 if (string == NULL)
6215 return(0);
6216 if (string[0] == 0)
6217 return(0);
6218 return(((unsigned int) string[0]) +
6219 (((unsigned int) string[1]) << 8));
6220 case XML_NAMESPACE_DECL:
6221 string = ((xmlNsPtr)node)->href;
6222 if (string == NULL)
6223 return(0);
6224 if (string[0] == 0)
6225 return(0);
6226 return(((unsigned int) string[0]) +
6227 (((unsigned int) string[1]) << 8));
6228 case XML_ATTRIBUTE_NODE:
6229 tmp = ((xmlAttrPtr) node)->children;
6230 break;
6231 case XML_ELEMENT_NODE:
6232 tmp = node->children;
6233 break;
6234 default:
6235 return(0);
6236 }
6237 while (tmp != NULL) {
6238 switch (tmp->type) {
6239 case XML_COMMENT_NODE:
6240 case XML_PI_NODE:
6241 case XML_CDATA_SECTION_NODE:
6242 case XML_TEXT_NODE:
6243 string = tmp->content;
6244 break;
6245 case XML_NAMESPACE_DECL:
6246 string = ((xmlNsPtr)tmp)->href;
6247 break;
6248 default:
6249 break;
6250 }
6251 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006252 if (len == 1) {
6253 return(ret + (((unsigned int) string[0]) << 8));
6254 }
6255 if (string[1] == 0) {
6256 len = 1;
6257 ret = (unsigned int) string[0];
6258 } else {
6259 return(((unsigned int) string[0]) +
6260 (((unsigned int) string[1]) << 8));
6261 }
6262 }
6263 /*
6264 * Skip to next node
6265 */
6266 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6267 if (tmp->children->type != XML_ENTITY_DECL) {
6268 tmp = tmp->children;
6269 continue;
6270 }
6271 }
6272 if (tmp == node)
6273 break;
6274
6275 if (tmp->next != NULL) {
6276 tmp = tmp->next;
6277 continue;
6278 }
6279
6280 do {
6281 tmp = tmp->parent;
6282 if (tmp == NULL)
6283 break;
6284 if (tmp == node) {
6285 tmp = NULL;
6286 break;
6287 }
6288 if (tmp->next != NULL) {
6289 tmp = tmp->next;
6290 break;
6291 }
6292 } while (tmp != NULL);
6293 }
6294 return(ret);
6295}
6296
6297/**
6298 * xmlXPathStringHash:
6299 * @string: a string
6300 *
6301 * Function computing the beginning of the string value of the node,
6302 * used to speed up comparisons
6303 *
6304 * Returns an int usable as a hash
6305 */
6306static unsigned int
6307xmlXPathStringHash(const xmlChar * string) {
6308 if (string == NULL)
6309 return((unsigned int) 0);
6310 if (string[0] == 0)
6311 return(0);
6312 return(((unsigned int) string[0]) +
6313 (((unsigned int) string[1]) << 8));
6314}
6315
6316/**
Owen Taylor3473f882001-02-23 17:55:21 +00006317 * xmlXPathCompareNodeSetFloat:
6318 * @ctxt: the XPath Parser context
6319 * @inf: less than (1) or greater than (0)
6320 * @strict: is the comparison strict
6321 * @arg: the node set
6322 * @f: the value
6323 *
6324 * Implement the compare operation between a nodeset and a number
6325 * @ns < @val (1, 1, ...
6326 * @ns <= @val (1, 0, ...
6327 * @ns > @val (0, 1, ...
6328 * @ns >= @val (0, 0, ...
6329 *
6330 * If one object to be compared is a node-set and the other is a number,
6331 * then the comparison will be true if and only if there is a node in the
6332 * node-set such that the result of performing the comparison on the number
6333 * to be compared and on the result of converting the string-value of that
6334 * node to a number using the number function is true.
6335 *
6336 * Returns 0 or 1 depending on the results of the test.
6337 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006338static int
Owen Taylor3473f882001-02-23 17:55:21 +00006339xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6340 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6341 int i, ret = 0;
6342 xmlNodeSetPtr ns;
6343 xmlChar *str2;
6344
6345 if ((f == NULL) || (arg == NULL) ||
6346 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006347 xmlXPathReleaseObject(ctxt->context, arg);
6348 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006349 return(0);
6350 }
6351 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006352 if (ns != NULL) {
6353 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006354 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006355 if (str2 != NULL) {
6356 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006357 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006358 xmlFree(str2);
6359 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006360 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006361 ret = xmlXPathCompareValues(ctxt, inf, strict);
6362 if (ret)
6363 break;
6364 }
6365 }
Owen Taylor3473f882001-02-23 17:55:21 +00006366 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006367 xmlXPathReleaseObject(ctxt->context, arg);
6368 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006369 return(ret);
6370}
6371
6372/**
6373 * xmlXPathCompareNodeSetString:
6374 * @ctxt: the XPath Parser context
6375 * @inf: less than (1) or greater than (0)
6376 * @strict: is the comparison strict
6377 * @arg: the node set
6378 * @s: the value
6379 *
6380 * Implement the compare operation between a nodeset and a string
6381 * @ns < @val (1, 1, ...
6382 * @ns <= @val (1, 0, ...
6383 * @ns > @val (0, 1, ...
6384 * @ns >= @val (0, 0, ...
6385 *
6386 * If one object to be compared is a node-set and the other is a string,
6387 * then the comparison will be true if and only if there is a node in
6388 * the node-set such that the result of performing the comparison on the
6389 * string-value of the node and the other string is true.
6390 *
6391 * Returns 0 or 1 depending on the results of the test.
6392 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006393static int
Owen Taylor3473f882001-02-23 17:55:21 +00006394xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6395 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6396 int i, ret = 0;
6397 xmlNodeSetPtr ns;
6398 xmlChar *str2;
6399
6400 if ((s == NULL) || (arg == NULL) ||
6401 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006402 xmlXPathReleaseObject(ctxt->context, arg);
6403 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006404 return(0);
6405 }
6406 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006407 if (ns != NULL) {
6408 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006409 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006410 if (str2 != NULL) {
6411 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006412 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006413 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006414 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006415 ret = xmlXPathCompareValues(ctxt, inf, strict);
6416 if (ret)
6417 break;
6418 }
6419 }
Owen Taylor3473f882001-02-23 17:55:21 +00006420 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006421 xmlXPathReleaseObject(ctxt->context, arg);
6422 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006423 return(ret);
6424}
6425
6426/**
6427 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006428 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006429 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006430 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006431 * @arg2: the second node set object
6432 *
6433 * Implement the compare operation on nodesets:
6434 *
6435 * If both objects to be compared are node-sets, then the comparison
6436 * will be true if and only if there is a node in the first node-set
6437 * and a node in the second node-set such that the result of performing
6438 * the comparison on the string-values of the two nodes is true.
6439 * ....
6440 * When neither object to be compared is a node-set and the operator
6441 * is <=, <, >= or >, then the objects are compared by converting both
6442 * objects to numbers and comparing the numbers according to IEEE 754.
6443 * ....
6444 * The number function converts its argument to a number as follows:
6445 * - a string that consists of optional whitespace followed by an
6446 * optional minus sign followed by a Number followed by whitespace
6447 * is converted to the IEEE 754 number that is nearest (according
6448 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6449 * represented by the string; any other string is converted to NaN
6450 *
6451 * Conclusion all nodes need to be converted first to their string value
6452 * and then the comparison must be done when possible
6453 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006454static int
6455xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006456 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6457 int i, j, init = 0;
6458 double val1;
6459 double *values2;
6460 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006461 xmlNodeSetPtr ns1;
6462 xmlNodeSetPtr ns2;
6463
6464 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006465 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6466 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006467 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006468 }
Owen Taylor3473f882001-02-23 17:55:21 +00006469 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006470 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6471 xmlXPathFreeObject(arg1);
6472 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006473 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006474 }
Owen Taylor3473f882001-02-23 17:55:21 +00006475
6476 ns1 = arg1->nodesetval;
6477 ns2 = arg2->nodesetval;
6478
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006479 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006480 xmlXPathFreeObject(arg1);
6481 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006482 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006483 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006484 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006485 xmlXPathFreeObject(arg1);
6486 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006487 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006488 }
Owen Taylor3473f882001-02-23 17:55:21 +00006489
6490 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6491 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006492 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006493 xmlXPathFreeObject(arg1);
6494 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006495 return(0);
6496 }
6497 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006498 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006499 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006500 continue;
6501 for (j = 0;j < ns2->nodeNr;j++) {
6502 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006503 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006504 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006505 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006506 continue;
6507 if (inf && strict)
6508 ret = (val1 < values2[j]);
6509 else if (inf && !strict)
6510 ret = (val1 <= values2[j]);
6511 else if (!inf && strict)
6512 ret = (val1 > values2[j]);
6513 else if (!inf && !strict)
6514 ret = (val1 >= values2[j]);
6515 if (ret)
6516 break;
6517 }
6518 if (ret)
6519 break;
6520 init = 1;
6521 }
6522 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006523 xmlXPathFreeObject(arg1);
6524 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006525 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006526}
6527
6528/**
6529 * xmlXPathCompareNodeSetValue:
6530 * @ctxt: the XPath Parser context
6531 * @inf: less than (1) or greater than (0)
6532 * @strict: is the comparison strict
6533 * @arg: the node set
6534 * @val: the value
6535 *
6536 * Implement the compare operation between a nodeset and a value
6537 * @ns < @val (1, 1, ...
6538 * @ns <= @val (1, 0, ...
6539 * @ns > @val (0, 1, ...
6540 * @ns >= @val (0, 0, ...
6541 *
6542 * If one object to be compared is a node-set and the other is a boolean,
6543 * then the comparison will be true if and only if the result of performing
6544 * the comparison on the boolean and on the result of converting
6545 * the node-set to a boolean using the boolean function is true.
6546 *
6547 * Returns 0 or 1 depending on the results of the test.
6548 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006549static int
Owen Taylor3473f882001-02-23 17:55:21 +00006550xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6551 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6552 if ((val == NULL) || (arg == NULL) ||
6553 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6554 return(0);
6555
6556 switch(val->type) {
6557 case XPATH_NUMBER:
6558 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6559 case XPATH_NODESET:
6560 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006561 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006562 case XPATH_STRING:
6563 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6564 case XPATH_BOOLEAN:
6565 valuePush(ctxt, arg);
6566 xmlXPathBooleanFunction(ctxt, 1);
6567 valuePush(ctxt, val);
6568 return(xmlXPathCompareValues(ctxt, inf, strict));
6569 default:
6570 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006571 }
6572 return(0);
6573}
6574
6575/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006576 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006577 * @arg: the nodeset object argument
6578 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006579 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006580 *
6581 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6582 * If one object to be compared is a node-set and the other is a string,
6583 * then the comparison will be true if and only if there is a node in
6584 * the node-set such that the result of performing the comparison on the
6585 * string-value of the node and the other string is true.
6586 *
6587 * Returns 0 or 1 depending on the results of the test.
6588 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006589static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006590xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006591{
Owen Taylor3473f882001-02-23 17:55:21 +00006592 int i;
6593 xmlNodeSetPtr ns;
6594 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006595 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006596
6597 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006598 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6599 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006600 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006601 /*
6602 * A NULL nodeset compared with a string is always false
6603 * (since there is no node equal, and no node not equal)
6604 */
6605 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006606 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006607 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006608 for (i = 0; i < ns->nodeNr; i++) {
6609 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6610 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6611 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6612 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006613 if (neq)
6614 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006615 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006616 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6617 if (neq)
6618 continue;
6619 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006620 } else if (neq) {
6621 if (str2 != NULL)
6622 xmlFree(str2);
6623 return (1);
6624 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006625 if (str2 != NULL)
6626 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006627 } else if (neq)
6628 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006629 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006630 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006631}
6632
6633/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006634 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006635 * @arg: the nodeset object argument
6636 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006637 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006638 *
6639 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6640 * If one object to be compared is a node-set and the other is a number,
6641 * then the comparison will be true if and only if there is a node in
6642 * the node-set such that the result of performing the comparison on the
6643 * number to be compared and on the result of converting the string-value
6644 * of that node to a number using the number function is true.
6645 *
6646 * Returns 0 or 1 depending on the results of the test.
6647 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006648static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006649xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6650 xmlXPathObjectPtr arg, double f, int neq) {
6651 int i, ret=0;
6652 xmlNodeSetPtr ns;
6653 xmlChar *str2;
6654 xmlXPathObjectPtr val;
6655 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006656
6657 if ((arg == NULL) ||
6658 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6659 return(0);
6660
William M. Brack0c022ad2002-07-12 00:56:01 +00006661 ns = arg->nodesetval;
6662 if (ns != NULL) {
6663 for (i=0;i<ns->nodeNr;i++) {
6664 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6665 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006666 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006667 xmlFree(str2);
6668 xmlXPathNumberFunction(ctxt, 1);
6669 val = valuePop(ctxt);
6670 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006671 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006672 if (!xmlXPathIsNaN(v)) {
6673 if ((!neq) && (v==f)) {
6674 ret = 1;
6675 break;
6676 } else if ((neq) && (v!=f)) {
6677 ret = 1;
6678 break;
6679 }
William M. Brack32f0f712005-07-14 07:00:33 +00006680 } else { /* NaN is unequal to any value */
6681 if (neq)
6682 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006683 }
6684 }
6685 }
6686 }
6687
6688 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006689}
6690
6691
6692/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006693 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006694 * @arg1: first nodeset object argument
6695 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006696 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006697 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006698 * Implement the equal / not equal operation on XPath nodesets:
6699 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006700 * If both objects to be compared are node-sets, then the comparison
6701 * will be true if and only if there is a node in the first node-set and
6702 * a node in the second node-set such that the result of performing the
6703 * comparison on the string-values of the two nodes is true.
6704 *
6705 * (needless to say, this is a costly operation)
6706 *
6707 * Returns 0 or 1 depending on the results of the test.
6708 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006709static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006710xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006711 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006712 unsigned int *hashs1;
6713 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006714 xmlChar **values1;
6715 xmlChar **values2;
6716 int ret = 0;
6717 xmlNodeSetPtr ns1;
6718 xmlNodeSetPtr ns2;
6719
6720 if ((arg1 == NULL) ||
6721 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6722 return(0);
6723 if ((arg2 == NULL) ||
6724 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6725 return(0);
6726
6727 ns1 = arg1->nodesetval;
6728 ns2 = arg2->nodesetval;
6729
Daniel Veillard911f49a2001-04-07 15:39:35 +00006730 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006731 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006732 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006733 return(0);
6734
6735 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006736 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006737 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006738 if (neq == 0)
6739 for (i = 0;i < ns1->nodeNr;i++)
6740 for (j = 0;j < ns2->nodeNr;j++)
6741 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6742 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006743
6744 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006745 if (values1 == NULL) {
6746 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006747 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006748 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006749 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6750 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006751 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006752 xmlFree(values1);
6753 return(0);
6754 }
Owen Taylor3473f882001-02-23 17:55:21 +00006755 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6756 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6757 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006758 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006759 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006760 xmlFree(values1);
6761 return(0);
6762 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006763 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6764 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006765 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006766 xmlFree(hashs1);
6767 xmlFree(values1);
6768 xmlFree(values2);
6769 return(0);
6770 }
Owen Taylor3473f882001-02-23 17:55:21 +00006771 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6772 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006773 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006774 for (j = 0;j < ns2->nodeNr;j++) {
6775 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006776 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006777 if (hashs1[i] != hashs2[j]) {
6778 if (neq) {
6779 ret = 1;
6780 break;
6781 }
6782 }
6783 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006784 if (values1[i] == NULL)
6785 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6786 if (values2[j] == NULL)
6787 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006788 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006789 if (ret)
6790 break;
6791 }
Owen Taylor3473f882001-02-23 17:55:21 +00006792 }
6793 if (ret)
6794 break;
6795 }
6796 for (i = 0;i < ns1->nodeNr;i++)
6797 if (values1[i] != NULL)
6798 xmlFree(values1[i]);
6799 for (j = 0;j < ns2->nodeNr;j++)
6800 if (values2[j] != NULL)
6801 xmlFree(values2[j]);
6802 xmlFree(values1);
6803 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006804 xmlFree(hashs1);
6805 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006806 return(ret);
6807}
6808
William M. Brack0c022ad2002-07-12 00:56:01 +00006809static int
6810xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6811 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006812 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006813 /*
6814 *At this point we are assured neither arg1 nor arg2
6815 *is a nodeset, so we can just pick the appropriate routine.
6816 */
Owen Taylor3473f882001-02-23 17:55:21 +00006817 switch (arg1->type) {
6818 case XPATH_UNDEFINED:
6819#ifdef DEBUG_EXPR
6820 xmlGenericError(xmlGenericErrorContext,
6821 "Equal: undefined\n");
6822#endif
6823 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006824 case XPATH_BOOLEAN:
6825 switch (arg2->type) {
6826 case XPATH_UNDEFINED:
6827#ifdef DEBUG_EXPR
6828 xmlGenericError(xmlGenericErrorContext,
6829 "Equal: undefined\n");
6830#endif
6831 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006832 case XPATH_BOOLEAN:
6833#ifdef DEBUG_EXPR
6834 xmlGenericError(xmlGenericErrorContext,
6835 "Equal: %d boolean %d \n",
6836 arg1->boolval, arg2->boolval);
6837#endif
6838 ret = (arg1->boolval == arg2->boolval);
6839 break;
6840 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006841 ret = (arg1->boolval ==
6842 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006843 break;
6844 case XPATH_STRING:
6845 if ((arg2->stringval == NULL) ||
6846 (arg2->stringval[0] == 0)) ret = 0;
6847 else
6848 ret = 1;
6849 ret = (arg1->boolval == ret);
6850 break;
6851 case XPATH_USERS:
6852 case XPATH_POINT:
6853 case XPATH_RANGE:
6854 case XPATH_LOCATIONSET:
6855 TODO
6856 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006857 case XPATH_NODESET:
6858 case XPATH_XSLT_TREE:
6859 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006860 }
6861 break;
6862 case XPATH_NUMBER:
6863 switch (arg2->type) {
6864 case XPATH_UNDEFINED:
6865#ifdef DEBUG_EXPR
6866 xmlGenericError(xmlGenericErrorContext,
6867 "Equal: undefined\n");
6868#endif
6869 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006870 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006871 ret = (arg2->boolval==
6872 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006873 break;
6874 case XPATH_STRING:
6875 valuePush(ctxt, arg2);
6876 xmlXPathNumberFunction(ctxt, 1);
6877 arg2 = valuePop(ctxt);
6878 /* no break on purpose */
6879 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006880 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006881 if (xmlXPathIsNaN(arg1->floatval) ||
6882 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006883 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006884 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6885 if (xmlXPathIsInf(arg2->floatval) == 1)
6886 ret = 1;
6887 else
6888 ret = 0;
6889 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6890 if (xmlXPathIsInf(arg2->floatval) == -1)
6891 ret = 1;
6892 else
6893 ret = 0;
6894 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6895 if (xmlXPathIsInf(arg1->floatval) == 1)
6896 ret = 1;
6897 else
6898 ret = 0;
6899 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6900 if (xmlXPathIsInf(arg1->floatval) == -1)
6901 ret = 1;
6902 else
6903 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006904 } else {
6905 ret = (arg1->floatval == arg2->floatval);
6906 }
Owen Taylor3473f882001-02-23 17:55:21 +00006907 break;
6908 case XPATH_USERS:
6909 case XPATH_POINT:
6910 case XPATH_RANGE:
6911 case XPATH_LOCATIONSET:
6912 TODO
6913 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006914 case XPATH_NODESET:
6915 case XPATH_XSLT_TREE:
6916 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006917 }
6918 break;
6919 case XPATH_STRING:
6920 switch (arg2->type) {
6921 case XPATH_UNDEFINED:
6922#ifdef DEBUG_EXPR
6923 xmlGenericError(xmlGenericErrorContext,
6924 "Equal: undefined\n");
6925#endif
6926 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006927 case XPATH_BOOLEAN:
6928 if ((arg1->stringval == NULL) ||
6929 (arg1->stringval[0] == 0)) ret = 0;
6930 else
6931 ret = 1;
6932 ret = (arg2->boolval == ret);
6933 break;
6934 case XPATH_STRING:
6935 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6936 break;
6937 case XPATH_NUMBER:
6938 valuePush(ctxt, arg1);
6939 xmlXPathNumberFunction(ctxt, 1);
6940 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006941 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006942 if (xmlXPathIsNaN(arg1->floatval) ||
6943 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006944 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006945 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6946 if (xmlXPathIsInf(arg2->floatval) == 1)
6947 ret = 1;
6948 else
6949 ret = 0;
6950 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6951 if (xmlXPathIsInf(arg2->floatval) == -1)
6952 ret = 1;
6953 else
6954 ret = 0;
6955 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6956 if (xmlXPathIsInf(arg1->floatval) == 1)
6957 ret = 1;
6958 else
6959 ret = 0;
6960 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6961 if (xmlXPathIsInf(arg1->floatval) == -1)
6962 ret = 1;
6963 else
6964 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006965 } else {
6966 ret = (arg1->floatval == arg2->floatval);
6967 }
Owen Taylor3473f882001-02-23 17:55:21 +00006968 break;
6969 case XPATH_USERS:
6970 case XPATH_POINT:
6971 case XPATH_RANGE:
6972 case XPATH_LOCATIONSET:
6973 TODO
6974 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006975 case XPATH_NODESET:
6976 case XPATH_XSLT_TREE:
6977 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006978 }
6979 break;
6980 case XPATH_USERS:
6981 case XPATH_POINT:
6982 case XPATH_RANGE:
6983 case XPATH_LOCATIONSET:
6984 TODO
6985 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006986 case XPATH_NODESET:
6987 case XPATH_XSLT_TREE:
6988 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006989 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006990 xmlXPathReleaseObject(ctxt->context, arg1);
6991 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006992 return(ret);
6993}
6994
William M. Brack0c022ad2002-07-12 00:56:01 +00006995/**
6996 * xmlXPathEqualValues:
6997 * @ctxt: the XPath Parser context
6998 *
6999 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7000 *
7001 * Returns 0 or 1 depending on the results of the test.
7002 */
7003int
7004xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7005 xmlXPathObjectPtr arg1, arg2, argtmp;
7006 int ret = 0;
7007
Daniel Veillard6128c012004-11-08 17:16:15 +00007008 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007009 arg2 = valuePop(ctxt);
7010 arg1 = valuePop(ctxt);
7011 if ((arg1 == NULL) || (arg2 == NULL)) {
7012 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007013 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007014 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007015 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007016 XP_ERROR0(XPATH_INVALID_OPERAND);
7017 }
7018
7019 if (arg1 == arg2) {
7020#ifdef DEBUG_EXPR
7021 xmlGenericError(xmlGenericErrorContext,
7022 "Equal: by pointer\n");
7023#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007024 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007025 return(1);
7026 }
7027
7028 /*
7029 *If either argument is a nodeset, it's a 'special case'
7030 */
7031 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7032 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7033 /*
7034 *Hack it to assure arg1 is the nodeset
7035 */
7036 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7037 argtmp = arg2;
7038 arg2 = arg1;
7039 arg1 = argtmp;
7040 }
7041 switch (arg2->type) {
7042 case XPATH_UNDEFINED:
7043#ifdef DEBUG_EXPR
7044 xmlGenericError(xmlGenericErrorContext,
7045 "Equal: undefined\n");
7046#endif
7047 break;
7048 case XPATH_NODESET:
7049 case XPATH_XSLT_TREE:
7050 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7051 break;
7052 case XPATH_BOOLEAN:
7053 if ((arg1->nodesetval == NULL) ||
7054 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7055 else
7056 ret = 1;
7057 ret = (ret == arg2->boolval);
7058 break;
7059 case XPATH_NUMBER:
7060 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7061 break;
7062 case XPATH_STRING:
7063 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7064 break;
7065 case XPATH_USERS:
7066 case XPATH_POINT:
7067 case XPATH_RANGE:
7068 case XPATH_LOCATIONSET:
7069 TODO
7070 break;
7071 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007072 xmlXPathReleaseObject(ctxt->context, arg1);
7073 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007074 return(ret);
7075 }
7076
7077 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7078}
7079
7080/**
7081 * xmlXPathNotEqualValues:
7082 * @ctxt: the XPath Parser context
7083 *
7084 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7085 *
7086 * Returns 0 or 1 depending on the results of the test.
7087 */
7088int
7089xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7090 xmlXPathObjectPtr arg1, arg2, argtmp;
7091 int ret = 0;
7092
Daniel Veillard6128c012004-11-08 17:16:15 +00007093 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007094 arg2 = valuePop(ctxt);
7095 arg1 = valuePop(ctxt);
7096 if ((arg1 == NULL) || (arg2 == NULL)) {
7097 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007098 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007099 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007100 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007101 XP_ERROR0(XPATH_INVALID_OPERAND);
7102 }
7103
7104 if (arg1 == arg2) {
7105#ifdef DEBUG_EXPR
7106 xmlGenericError(xmlGenericErrorContext,
7107 "NotEqual: by pointer\n");
7108#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007109 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007110 return(0);
7111 }
7112
7113 /*
7114 *If either argument is a nodeset, it's a 'special case'
7115 */
7116 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7117 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7118 /*
7119 *Hack it to assure arg1 is the nodeset
7120 */
7121 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7122 argtmp = arg2;
7123 arg2 = arg1;
7124 arg1 = argtmp;
7125 }
7126 switch (arg2->type) {
7127 case XPATH_UNDEFINED:
7128#ifdef DEBUG_EXPR
7129 xmlGenericError(xmlGenericErrorContext,
7130 "NotEqual: undefined\n");
7131#endif
7132 break;
7133 case XPATH_NODESET:
7134 case XPATH_XSLT_TREE:
7135 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7136 break;
7137 case XPATH_BOOLEAN:
7138 if ((arg1->nodesetval == NULL) ||
7139 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7140 else
7141 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007142 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007143 break;
7144 case XPATH_NUMBER:
7145 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7146 break;
7147 case XPATH_STRING:
7148 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7149 break;
7150 case XPATH_USERS:
7151 case XPATH_POINT:
7152 case XPATH_RANGE:
7153 case XPATH_LOCATIONSET:
7154 TODO
7155 break;
7156 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007157 xmlXPathReleaseObject(ctxt->context, arg1);
7158 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007159 return(ret);
7160 }
7161
7162 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7163}
Owen Taylor3473f882001-02-23 17:55:21 +00007164
7165/**
7166 * xmlXPathCompareValues:
7167 * @ctxt: the XPath Parser context
7168 * @inf: less than (1) or greater than (0)
7169 * @strict: is the comparison strict
7170 *
7171 * Implement the compare operation on XPath objects:
7172 * @arg1 < @arg2 (1, 1, ...
7173 * @arg1 <= @arg2 (1, 0, ...
7174 * @arg1 > @arg2 (0, 1, ...
7175 * @arg1 >= @arg2 (0, 0, ...
7176 *
7177 * When neither object to be compared is a node-set and the operator is
7178 * <=, <, >=, >, then the objects are compared by converted both objects
7179 * to numbers and comparing the numbers according to IEEE 754. The <
7180 * comparison will be true if and only if the first number is less than the
7181 * second number. The <= comparison will be true if and only if the first
7182 * number is less than or equal to the second number. The > comparison
7183 * will be true if and only if the first number is greater than the second
7184 * number. The >= comparison will be true if and only if the first number
7185 * is greater than or equal to the second number.
7186 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007187 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007188 */
7189int
7190xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007191 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007192 xmlXPathObjectPtr arg1, arg2;
7193
Daniel Veillard6128c012004-11-08 17:16:15 +00007194 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007195 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007196 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007197 if ((arg1 == NULL) || (arg2 == NULL)) {
7198 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007199 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007200 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007201 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007202 XP_ERROR0(XPATH_INVALID_OPERAND);
7203 }
7204
William M. Brack0c022ad2002-07-12 00:56:01 +00007205 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7206 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007207 /*
7208 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7209 * are not freed from within this routine; they will be freed from the
7210 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7211 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007212 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7213 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007214 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007215 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007216 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007217 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7218 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007219 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007220 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7221 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007222 }
7223 }
7224 return(ret);
7225 }
7226
7227 if (arg1->type != XPATH_NUMBER) {
7228 valuePush(ctxt, arg1);
7229 xmlXPathNumberFunction(ctxt, 1);
7230 arg1 = valuePop(ctxt);
7231 }
7232 if (arg1->type != XPATH_NUMBER) {
7233 xmlXPathFreeObject(arg1);
7234 xmlXPathFreeObject(arg2);
7235 XP_ERROR0(XPATH_INVALID_OPERAND);
7236 }
7237 if (arg2->type != XPATH_NUMBER) {
7238 valuePush(ctxt, arg2);
7239 xmlXPathNumberFunction(ctxt, 1);
7240 arg2 = valuePop(ctxt);
7241 }
7242 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007243 xmlXPathReleaseObject(ctxt->context, arg1);
7244 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007245 XP_ERROR0(XPATH_INVALID_OPERAND);
7246 }
7247 /*
7248 * Add tests for infinity and nan
7249 * => feedback on 3.4 for Inf and NaN
7250 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007251 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007252 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007253 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007254 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007255 arg1i=xmlXPathIsInf(arg1->floatval);
7256 arg2i=xmlXPathIsInf(arg2->floatval);
7257 if (inf && strict) {
7258 if ((arg1i == -1 && arg2i != -1) ||
7259 (arg2i == 1 && arg1i != 1)) {
7260 ret = 1;
7261 } else if (arg1i == 0 && arg2i == 0) {
7262 ret = (arg1->floatval < arg2->floatval);
7263 } else {
7264 ret = 0;
7265 }
7266 }
7267 else if (inf && !strict) {
7268 if (arg1i == -1 || arg2i == 1) {
7269 ret = 1;
7270 } else if (arg1i == 0 && arg2i == 0) {
7271 ret = (arg1->floatval <= arg2->floatval);
7272 } else {
7273 ret = 0;
7274 }
7275 }
7276 else if (!inf && strict) {
7277 if ((arg1i == 1 && arg2i != 1) ||
7278 (arg2i == -1 && arg1i != -1)) {
7279 ret = 1;
7280 } else if (arg1i == 0 && arg2i == 0) {
7281 ret = (arg1->floatval > arg2->floatval);
7282 } else {
7283 ret = 0;
7284 }
7285 }
7286 else if (!inf && !strict) {
7287 if (arg1i == 1 || arg2i == -1) {
7288 ret = 1;
7289 } else if (arg1i == 0 && arg2i == 0) {
7290 ret = (arg1->floatval >= arg2->floatval);
7291 } else {
7292 ret = 0;
7293 }
7294 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007295 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007296 xmlXPathReleaseObject(ctxt->context, arg1);
7297 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007298 return(ret);
7299}
7300
7301/**
7302 * xmlXPathValueFlipSign:
7303 * @ctxt: the XPath Parser context
7304 *
7305 * Implement the unary - operation on an XPath object
7306 * The numeric operators convert their operands to numbers as if
7307 * by calling the number function.
7308 */
7309void
7310xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007311 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007312 CAST_TO_NUMBER;
7313 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007314 if (xmlXPathIsNaN(ctxt->value->floatval))
7315 ctxt->value->floatval=xmlXPathNAN;
7316 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7317 ctxt->value->floatval=xmlXPathNINF;
7318 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7319 ctxt->value->floatval=xmlXPathPINF;
7320 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007321 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7322 ctxt->value->floatval = xmlXPathNZERO;
7323 else
7324 ctxt->value->floatval = 0;
7325 }
7326 else
7327 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007328}
7329
7330/**
7331 * xmlXPathAddValues:
7332 * @ctxt: the XPath Parser context
7333 *
7334 * Implement the add operation on XPath objects:
7335 * The numeric operators convert their operands to numbers as if
7336 * by calling the number function.
7337 */
7338void
7339xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7340 xmlXPathObjectPtr arg;
7341 double val;
7342
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007343 arg = valuePop(ctxt);
7344 if (arg == NULL)
7345 XP_ERROR(XPATH_INVALID_OPERAND);
7346 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007347 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007348 CAST_TO_NUMBER;
7349 CHECK_TYPE(XPATH_NUMBER);
7350 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007351}
7352
7353/**
7354 * xmlXPathSubValues:
7355 * @ctxt: the XPath Parser context
7356 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007357 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007358 * The numeric operators convert their operands to numbers as if
7359 * by calling the number function.
7360 */
7361void
7362xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7363 xmlXPathObjectPtr arg;
7364 double val;
7365
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007366 arg = valuePop(ctxt);
7367 if (arg == NULL)
7368 XP_ERROR(XPATH_INVALID_OPERAND);
7369 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007370 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007371 CAST_TO_NUMBER;
7372 CHECK_TYPE(XPATH_NUMBER);
7373 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007374}
7375
7376/**
7377 * xmlXPathMultValues:
7378 * @ctxt: the XPath Parser context
7379 *
7380 * Implement the multiply operation on XPath objects:
7381 * The numeric operators convert their operands to numbers as if
7382 * by calling the number function.
7383 */
7384void
7385xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7386 xmlXPathObjectPtr arg;
7387 double val;
7388
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007389 arg = valuePop(ctxt);
7390 if (arg == NULL)
7391 XP_ERROR(XPATH_INVALID_OPERAND);
7392 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007393 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007394 CAST_TO_NUMBER;
7395 CHECK_TYPE(XPATH_NUMBER);
7396 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007397}
7398
7399/**
7400 * xmlXPathDivValues:
7401 * @ctxt: the XPath Parser context
7402 *
7403 * Implement the div operation on XPath objects @arg1 / @arg2:
7404 * The numeric operators convert their operands to numbers as if
7405 * by calling the number function.
7406 */
7407void
7408xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7409 xmlXPathObjectPtr arg;
7410 double val;
7411
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007412 arg = valuePop(ctxt);
7413 if (arg == NULL)
7414 XP_ERROR(XPATH_INVALID_OPERAND);
7415 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007416 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007417 CAST_TO_NUMBER;
7418 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007419 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7420 ctxt->value->floatval = xmlXPathNAN;
7421 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007422 if (ctxt->value->floatval == 0)
7423 ctxt->value->floatval = xmlXPathNAN;
7424 else if (ctxt->value->floatval > 0)
7425 ctxt->value->floatval = xmlXPathNINF;
7426 else if (ctxt->value->floatval < 0)
7427 ctxt->value->floatval = xmlXPathPINF;
7428 }
7429 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007430 if (ctxt->value->floatval == 0)
7431 ctxt->value->floatval = xmlXPathNAN;
7432 else if (ctxt->value->floatval > 0)
7433 ctxt->value->floatval = xmlXPathPINF;
7434 else if (ctxt->value->floatval < 0)
7435 ctxt->value->floatval = xmlXPathNINF;
7436 } else
7437 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007438}
7439
7440/**
7441 * xmlXPathModValues:
7442 * @ctxt: the XPath Parser context
7443 *
7444 * Implement the mod operation on XPath objects: @arg1 / @arg2
7445 * The numeric operators convert their operands to numbers as if
7446 * by calling the number function.
7447 */
7448void
7449xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7450 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007451 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007452
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007453 arg = valuePop(ctxt);
7454 if (arg == NULL)
7455 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007456 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007457 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007458 CAST_TO_NUMBER;
7459 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007460 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007461 if (arg2 == 0)
7462 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007463 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007464 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007465 }
Owen Taylor3473f882001-02-23 17:55:21 +00007466}
7467
7468/************************************************************************
7469 * *
7470 * The traversal functions *
7471 * *
7472 ************************************************************************/
7473
Owen Taylor3473f882001-02-23 17:55:21 +00007474/*
7475 * A traversal function enumerates nodes along an axis.
7476 * Initially it must be called with NULL, and it indicates
7477 * termination on the axis by returning NULL.
7478 */
7479typedef xmlNodePtr (*xmlXPathTraversalFunction)
7480 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7481
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007482/*
7483 * xmlXPathTraversalFunctionExt:
7484 * A traversal function enumerates nodes along an axis.
7485 * Initially it must be called with NULL, and it indicates
7486 * termination on the axis by returning NULL.
7487 * The context node of the traversal is specified via @contextNode.
7488 */
7489typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7490 (xmlNodePtr cur, xmlNodePtr contextNode);
7491
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007492/*
7493 * xmlXPathNodeSetMergeFunction:
7494 * Used for merging node sets in xmlXPathCollectAndTest().
7495 */
7496typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7497 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7498
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007499
Owen Taylor3473f882001-02-23 17:55:21 +00007500/**
7501 * xmlXPathNextSelf:
7502 * @ctxt: the XPath Parser context
7503 * @cur: the current node in the traversal
7504 *
7505 * Traversal function for the "self" direction
7506 * The self axis contains just the context node itself
7507 *
7508 * Returns the next element following that axis
7509 */
7510xmlNodePtr
7511xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007512 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007513 if (cur == NULL)
7514 return(ctxt->context->node);
7515 return(NULL);
7516}
7517
7518/**
7519 * xmlXPathNextChild:
7520 * @ctxt: the XPath Parser context
7521 * @cur: the current node in the traversal
7522 *
7523 * Traversal function for the "child" direction
7524 * The child axis contains the children of the context node in document order.
7525 *
7526 * Returns the next element following that axis
7527 */
7528xmlNodePtr
7529xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007530 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007531 if (cur == NULL) {
7532 if (ctxt->context->node == NULL) return(NULL);
7533 switch (ctxt->context->node->type) {
7534 case XML_ELEMENT_NODE:
7535 case XML_TEXT_NODE:
7536 case XML_CDATA_SECTION_NODE:
7537 case XML_ENTITY_REF_NODE:
7538 case XML_ENTITY_NODE:
7539 case XML_PI_NODE:
7540 case XML_COMMENT_NODE:
7541 case XML_NOTATION_NODE:
7542 case XML_DTD_NODE:
7543 return(ctxt->context->node->children);
7544 case XML_DOCUMENT_NODE:
7545 case XML_DOCUMENT_TYPE_NODE:
7546 case XML_DOCUMENT_FRAG_NODE:
7547 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007548#ifdef LIBXML_DOCB_ENABLED
7549 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007550#endif
7551 return(((xmlDocPtr) ctxt->context->node)->children);
7552 case XML_ELEMENT_DECL:
7553 case XML_ATTRIBUTE_DECL:
7554 case XML_ENTITY_DECL:
7555 case XML_ATTRIBUTE_NODE:
7556 case XML_NAMESPACE_DECL:
7557 case XML_XINCLUDE_START:
7558 case XML_XINCLUDE_END:
7559 return(NULL);
7560 }
7561 return(NULL);
7562 }
7563 if ((cur->type == XML_DOCUMENT_NODE) ||
7564 (cur->type == XML_HTML_DOCUMENT_NODE))
7565 return(NULL);
7566 return(cur->next);
7567}
7568
7569/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007570 * xmlXPathNextChildElement:
7571 * @ctxt: the XPath Parser context
7572 * @cur: the current node in the traversal
7573 *
7574 * Traversal function for the "child" direction and nodes of type element.
7575 * The child axis contains the children of the context node in document order.
7576 *
7577 * Returns the next element following that axis
7578 */
7579static xmlNodePtr
7580xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7581 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7582 if (cur == NULL) {
7583 cur = ctxt->context->node;
7584 if (cur == NULL) return(NULL);
7585 /*
7586 * Get the first element child.
7587 */
7588 switch (cur->type) {
7589 case XML_ELEMENT_NODE:
7590 case XML_DOCUMENT_FRAG_NODE:
7591 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7592 case XML_ENTITY_NODE:
7593 cur = cur->children;
7594 if (cur != NULL) {
7595 if (cur->type == XML_ELEMENT_NODE)
7596 return(cur);
7597 do {
7598 cur = cur->next;
7599 } while ((cur != NULL) &&
7600 (cur->type != XML_ELEMENT_NODE));
7601 return(cur);
7602 }
7603 return(NULL);
7604 case XML_DOCUMENT_NODE:
7605 case XML_HTML_DOCUMENT_NODE:
7606#ifdef LIBXML_DOCB_ENABLED
7607 case XML_DOCB_DOCUMENT_NODE:
7608#endif
7609 return(xmlDocGetRootElement((xmlDocPtr) cur));
7610 default:
7611 return(NULL);
7612 }
7613 return(NULL);
7614 }
7615 /*
7616 * Get the next sibling element node.
7617 */
7618 switch (cur->type) {
7619 case XML_ELEMENT_NODE:
7620 case XML_TEXT_NODE:
7621 case XML_ENTITY_REF_NODE:
7622 case XML_ENTITY_NODE:
7623 case XML_CDATA_SECTION_NODE:
7624 case XML_PI_NODE:
7625 case XML_COMMENT_NODE:
7626 case XML_XINCLUDE_END:
7627 break;
7628 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7629 default:
7630 return(NULL);
7631 }
7632 if (cur->next != NULL) {
7633 if (cur->next->type == XML_ELEMENT_NODE)
7634 return(cur->next);
7635 cur = cur->next;
7636 do {
7637 cur = cur->next;
7638 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7639 return(cur);
7640 }
7641 return(NULL);
7642}
7643
7644/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007645 * xmlXPathNextDescendantOrSelfElemParent:
7646 * @ctxt: the XPath Parser context
7647 * @cur: the current node in the traversal
7648 *
7649 * Traversal function for the "descendant-or-self" axis.
7650 * Additionally it returns only nodes which can be parents of
7651 * element nodes.
7652 *
7653 *
7654 * Returns the next element following that axis
7655 */
7656static xmlNodePtr
7657xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7658 xmlNodePtr contextNode)
7659{
7660 if (cur == NULL) {
7661 if (contextNode == NULL)
7662 return(NULL);
7663 switch (contextNode->type) {
7664 case XML_ELEMENT_NODE:
7665 case XML_XINCLUDE_START:
7666 case XML_DOCUMENT_FRAG_NODE:
7667 case XML_DOCUMENT_NODE:
7668#ifdef LIBXML_DOCB_ENABLED
7669 case XML_DOCB_DOCUMENT_NODE:
7670#endif
7671 case XML_HTML_DOCUMENT_NODE:
7672 return(contextNode);
7673 default:
7674 return(NULL);
7675 }
7676 return(NULL);
7677 } else {
7678 xmlNodePtr start = cur;
7679
7680 while (cur != NULL) {
7681 switch (cur->type) {
7682 case XML_ELEMENT_NODE:
7683 /* TODO: OK to have XInclude here? */
7684 case XML_XINCLUDE_START:
7685 case XML_DOCUMENT_FRAG_NODE:
7686 if (cur != start)
7687 return(cur);
7688 if (cur->children != NULL) {
7689 cur = cur->children;
7690 continue;
7691 }
7692 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007693 /* Not sure if we need those here. */
7694 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007695#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007696 case XML_DOCB_DOCUMENT_NODE:
7697#endif
7698 case XML_HTML_DOCUMENT_NODE:
7699 if (cur != start)
7700 return(cur);
7701 return(xmlDocGetRootElement((xmlDocPtr) cur));
7702 default:
7703 break;
7704 }
7705
7706next_sibling:
7707 if ((cur == NULL) || (cur == contextNode))
7708 return(NULL);
7709 if (cur->next != NULL) {
7710 cur = cur->next;
7711 } else {
7712 cur = cur->parent;
7713 goto next_sibling;
7714 }
7715 }
7716 }
7717 return(NULL);
7718}
7719
7720/**
Owen Taylor3473f882001-02-23 17:55:21 +00007721 * xmlXPathNextDescendant:
7722 * @ctxt: the XPath Parser context
7723 * @cur: the current node in the traversal
7724 *
7725 * Traversal function for the "descendant" direction
7726 * the descendant axis contains the descendants of the context node in document
7727 * order; a descendant is a child or a child of a child and so on.
7728 *
7729 * Returns the next element following that axis
7730 */
7731xmlNodePtr
7732xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007733 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007734 if (cur == NULL) {
7735 if (ctxt->context->node == NULL)
7736 return(NULL);
7737 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7738 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7739 return(NULL);
7740
7741 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7742 return(ctxt->context->doc->children);
7743 return(ctxt->context->node->children);
7744 }
7745
Daniel Veillard567e1b42001-08-01 15:53:47 +00007746 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007747 /*
7748 * Do not descend on entities declarations
7749 */
7750 if (cur->children->type != XML_ENTITY_DECL) {
7751 cur = cur->children;
7752 /*
7753 * Skip DTDs
7754 */
7755 if (cur->type != XML_DTD_NODE)
7756 return(cur);
7757 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007758 }
7759
7760 if (cur == ctxt->context->node) return(NULL);
7761
Daniel Veillard68e9e742002-11-16 15:35:11 +00007762 while (cur->next != NULL) {
7763 cur = cur->next;
7764 if ((cur->type != XML_ENTITY_DECL) &&
7765 (cur->type != XML_DTD_NODE))
7766 return(cur);
7767 }
Owen Taylor3473f882001-02-23 17:55:21 +00007768
7769 do {
7770 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007771 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007772 if (cur == ctxt->context->node) return(NULL);
7773 if (cur->next != NULL) {
7774 cur = cur->next;
7775 return(cur);
7776 }
7777 } while (cur != NULL);
7778 return(cur);
7779}
7780
7781/**
7782 * xmlXPathNextDescendantOrSelf:
7783 * @ctxt: the XPath Parser context
7784 * @cur: the current node in the traversal
7785 *
7786 * Traversal function for the "descendant-or-self" direction
7787 * the descendant-or-self axis contains the context node and the descendants
7788 * of the context node in document order; thus the context node is the first
7789 * node on the axis, and the first child of the context node is the second node
7790 * on the axis
7791 *
7792 * Returns the next element following that axis
7793 */
7794xmlNodePtr
7795xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007796 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007797 if (cur == NULL) {
7798 if (ctxt->context->node == NULL)
7799 return(NULL);
7800 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7801 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7802 return(NULL);
7803 return(ctxt->context->node);
7804 }
7805
7806 return(xmlXPathNextDescendant(ctxt, cur));
7807}
7808
7809/**
7810 * xmlXPathNextParent:
7811 * @ctxt: the XPath Parser context
7812 * @cur: the current node in the traversal
7813 *
7814 * Traversal function for the "parent" direction
7815 * The parent axis contains the parent of the context node, if there is one.
7816 *
7817 * Returns the next element following that axis
7818 */
7819xmlNodePtr
7820xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007821 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007822 /*
7823 * the parent of an attribute or namespace node is the element
7824 * to which the attribute or namespace node is attached
7825 * Namespace handling !!!
7826 */
7827 if (cur == NULL) {
7828 if (ctxt->context->node == NULL) return(NULL);
7829 switch (ctxt->context->node->type) {
7830 case XML_ELEMENT_NODE:
7831 case XML_TEXT_NODE:
7832 case XML_CDATA_SECTION_NODE:
7833 case XML_ENTITY_REF_NODE:
7834 case XML_ENTITY_NODE:
7835 case XML_PI_NODE:
7836 case XML_COMMENT_NODE:
7837 case XML_NOTATION_NODE:
7838 case XML_DTD_NODE:
7839 case XML_ELEMENT_DECL:
7840 case XML_ATTRIBUTE_DECL:
7841 case XML_XINCLUDE_START:
7842 case XML_XINCLUDE_END:
7843 case XML_ENTITY_DECL:
7844 if (ctxt->context->node->parent == NULL)
7845 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007846 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007847 ((ctxt->context->node->parent->name[0] == ' ') ||
7848 (xmlStrEqual(ctxt->context->node->parent->name,
7849 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007850 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007851 return(ctxt->context->node->parent);
7852 case XML_ATTRIBUTE_NODE: {
7853 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7854
7855 return(att->parent);
7856 }
7857 case XML_DOCUMENT_NODE:
7858 case XML_DOCUMENT_TYPE_NODE:
7859 case XML_DOCUMENT_FRAG_NODE:
7860 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007861#ifdef LIBXML_DOCB_ENABLED
7862 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007863#endif
7864 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007865 case XML_NAMESPACE_DECL: {
7866 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7867
7868 if ((ns->next != NULL) &&
7869 (ns->next->type != XML_NAMESPACE_DECL))
7870 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007872 }
Owen Taylor3473f882001-02-23 17:55:21 +00007873 }
7874 }
7875 return(NULL);
7876}
7877
7878/**
7879 * xmlXPathNextAncestor:
7880 * @ctxt: the XPath Parser context
7881 * @cur: the current node in the traversal
7882 *
7883 * Traversal function for the "ancestor" direction
7884 * the ancestor axis contains the ancestors of the context node; the ancestors
7885 * of the context node consist of the parent of context node and the parent's
7886 * parent and so on; the nodes are ordered in reverse document order; thus the
7887 * parent is the first node on the axis, and the parent's parent is the second
7888 * node on the axis
7889 *
7890 * Returns the next element following that axis
7891 */
7892xmlNodePtr
7893xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007894 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007895 /*
7896 * the parent of an attribute or namespace node is the element
7897 * to which the attribute or namespace node is attached
7898 * !!!!!!!!!!!!!
7899 */
7900 if (cur == NULL) {
7901 if (ctxt->context->node == NULL) return(NULL);
7902 switch (ctxt->context->node->type) {
7903 case XML_ELEMENT_NODE:
7904 case XML_TEXT_NODE:
7905 case XML_CDATA_SECTION_NODE:
7906 case XML_ENTITY_REF_NODE:
7907 case XML_ENTITY_NODE:
7908 case XML_PI_NODE:
7909 case XML_COMMENT_NODE:
7910 case XML_DTD_NODE:
7911 case XML_ELEMENT_DECL:
7912 case XML_ATTRIBUTE_DECL:
7913 case XML_ENTITY_DECL:
7914 case XML_NOTATION_NODE:
7915 case XML_XINCLUDE_START:
7916 case XML_XINCLUDE_END:
7917 if (ctxt->context->node->parent == NULL)
7918 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007919 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007920 ((ctxt->context->node->parent->name[0] == ' ') ||
7921 (xmlStrEqual(ctxt->context->node->parent->name,
7922 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007923 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007924 return(ctxt->context->node->parent);
7925 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007926 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007927
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007928 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007929 }
7930 case XML_DOCUMENT_NODE:
7931 case XML_DOCUMENT_TYPE_NODE:
7932 case XML_DOCUMENT_FRAG_NODE:
7933 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007934#ifdef LIBXML_DOCB_ENABLED
7935 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007936#endif
7937 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007938 case XML_NAMESPACE_DECL: {
7939 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7940
7941 if ((ns->next != NULL) &&
7942 (ns->next->type != XML_NAMESPACE_DECL))
7943 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007944 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007945 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007946 }
Owen Taylor3473f882001-02-23 17:55:21 +00007947 }
7948 return(NULL);
7949 }
7950 if (cur == ctxt->context->doc->children)
7951 return((xmlNodePtr) ctxt->context->doc);
7952 if (cur == (xmlNodePtr) ctxt->context->doc)
7953 return(NULL);
7954 switch (cur->type) {
7955 case XML_ELEMENT_NODE:
7956 case XML_TEXT_NODE:
7957 case XML_CDATA_SECTION_NODE:
7958 case XML_ENTITY_REF_NODE:
7959 case XML_ENTITY_NODE:
7960 case XML_PI_NODE:
7961 case XML_COMMENT_NODE:
7962 case XML_NOTATION_NODE:
7963 case XML_DTD_NODE:
7964 case XML_ELEMENT_DECL:
7965 case XML_ATTRIBUTE_DECL:
7966 case XML_ENTITY_DECL:
7967 case XML_XINCLUDE_START:
7968 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007969 if (cur->parent == NULL)
7970 return(NULL);
7971 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007972 ((cur->parent->name[0] == ' ') ||
7973 (xmlStrEqual(cur->parent->name,
7974 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007975 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007976 return(cur->parent);
7977 case XML_ATTRIBUTE_NODE: {
7978 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7979
7980 return(att->parent);
7981 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007982 case XML_NAMESPACE_DECL: {
7983 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7984
7985 if ((ns->next != NULL) &&
7986 (ns->next->type != XML_NAMESPACE_DECL))
7987 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007988 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007989 return(NULL);
7990 }
Owen Taylor3473f882001-02-23 17:55:21 +00007991 case XML_DOCUMENT_NODE:
7992 case XML_DOCUMENT_TYPE_NODE:
7993 case XML_DOCUMENT_FRAG_NODE:
7994 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007995#ifdef LIBXML_DOCB_ENABLED
7996 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007997#endif
7998 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007999 }
8000 return(NULL);
8001}
8002
8003/**
8004 * xmlXPathNextAncestorOrSelf:
8005 * @ctxt: the XPath Parser context
8006 * @cur: the current node in the traversal
8007 *
8008 * Traversal function for the "ancestor-or-self" direction
8009 * he ancestor-or-self axis contains the context node and ancestors of
8010 * the context node in reverse document order; thus the context node is
8011 * the first node on the axis, and the context node's parent the second;
8012 * parent here is defined the same as with the parent axis.
8013 *
8014 * Returns the next element following that axis
8015 */
8016xmlNodePtr
8017xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008018 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008019 if (cur == NULL)
8020 return(ctxt->context->node);
8021 return(xmlXPathNextAncestor(ctxt, cur));
8022}
8023
8024/**
8025 * xmlXPathNextFollowingSibling:
8026 * @ctxt: the XPath Parser context
8027 * @cur: the current node in the traversal
8028 *
8029 * Traversal function for the "following-sibling" direction
8030 * The following-sibling axis contains the following siblings of the context
8031 * node in document order.
8032 *
8033 * Returns the next element following that axis
8034 */
8035xmlNodePtr
8036xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008037 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008038 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8039 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8040 return(NULL);
8041 if (cur == (xmlNodePtr) ctxt->context->doc)
8042 return(NULL);
8043 if (cur == NULL)
8044 return(ctxt->context->node->next);
8045 return(cur->next);
8046}
8047
8048/**
8049 * xmlXPathNextPrecedingSibling:
8050 * @ctxt: the XPath Parser context
8051 * @cur: the current node in the traversal
8052 *
8053 * Traversal function for the "preceding-sibling" direction
8054 * The preceding-sibling axis contains the preceding siblings of the context
8055 * node in reverse document order; the first preceding sibling is first on the
8056 * axis; the sibling preceding that node is the second on the axis and so on.
8057 *
8058 * Returns the next element following that axis
8059 */
8060xmlNodePtr
8061xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008062 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008063 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8064 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8065 return(NULL);
8066 if (cur == (xmlNodePtr) ctxt->context->doc)
8067 return(NULL);
8068 if (cur == NULL)
8069 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008070 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8071 cur = cur->prev;
8072 if (cur == NULL)
8073 return(ctxt->context->node->prev);
8074 }
Owen Taylor3473f882001-02-23 17:55:21 +00008075 return(cur->prev);
8076}
8077
8078/**
8079 * xmlXPathNextFollowing:
8080 * @ctxt: the XPath Parser context
8081 * @cur: the current node in the traversal
8082 *
8083 * Traversal function for the "following" direction
8084 * The following axis contains all nodes in the same document as the context
8085 * node that are after the context node in document order, excluding any
8086 * descendants and excluding attribute nodes and namespace nodes; the nodes
8087 * are ordered in document order
8088 *
8089 * Returns the next element following that axis
8090 */
8091xmlNodePtr
8092xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008093 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008094 if (cur != NULL && cur->children != NULL)
8095 return cur->children ;
8096 if (cur == NULL) cur = ctxt->context->node;
8097 if (cur == NULL) return(NULL) ; /* ERROR */
8098 if (cur->next != NULL) return(cur->next) ;
8099 do {
8100 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008101 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008102 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8103 if (cur->next != NULL) return(cur->next);
8104 } while (cur != NULL);
8105 return(cur);
8106}
8107
8108/*
8109 * xmlXPathIsAncestor:
8110 * @ancestor: the ancestor node
8111 * @node: the current node
8112 *
8113 * Check that @ancestor is a @node's ancestor
8114 *
8115 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8116 */
8117static int
8118xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8119 if ((ancestor == NULL) || (node == NULL)) return(0);
8120 /* nodes need to be in the same document */
8121 if (ancestor->doc != node->doc) return(0);
8122 /* avoid searching if ancestor or node is the root node */
8123 if (ancestor == (xmlNodePtr) node->doc) return(1);
8124 if (node == (xmlNodePtr) ancestor->doc) return(0);
8125 while (node->parent != NULL) {
8126 if (node->parent == ancestor)
8127 return(1);
8128 node = node->parent;
8129 }
8130 return(0);
8131}
8132
8133/**
8134 * xmlXPathNextPreceding:
8135 * @ctxt: the XPath Parser context
8136 * @cur: the current node in the traversal
8137 *
8138 * Traversal function for the "preceding" direction
8139 * the preceding axis contains all nodes in the same document as the context
8140 * node that are before the context node in document order, excluding any
8141 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8142 * ordered in reverse document order
8143 *
8144 * Returns the next element following that axis
8145 */
8146xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008147xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8148{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008149 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008150 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008151 cur = ctxt->context->node;
8152 if (cur == NULL)
8153 return (NULL);
8154 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8155 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008156 do {
8157 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008158 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8159 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008160 }
8161
8162 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008163 if (cur == NULL)
8164 return (NULL);
8165 if (cur == ctxt->context->doc->children)
8166 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008167 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008168 return (cur);
8169}
8170
8171/**
8172 * xmlXPathNextPrecedingInternal:
8173 * @ctxt: the XPath Parser context
8174 * @cur: the current node in the traversal
8175 *
8176 * Traversal function for the "preceding" direction
8177 * the preceding axis contains all nodes in the same document as the context
8178 * node that are before the context node in document order, excluding any
8179 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8180 * ordered in reverse document order
8181 * This is a faster implementation but internal only since it requires a
8182 * state kept in the parser context: ctxt->ancestor.
8183 *
8184 * Returns the next element following that axis
8185 */
8186static xmlNodePtr
8187xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8188 xmlNodePtr cur)
8189{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008190 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008191 if (cur == NULL) {
8192 cur = ctxt->context->node;
8193 if (cur == NULL)
8194 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008195 if (cur->type == XML_NAMESPACE_DECL)
8196 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008197 ctxt->ancestor = cur->parent;
8198 }
8199 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8200 cur = cur->prev;
8201 while (cur->prev == NULL) {
8202 cur = cur->parent;
8203 if (cur == NULL)
8204 return (NULL);
8205 if (cur == ctxt->context->doc->children)
8206 return (NULL);
8207 if (cur != ctxt->ancestor)
8208 return (cur);
8209 ctxt->ancestor = cur->parent;
8210 }
8211 cur = cur->prev;
8212 while (cur->last != NULL)
8213 cur = cur->last;
8214 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008215}
8216
8217/**
8218 * xmlXPathNextNamespace:
8219 * @ctxt: the XPath Parser context
8220 * @cur: the current attribute in the traversal
8221 *
8222 * Traversal function for the "namespace" direction
8223 * the namespace axis contains the namespace nodes of the context node;
8224 * the order of nodes on this axis is implementation-defined; the axis will
8225 * be empty unless the context node is an element
8226 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008227 * We keep the XML namespace node at the end of the list.
8228 *
Owen Taylor3473f882001-02-23 17:55:21 +00008229 * Returns the next element following that axis
8230 */
8231xmlNodePtr
8232xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008233 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008234 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008235 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008236 if (ctxt->context->tmpNsList != NULL)
8237 xmlFree(ctxt->context->tmpNsList);
8238 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008239 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008240 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008241 if (ctxt->context->tmpNsList != NULL) {
8242 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8243 ctxt->context->tmpNsNr++;
8244 }
8245 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008246 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008247 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008248 if (ctxt->context->tmpNsNr > 0) {
8249 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8250 } else {
8251 if (ctxt->context->tmpNsList != NULL)
8252 xmlFree(ctxt->context->tmpNsList);
8253 ctxt->context->tmpNsList = NULL;
8254 return(NULL);
8255 }
Owen Taylor3473f882001-02-23 17:55:21 +00008256}
8257
8258/**
8259 * xmlXPathNextAttribute:
8260 * @ctxt: the XPath Parser context
8261 * @cur: the current attribute in the traversal
8262 *
8263 * Traversal function for the "attribute" direction
8264 * TODO: support DTD inherited default attributes
8265 *
8266 * Returns the next element following that axis
8267 */
8268xmlNodePtr
8269xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008270 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008271 if (ctxt->context->node == NULL)
8272 return(NULL);
8273 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8274 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008275 if (cur == NULL) {
8276 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8277 return(NULL);
8278 return((xmlNodePtr)ctxt->context->node->properties);
8279 }
8280 return((xmlNodePtr)cur->next);
8281}
8282
8283/************************************************************************
8284 * *
8285 * NodeTest Functions *
8286 * *
8287 ************************************************************************/
8288
Owen Taylor3473f882001-02-23 17:55:21 +00008289#define IS_FUNCTION 200
8290
Owen Taylor3473f882001-02-23 17:55:21 +00008291
8292/************************************************************************
8293 * *
8294 * Implicit tree core function library *
8295 * *
8296 ************************************************************************/
8297
8298/**
8299 * xmlXPathRoot:
8300 * @ctxt: the XPath Parser context
8301 *
8302 * Initialize the context to the root of the document
8303 */
8304void
8305xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008306 if ((ctxt == NULL) || (ctxt->context == NULL))
8307 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008308 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008309 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8310 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008311}
8312
8313/************************************************************************
8314 * *
8315 * The explicit core function library *
8316 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8317 * *
8318 ************************************************************************/
8319
8320
8321/**
8322 * xmlXPathLastFunction:
8323 * @ctxt: the XPath Parser context
8324 * @nargs: the number of arguments
8325 *
8326 * Implement the last() XPath function
8327 * number last()
8328 * The last function returns the number of nodes in the context node list.
8329 */
8330void
8331xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8332 CHECK_ARITY(0);
8333 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008334 valuePush(ctxt,
8335 xmlXPathCacheNewFloat(ctxt->context,
8336 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008337#ifdef DEBUG_EXPR
8338 xmlGenericError(xmlGenericErrorContext,
8339 "last() : %d\n", ctxt->context->contextSize);
8340#endif
8341 } else {
8342 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8343 }
8344}
8345
8346/**
8347 * xmlXPathPositionFunction:
8348 * @ctxt: the XPath Parser context
8349 * @nargs: the number of arguments
8350 *
8351 * Implement the position() XPath function
8352 * number position()
8353 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008354 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008355 * will be equal to last().
8356 */
8357void
8358xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8359 CHECK_ARITY(0);
8360 if (ctxt->context->proximityPosition >= 0) {
8361 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008362 xmlXPathCacheNewFloat(ctxt->context,
8363 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008364#ifdef DEBUG_EXPR
8365 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8366 ctxt->context->proximityPosition);
8367#endif
8368 } else {
8369 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8370 }
8371}
8372
8373/**
8374 * xmlXPathCountFunction:
8375 * @ctxt: the XPath Parser context
8376 * @nargs: the number of arguments
8377 *
8378 * Implement the count() XPath function
8379 * number count(node-set)
8380 */
8381void
8382xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8383 xmlXPathObjectPtr cur;
8384
8385 CHECK_ARITY(1);
8386 if ((ctxt->value == NULL) ||
8387 ((ctxt->value->type != XPATH_NODESET) &&
8388 (ctxt->value->type != XPATH_XSLT_TREE)))
8389 XP_ERROR(XPATH_INVALID_TYPE);
8390 cur = valuePop(ctxt);
8391
Daniel Veillard911f49a2001-04-07 15:39:35 +00008392 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008393 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008394 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008395 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8396 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008397 } else {
8398 if ((cur->nodesetval->nodeNr != 1) ||
8399 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008400 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008401 } else {
8402 xmlNodePtr tmp;
8403 int i = 0;
8404
8405 tmp = cur->nodesetval->nodeTab[0];
8406 if (tmp != NULL) {
8407 tmp = tmp->children;
8408 while (tmp != NULL) {
8409 tmp = tmp->next;
8410 i++;
8411 }
8412 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008413 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008414 }
8415 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008416 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008417}
8418
8419/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008420 * xmlXPathGetElementsByIds:
8421 * @doc: the document
8422 * @ids: a whitespace separated list of IDs
8423 *
8424 * Selects elements by their unique ID.
8425 *
8426 * Returns a node-set of selected elements.
8427 */
8428static xmlNodeSetPtr
8429xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8430 xmlNodeSetPtr ret;
8431 const xmlChar *cur = ids;
8432 xmlChar *ID;
8433 xmlAttrPtr attr;
8434 xmlNodePtr elem = NULL;
8435
Daniel Veillard7a985a12003-07-06 17:57:42 +00008436 if (ids == NULL) return(NULL);
8437
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008438 ret = xmlXPathNodeSetCreate(NULL);
8439
William M. Brack76e95df2003-10-18 16:20:14 +00008440 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008441 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008442 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008443 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008444
8445 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008446 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008447 /*
8448 * We used to check the fact that the value passed
8449 * was an NCName, but this generated much troubles for
8450 * me and Aleksey Sanin, people blatantly violated that
8451 * constaint, like Visa3D spec.
8452 * if (xmlValidateNCName(ID, 1) == 0)
8453 */
8454 attr = xmlGetID(doc, ID);
8455 if (attr != NULL) {
8456 if (attr->type == XML_ATTRIBUTE_NODE)
8457 elem = attr->parent;
8458 else if (attr->type == XML_ELEMENT_NODE)
8459 elem = (xmlNodePtr) attr;
8460 else
8461 elem = NULL;
8462 if (elem != NULL)
8463 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008464 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008465 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008466 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008467
William M. Brack76e95df2003-10-18 16:20:14 +00008468 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008469 ids = cur;
8470 }
8471 return(ret);
8472}
8473
8474/**
Owen Taylor3473f882001-02-23 17:55:21 +00008475 * xmlXPathIdFunction:
8476 * @ctxt: the XPath Parser context
8477 * @nargs: the number of arguments
8478 *
8479 * Implement the id() XPath function
8480 * node-set id(object)
8481 * The id function selects elements by their unique ID
8482 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8483 * then the result is the union of the result of applying id to the
8484 * string value of each of the nodes in the argument node-set. When the
8485 * argument to id is of any other type, the argument is converted to a
8486 * string as if by a call to the string function; the string is split
8487 * into a whitespace-separated list of tokens (whitespace is any sequence
8488 * of characters matching the production S); the result is a node-set
8489 * containing the elements in the same document as the context node that
8490 * have a unique ID equal to any of the tokens in the list.
8491 */
8492void
8493xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008494 xmlChar *tokens;
8495 xmlNodeSetPtr ret;
8496 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008497
8498 CHECK_ARITY(1);
8499 obj = valuePop(ctxt);
8500 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008501 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008502 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008503 int i;
8504
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008505 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008506
Daniel Veillard911f49a2001-04-07 15:39:35 +00008507 if (obj->nodesetval != NULL) {
8508 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008509 tokens =
8510 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8511 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8512 ret = xmlXPathNodeSetMerge(ret, ns);
8513 xmlXPathFreeNodeSet(ns);
8514 if (tokens != NULL)
8515 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008516 }
Owen Taylor3473f882001-02-23 17:55:21 +00008517 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008518 xmlXPathReleaseObject(ctxt->context, obj);
8519 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008520 return;
8521 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008522 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008523 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008524 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8525 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008526 return;
8527}
8528
8529/**
8530 * xmlXPathLocalNameFunction:
8531 * @ctxt: the XPath Parser context
8532 * @nargs: the number of arguments
8533 *
8534 * Implement the local-name() XPath function
8535 * string local-name(node-set?)
8536 * The local-name function returns a string containing the local part
8537 * of the name of the node in the argument node-set that is first in
8538 * document order. If the node-set is empty or the first node has no
8539 * name, an empty string is returned. If the argument is omitted it
8540 * defaults to the context node.
8541 */
8542void
8543xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8544 xmlXPathObjectPtr cur;
8545
Daniel Veillarda82b1822004-11-08 16:24:57 +00008546 if (ctxt == NULL) return;
8547
Owen Taylor3473f882001-02-23 17:55:21 +00008548 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008549 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8550 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008551 nargs = 1;
8552 }
8553
8554 CHECK_ARITY(1);
8555 if ((ctxt->value == NULL) ||
8556 ((ctxt->value->type != XPATH_NODESET) &&
8557 (ctxt->value->type != XPATH_XSLT_TREE)))
8558 XP_ERROR(XPATH_INVALID_TYPE);
8559 cur = valuePop(ctxt);
8560
Daniel Veillard911f49a2001-04-07 15:39:35 +00008561 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008562 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008563 } else {
8564 int i = 0; /* Should be first in document order !!!!! */
8565 switch (cur->nodesetval->nodeTab[i]->type) {
8566 case XML_ELEMENT_NODE:
8567 case XML_ATTRIBUTE_NODE:
8568 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008569 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008570 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008571 else
8572 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008573 xmlXPathCacheNewString(ctxt->context,
8574 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008575 break;
8576 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008577 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008578 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8579 break;
8580 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008581 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008582 }
8583 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008584 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008585}
8586
8587/**
8588 * xmlXPathNamespaceURIFunction:
8589 * @ctxt: the XPath Parser context
8590 * @nargs: the number of arguments
8591 *
8592 * Implement the namespace-uri() XPath function
8593 * string namespace-uri(node-set?)
8594 * The namespace-uri function returns a string containing the
8595 * namespace URI of the expanded name of the node in the argument
8596 * node-set that is first in document order. If the node-set is empty,
8597 * the first node has no name, or the expanded name has no namespace
8598 * URI, an empty string is returned. If the argument is omitted it
8599 * defaults to the context node.
8600 */
8601void
8602xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8603 xmlXPathObjectPtr cur;
8604
Daniel Veillarda82b1822004-11-08 16:24:57 +00008605 if (ctxt == NULL) return;
8606
Owen Taylor3473f882001-02-23 17:55:21 +00008607 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008608 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8609 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008610 nargs = 1;
8611 }
8612 CHECK_ARITY(1);
8613 if ((ctxt->value == NULL) ||
8614 ((ctxt->value->type != XPATH_NODESET) &&
8615 (ctxt->value->type != XPATH_XSLT_TREE)))
8616 XP_ERROR(XPATH_INVALID_TYPE);
8617 cur = valuePop(ctxt);
8618
Daniel Veillard911f49a2001-04-07 15:39:35 +00008619 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008620 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008621 } else {
8622 int i = 0; /* Should be first in document order !!!!! */
8623 switch (cur->nodesetval->nodeTab[i]->type) {
8624 case XML_ELEMENT_NODE:
8625 case XML_ATTRIBUTE_NODE:
8626 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008627 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008628 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008629 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008630 cur->nodesetval->nodeTab[i]->ns->href));
8631 break;
8632 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008633 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008634 }
8635 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008636 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008637}
8638
8639/**
8640 * xmlXPathNameFunction:
8641 * @ctxt: the XPath Parser context
8642 * @nargs: the number of arguments
8643 *
8644 * Implement the name() XPath function
8645 * string name(node-set?)
8646 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008647 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008648 * order. The QName must represent the name with respect to the namespace
8649 * declarations in effect on the node whose name is being represented.
8650 * Typically, this will be the form in which the name occurred in the XML
8651 * source. This need not be the case if there are namespace declarations
8652 * in effect on the node that associate multiple prefixes with the same
8653 * namespace. However, an implementation may include information about
8654 * the original prefix in its representation of nodes; in this case, an
8655 * implementation can ensure that the returned string is always the same
8656 * as the QName used in the XML source. If the argument it omitted it
8657 * defaults to the context node.
8658 * Libxml keep the original prefix so the "real qualified name" used is
8659 * returned.
8660 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008661static void
Daniel Veillard04383752001-07-08 14:27:15 +00008662xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8663{
Owen Taylor3473f882001-02-23 17:55:21 +00008664 xmlXPathObjectPtr cur;
8665
8666 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008667 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8668 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008669 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008670 }
8671
8672 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008673 if ((ctxt->value == NULL) ||
8674 ((ctxt->value->type != XPATH_NODESET) &&
8675 (ctxt->value->type != XPATH_XSLT_TREE)))
8676 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008677 cur = valuePop(ctxt);
8678
Daniel Veillard911f49a2001-04-07 15:39:35 +00008679 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008680 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008681 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008682 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008683
Daniel Veillard04383752001-07-08 14:27:15 +00008684 switch (cur->nodesetval->nodeTab[i]->type) {
8685 case XML_ELEMENT_NODE:
8686 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008687 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008688 valuePush(ctxt,
8689 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008690 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8691 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008692 valuePush(ctxt,
8693 xmlXPathCacheNewString(ctxt->context,
8694 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008695 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008696 xmlChar *fullname;
8697
8698 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8699 cur->nodesetval->nodeTab[i]->ns->prefix,
8700 NULL, 0);
8701 if (fullname == cur->nodesetval->nodeTab[i]->name)
8702 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8703 if (fullname == NULL) {
8704 XP_ERROR(XPATH_MEMORY_ERROR);
8705 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008706 valuePush(ctxt, xmlXPathCacheWrapString(
8707 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008708 }
8709 break;
8710 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008711 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8712 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008713 xmlXPathLocalNameFunction(ctxt, 1);
8714 }
Owen Taylor3473f882001-02-23 17:55:21 +00008715 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008716 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008717}
8718
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008719
8720/**
Owen Taylor3473f882001-02-23 17:55:21 +00008721 * xmlXPathStringFunction:
8722 * @ctxt: the XPath Parser context
8723 * @nargs: the number of arguments
8724 *
8725 * Implement the string() XPath function
8726 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008727 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008728 * - A node-set is converted to a string by returning the value of
8729 * the node in the node-set that is first in document order.
8730 * If the node-set is empty, an empty string is returned.
8731 * - A number is converted to a string as follows
8732 * + NaN is converted to the string NaN
8733 * + positive zero is converted to the string 0
8734 * + negative zero is converted to the string 0
8735 * + positive infinity is converted to the string Infinity
8736 * + negative infinity is converted to the string -Infinity
8737 * + if the number is an integer, the number is represented in
8738 * decimal form as a Number with no decimal point and no leading
8739 * zeros, preceded by a minus sign (-) if the number is negative
8740 * + otherwise, the number is represented in decimal form as a
8741 * Number including a decimal point with at least one digit
8742 * before the decimal point and at least one digit after the
8743 * decimal point, preceded by a minus sign (-) if the number
8744 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008745 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008746 * before the decimal point; beyond the one required digit
8747 * after the decimal point there must be as many, but only as
8748 * many, more digits as are needed to uniquely distinguish the
8749 * number from all other IEEE 754 numeric values.
8750 * - The boolean false value is converted to the string false.
8751 * The boolean true value is converted to the string true.
8752 *
8753 * If the argument is omitted, it defaults to a node-set with the
8754 * context node as its only member.
8755 */
8756void
8757xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8758 xmlXPathObjectPtr cur;
8759
Daniel Veillarda82b1822004-11-08 16:24:57 +00008760 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008761 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008762 valuePush(ctxt,
8763 xmlXPathCacheWrapString(ctxt->context,
8764 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008765 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008766 }
8767
8768 CHECK_ARITY(1);
8769 cur = valuePop(ctxt);
8770 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008771 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008772}
8773
8774/**
8775 * xmlXPathStringLengthFunction:
8776 * @ctxt: the XPath Parser context
8777 * @nargs: the number of arguments
8778 *
8779 * Implement the string-length() XPath function
8780 * number string-length(string?)
8781 * The string-length returns the number of characters in the string
8782 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8783 * the context node converted to a string, in other words the value
8784 * of the context node.
8785 */
8786void
8787xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8788 xmlXPathObjectPtr cur;
8789
8790 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008791 if ((ctxt == NULL) || (ctxt->context == NULL))
8792 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008793 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008794 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008795 } else {
8796 xmlChar *content;
8797
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008798 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008799 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8800 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008801 xmlFree(content);
8802 }
8803 return;
8804 }
8805 CHECK_ARITY(1);
8806 CAST_TO_STRING;
8807 CHECK_TYPE(XPATH_STRING);
8808 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008809 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8810 xmlUTF8Strlen(cur->stringval)));
8811 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008812}
8813
8814/**
8815 * xmlXPathConcatFunction:
8816 * @ctxt: the XPath Parser context
8817 * @nargs: the number of arguments
8818 *
8819 * Implement the concat() XPath function
8820 * string concat(string, string, string*)
8821 * The concat function returns the concatenation of its arguments.
8822 */
8823void
8824xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8825 xmlXPathObjectPtr cur, newobj;
8826 xmlChar *tmp;
8827
Daniel Veillarda82b1822004-11-08 16:24:57 +00008828 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008829 if (nargs < 2) {
8830 CHECK_ARITY(2);
8831 }
8832
8833 CAST_TO_STRING;
8834 cur = valuePop(ctxt);
8835 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008836 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008837 return;
8838 }
8839 nargs--;
8840
8841 while (nargs > 0) {
8842 CAST_TO_STRING;
8843 newobj = valuePop(ctxt);
8844 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008845 xmlXPathReleaseObject(ctxt->context, newobj);
8846 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008847 XP_ERROR(XPATH_INVALID_TYPE);
8848 }
8849 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8850 newobj->stringval = cur->stringval;
8851 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008852 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008853 nargs--;
8854 }
8855 valuePush(ctxt, cur);
8856}
8857
8858/**
8859 * xmlXPathContainsFunction:
8860 * @ctxt: the XPath Parser context
8861 * @nargs: the number of arguments
8862 *
8863 * Implement the contains() XPath function
8864 * boolean contains(string, string)
8865 * The contains function returns true if the first argument string
8866 * contains the second argument string, and otherwise returns false.
8867 */
8868void
8869xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8870 xmlXPathObjectPtr hay, needle;
8871
8872 CHECK_ARITY(2);
8873 CAST_TO_STRING;
8874 CHECK_TYPE(XPATH_STRING);
8875 needle = valuePop(ctxt);
8876 CAST_TO_STRING;
8877 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008878
Owen Taylor3473f882001-02-23 17:55:21 +00008879 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008880 xmlXPathReleaseObject(ctxt->context, hay);
8881 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008882 XP_ERROR(XPATH_INVALID_TYPE);
8883 }
8884 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008885 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008886 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008887 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8888 xmlXPathReleaseObject(ctxt->context, hay);
8889 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008890}
8891
8892/**
8893 * xmlXPathStartsWithFunction:
8894 * @ctxt: the XPath Parser context
8895 * @nargs: the number of arguments
8896 *
8897 * Implement the starts-with() XPath function
8898 * boolean starts-with(string, string)
8899 * The starts-with function returns true if the first argument string
8900 * starts with the second argument string, and otherwise returns false.
8901 */
8902void
8903xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8904 xmlXPathObjectPtr hay, needle;
8905 int n;
8906
8907 CHECK_ARITY(2);
8908 CAST_TO_STRING;
8909 CHECK_TYPE(XPATH_STRING);
8910 needle = valuePop(ctxt);
8911 CAST_TO_STRING;
8912 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008913
Owen Taylor3473f882001-02-23 17:55:21 +00008914 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008915 xmlXPathReleaseObject(ctxt->context, hay);
8916 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008917 XP_ERROR(XPATH_INVALID_TYPE);
8918 }
8919 n = xmlStrlen(needle->stringval);
8920 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008921 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008922 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008923 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8924 xmlXPathReleaseObject(ctxt->context, hay);
8925 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008926}
8927
8928/**
8929 * xmlXPathSubstringFunction:
8930 * @ctxt: the XPath Parser context
8931 * @nargs: the number of arguments
8932 *
8933 * Implement the substring() XPath function
8934 * string substring(string, number, number?)
8935 * The substring function returns the substring of the first argument
8936 * starting at the position specified in the second argument with
8937 * length specified in the third argument. For example,
8938 * substring("12345",2,3) returns "234". If the third argument is not
8939 * specified, it returns the substring starting at the position specified
8940 * in the second argument and continuing to the end of the string. For
8941 * example, substring("12345",2) returns "2345". More precisely, each
8942 * character in the string (see [3.6 Strings]) is considered to have a
8943 * numeric position: the position of the first character is 1, the position
8944 * of the second character is 2 and so on. The returned substring contains
8945 * those characters for which the position of the character is greater than
8946 * or equal to the second argument and, if the third argument is specified,
8947 * less than the sum of the second and third arguments; the comparisons
8948 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8949 * - substring("12345", 1.5, 2.6) returns "234"
8950 * - substring("12345", 0, 3) returns "12"
8951 * - substring("12345", 0 div 0, 3) returns ""
8952 * - substring("12345", 1, 0 div 0) returns ""
8953 * - substring("12345", -42, 1 div 0) returns "12345"
8954 * - substring("12345", -1 div 0, 1 div 0) returns ""
8955 */
8956void
8957xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8958 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008959 double le=0, in;
8960 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008961 xmlChar *ret;
8962
Owen Taylor3473f882001-02-23 17:55:21 +00008963 if (nargs < 2) {
8964 CHECK_ARITY(2);
8965 }
8966 if (nargs > 3) {
8967 CHECK_ARITY(3);
8968 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008969 /*
8970 * take care of possible last (position) argument
8971 */
Owen Taylor3473f882001-02-23 17:55:21 +00008972 if (nargs == 3) {
8973 CAST_TO_NUMBER;
8974 CHECK_TYPE(XPATH_NUMBER);
8975 len = valuePop(ctxt);
8976 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008977 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008978 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008979
Owen Taylor3473f882001-02-23 17:55:21 +00008980 CAST_TO_NUMBER;
8981 CHECK_TYPE(XPATH_NUMBER);
8982 start = valuePop(ctxt);
8983 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008984 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008985 CAST_TO_STRING;
8986 CHECK_TYPE(XPATH_STRING);
8987 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008988 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008989
Daniel Veillard97ac1312001-05-30 19:14:17 +00008990 /*
8991 * If last pos not present, calculate last position
8992 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008993 if (nargs != 3) {
8994 le = (double)m;
8995 if (in < 1.0)
8996 in = 1.0;
8997 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008998
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008999 /* Need to check for the special cases where either
9000 * the index is NaN, the length is NaN, or both
9001 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00009002 */
Daniel Veillard9e412302002-06-10 15:59:44 +00009003 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009004 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009005 * To meet the requirements of the spec, the arguments
9006 * must be converted to integer format before
9007 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009008 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009009 * First we go to integer form, rounding up
9010 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009011 */
9012 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009013 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009014
Daniel Veillard9e412302002-06-10 15:59:44 +00009015 if (xmlXPathIsInf(le) == 1) {
9016 l = m;
9017 if (i < 1)
9018 i = 1;
9019 }
9020 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9021 l = 0;
9022 else {
9023 l = (int) le;
9024 if (((double)l)+0.5 <= le) l++;
9025 }
9026
9027 /* Now we normalize inidices */
9028 i -= 1;
9029 l += i;
9030 if (i < 0)
9031 i = 0;
9032 if (l > m)
9033 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009034
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009035 /* number of chars to copy */
9036 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009037
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009038 ret = xmlUTF8Strsub(str->stringval, i, l);
9039 }
9040 else {
9041 ret = NULL;
9042 }
Owen Taylor3473f882001-02-23 17:55:21 +00009043 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009044 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009045 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009046 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009047 xmlFree(ret);
9048 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009049 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009050}
9051
9052/**
9053 * xmlXPathSubstringBeforeFunction:
9054 * @ctxt: the XPath Parser context
9055 * @nargs: the number of arguments
9056 *
9057 * Implement the substring-before() XPath function
9058 * string substring-before(string, string)
9059 * The substring-before function returns the substring of the first
9060 * argument string that precedes the first occurrence of the second
9061 * argument string in the first argument string, or the empty string
9062 * if the first argument string does not contain the second argument
9063 * string. For example, substring-before("1999/04/01","/") returns 1999.
9064 */
9065void
9066xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9067 xmlXPathObjectPtr str;
9068 xmlXPathObjectPtr find;
9069 xmlBufferPtr target;
9070 const xmlChar *point;
9071 int offset;
9072
9073 CHECK_ARITY(2);
9074 CAST_TO_STRING;
9075 find = valuePop(ctxt);
9076 CAST_TO_STRING;
9077 str = valuePop(ctxt);
9078
9079 target = xmlBufferCreate();
9080 if (target) {
9081 point = xmlStrstr(str->stringval, find->stringval);
9082 if (point) {
9083 offset = (int)(point - str->stringval);
9084 xmlBufferAdd(target, str->stringval, offset);
9085 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009086 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9087 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009088 xmlBufferFree(target);
9089 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009090 xmlXPathReleaseObject(ctxt->context, str);
9091 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009092}
9093
9094/**
9095 * xmlXPathSubstringAfterFunction:
9096 * @ctxt: the XPath Parser context
9097 * @nargs: the number of arguments
9098 *
9099 * Implement the substring-after() XPath function
9100 * string substring-after(string, string)
9101 * The substring-after function returns the substring of the first
9102 * argument string that follows the first occurrence of the second
9103 * argument string in the first argument string, or the empty stringi
9104 * if the first argument string does not contain the second argument
9105 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9106 * and substring-after("1999/04/01","19") returns 99/04/01.
9107 */
9108void
9109xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9110 xmlXPathObjectPtr str;
9111 xmlXPathObjectPtr find;
9112 xmlBufferPtr target;
9113 const xmlChar *point;
9114 int offset;
9115
9116 CHECK_ARITY(2);
9117 CAST_TO_STRING;
9118 find = valuePop(ctxt);
9119 CAST_TO_STRING;
9120 str = valuePop(ctxt);
9121
9122 target = xmlBufferCreate();
9123 if (target) {
9124 point = xmlStrstr(str->stringval, find->stringval);
9125 if (point) {
9126 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9127 xmlBufferAdd(target, &str->stringval[offset],
9128 xmlStrlen(str->stringval) - offset);
9129 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009130 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9131 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009132 xmlBufferFree(target);
9133 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009134 xmlXPathReleaseObject(ctxt->context, str);
9135 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009136}
9137
9138/**
9139 * xmlXPathNormalizeFunction:
9140 * @ctxt: the XPath Parser context
9141 * @nargs: the number of arguments
9142 *
9143 * Implement the normalize-space() XPath function
9144 * string normalize-space(string?)
9145 * The normalize-space function returns the argument string with white
9146 * space normalized by stripping leading and trailing whitespace
9147 * and replacing sequences of whitespace characters by a single
9148 * space. Whitespace characters are the same allowed by the S production
9149 * in XML. If the argument is omitted, it defaults to the context
9150 * node converted to a string, in other words the value of the context node.
9151 */
9152void
9153xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9154 xmlXPathObjectPtr obj = NULL;
9155 xmlChar *source = NULL;
9156 xmlBufferPtr target;
9157 xmlChar blank;
9158
Daniel Veillarda82b1822004-11-08 16:24:57 +00009159 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009160 if (nargs == 0) {
9161 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009162 valuePush(ctxt,
9163 xmlXPathCacheWrapString(ctxt->context,
9164 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009165 nargs = 1;
9166 }
9167
9168 CHECK_ARITY(1);
9169 CAST_TO_STRING;
9170 CHECK_TYPE(XPATH_STRING);
9171 obj = valuePop(ctxt);
9172 source = obj->stringval;
9173
9174 target = xmlBufferCreate();
9175 if (target && source) {
9176
9177 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009178 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009179 source++;
9180
9181 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9182 blank = 0;
9183 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009184 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009185 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009186 } else {
9187 if (blank) {
9188 xmlBufferAdd(target, &blank, 1);
9189 blank = 0;
9190 }
9191 xmlBufferAdd(target, source, 1);
9192 }
9193 source++;
9194 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009195 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9196 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009197 xmlBufferFree(target);
9198 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009199 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009200}
9201
9202/**
9203 * xmlXPathTranslateFunction:
9204 * @ctxt: the XPath Parser context
9205 * @nargs: the number of arguments
9206 *
9207 * Implement the translate() XPath function
9208 * string translate(string, string, string)
9209 * The translate function returns the first argument string with
9210 * occurrences of characters in the second argument string replaced
9211 * by the character at the corresponding position in the third argument
9212 * string. For example, translate("bar","abc","ABC") returns the string
9213 * BAr. If there is a character in the second argument string with no
9214 * character at a corresponding position in the third argument string
9215 * (because the second argument string is longer than the third argument
9216 * string), then occurrences of that character in the first argument
9217 * string are removed. For example, translate("--aaa--","abc-","ABC")
9218 * returns "AAA". If a character occurs more than once in second
9219 * argument string, then the first occurrence determines the replacement
9220 * character. If the third argument string is longer than the second
9221 * argument string, then excess characters are ignored.
9222 */
9223void
9224xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009225 xmlXPathObjectPtr str;
9226 xmlXPathObjectPtr from;
9227 xmlXPathObjectPtr to;
9228 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009229 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009230 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009231 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009232 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009233
Daniel Veillarde043ee12001-04-16 14:08:07 +00009234 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009235
Daniel Veillarde043ee12001-04-16 14:08:07 +00009236 CAST_TO_STRING;
9237 to = valuePop(ctxt);
9238 CAST_TO_STRING;
9239 from = valuePop(ctxt);
9240 CAST_TO_STRING;
9241 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009242
Daniel Veillarde043ee12001-04-16 14:08:07 +00009243 target = xmlBufferCreate();
9244 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009245 max = xmlUTF8Strlen(to->stringval);
9246 for (cptr = str->stringval; (ch=*cptr); ) {
9247 offset = xmlUTF8Strloc(from->stringval, cptr);
9248 if (offset >= 0) {
9249 if (offset < max) {
9250 point = xmlUTF8Strpos(to->stringval, offset);
9251 if (point)
9252 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9253 }
9254 } else
9255 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9256
9257 /* Step to next character in input */
9258 cptr++;
9259 if ( ch & 0x80 ) {
9260 /* if not simple ascii, verify proper format */
9261 if ( (ch & 0xc0) != 0xc0 ) {
9262 xmlGenericError(xmlGenericErrorContext,
9263 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9264 break;
9265 }
9266 /* then skip over remaining bytes for this char */
9267 while ( (ch <<= 1) & 0x80 )
9268 if ( (*cptr++ & 0xc0) != 0x80 ) {
9269 xmlGenericError(xmlGenericErrorContext,
9270 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9271 break;
9272 }
9273 if (ch & 0x80) /* must have had error encountered */
9274 break;
9275 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009276 }
Owen Taylor3473f882001-02-23 17:55:21 +00009277 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009278 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9279 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009280 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009281 xmlXPathReleaseObject(ctxt->context, str);
9282 xmlXPathReleaseObject(ctxt->context, from);
9283 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009284}
9285
9286/**
9287 * xmlXPathBooleanFunction:
9288 * @ctxt: the XPath Parser context
9289 * @nargs: the number of arguments
9290 *
9291 * Implement the boolean() XPath function
9292 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009293 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009294 * - a number is true if and only if it is neither positive or
9295 * negative zero nor NaN
9296 * - a node-set is true if and only if it is non-empty
9297 * - a string is true if and only if its length is non-zero
9298 */
9299void
9300xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9301 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009302
9303 CHECK_ARITY(1);
9304 cur = valuePop(ctxt);
9305 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009306 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009307 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009308}
9309
9310/**
9311 * xmlXPathNotFunction:
9312 * @ctxt: the XPath Parser context
9313 * @nargs: the number of arguments
9314 *
9315 * Implement the not() XPath function
9316 * boolean not(boolean)
9317 * The not function returns true if its argument is false,
9318 * and false otherwise.
9319 */
9320void
9321xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9322 CHECK_ARITY(1);
9323 CAST_TO_BOOLEAN;
9324 CHECK_TYPE(XPATH_BOOLEAN);
9325 ctxt->value->boolval = ! ctxt->value->boolval;
9326}
9327
9328/**
9329 * xmlXPathTrueFunction:
9330 * @ctxt: the XPath Parser context
9331 * @nargs: the number of arguments
9332 *
9333 * Implement the true() XPath function
9334 * boolean true()
9335 */
9336void
9337xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9338 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009339 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009340}
9341
9342/**
9343 * xmlXPathFalseFunction:
9344 * @ctxt: the XPath Parser context
9345 * @nargs: the number of arguments
9346 *
9347 * Implement the false() XPath function
9348 * boolean false()
9349 */
9350void
9351xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9352 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009353 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009354}
9355
9356/**
9357 * xmlXPathLangFunction:
9358 * @ctxt: the XPath Parser context
9359 * @nargs: the number of arguments
9360 *
9361 * Implement the lang() XPath function
9362 * boolean lang(string)
9363 * The lang function returns true or false depending on whether the
9364 * language of the context node as specified by xml:lang attributes
9365 * is the same as or is a sublanguage of the language specified by
9366 * the argument string. The language of the context node is determined
9367 * by the value of the xml:lang attribute on the context node, or, if
9368 * the context node has no xml:lang attribute, by the value of the
9369 * xml:lang attribute on the nearest ancestor of the context node that
9370 * has an xml:lang attribute. If there is no such attribute, then lang
9371 * returns false. If there is such an attribute, then lang returns
9372 * true if the attribute value is equal to the argument ignoring case,
9373 * or if there is some suffix starting with - such that the attribute
9374 * value is equal to the argument ignoring that suffix of the attribute
9375 * value and ignoring case.
9376 */
9377void
9378xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009379 xmlXPathObjectPtr val = NULL;
9380 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009381 const xmlChar *lang;
9382 int ret = 0;
9383 int i;
9384
9385 CHECK_ARITY(1);
9386 CAST_TO_STRING;
9387 CHECK_TYPE(XPATH_STRING);
9388 val = valuePop(ctxt);
9389 lang = val->stringval;
9390 theLang = xmlNodeGetLang(ctxt->context->node);
9391 if ((theLang != NULL) && (lang != NULL)) {
9392 for (i = 0;lang[i] != 0;i++)
9393 if (toupper(lang[i]) != toupper(theLang[i]))
9394 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009395 if ((theLang[i] == 0) || (theLang[i] == '-'))
9396 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009397 }
9398not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009399 if (theLang != NULL)
9400 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009401
9402 xmlXPathReleaseObject(ctxt->context, val);
9403 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009404}
9405
9406/**
9407 * xmlXPathNumberFunction:
9408 * @ctxt: the XPath Parser context
9409 * @nargs: the number of arguments
9410 *
9411 * Implement the number() XPath function
9412 * number number(object?)
9413 */
9414void
9415xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9416 xmlXPathObjectPtr cur;
9417 double res;
9418
Daniel Veillarda82b1822004-11-08 16:24:57 +00009419 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009420 if (nargs == 0) {
9421 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009422 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009423 } else {
9424 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9425
9426 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009427 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009428 xmlFree(content);
9429 }
9430 return;
9431 }
9432
9433 CHECK_ARITY(1);
9434 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009435 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009436}
9437
9438/**
9439 * xmlXPathSumFunction:
9440 * @ctxt: the XPath Parser context
9441 * @nargs: the number of arguments
9442 *
9443 * Implement the sum() XPath function
9444 * number sum(node-set)
9445 * The sum function returns the sum of the values of the nodes in
9446 * the argument node-set.
9447 */
9448void
9449xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9450 xmlXPathObjectPtr cur;
9451 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009452 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009453
9454 CHECK_ARITY(1);
9455 if ((ctxt->value == NULL) ||
9456 ((ctxt->value->type != XPATH_NODESET) &&
9457 (ctxt->value->type != XPATH_XSLT_TREE)))
9458 XP_ERROR(XPATH_INVALID_TYPE);
9459 cur = valuePop(ctxt);
9460
William M. Brack08171912003-12-29 02:52:11 +00009461 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009462 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9463 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009464 }
9465 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009466 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9467 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009468}
9469
William M. Brack3d426662005-04-19 14:40:28 +00009470/*
9471 * To assure working code on multiple platforms, we want to only depend
9472 * upon the characteristic truncation of converting a floating point value
9473 * to an integer. Unfortunately, because of the different storage sizes
9474 * of our internal floating point value (double) and integer (int), we
9475 * can't directly convert (see bug 301162). This macro is a messy
9476 * 'workaround'
9477 */
9478#define XTRUNC(f, v) \
9479 f = fmod((v), INT_MAX); \
9480 f = (v) - (f) + (double)((int)(f));
9481
Owen Taylor3473f882001-02-23 17:55:21 +00009482/**
9483 * xmlXPathFloorFunction:
9484 * @ctxt: the XPath Parser context
9485 * @nargs: the number of arguments
9486 *
9487 * Implement the floor() XPath function
9488 * number floor(number)
9489 * The floor function returns the largest (closest to positive infinity)
9490 * number that is not greater than the argument and that is an integer.
9491 */
9492void
9493xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009494 double f;
9495
Owen Taylor3473f882001-02-23 17:55:21 +00009496 CHECK_ARITY(1);
9497 CAST_TO_NUMBER;
9498 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009499
William M. Brack3d426662005-04-19 14:40:28 +00009500 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009501 if (f != ctxt->value->floatval) {
9502 if (ctxt->value->floatval > 0)
9503 ctxt->value->floatval = f;
9504 else
9505 ctxt->value->floatval = f - 1;
9506 }
Owen Taylor3473f882001-02-23 17:55:21 +00009507}
9508
9509/**
9510 * xmlXPathCeilingFunction:
9511 * @ctxt: the XPath Parser context
9512 * @nargs: the number of arguments
9513 *
9514 * Implement the ceiling() XPath function
9515 * number ceiling(number)
9516 * The ceiling function returns the smallest (closest to negative infinity)
9517 * number that is not less than the argument and that is an integer.
9518 */
9519void
9520xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9521 double f;
9522
9523 CHECK_ARITY(1);
9524 CAST_TO_NUMBER;
9525 CHECK_TYPE(XPATH_NUMBER);
9526
9527#if 0
9528 ctxt->value->floatval = ceil(ctxt->value->floatval);
9529#else
William M. Brack3d426662005-04-19 14:40:28 +00009530 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009531 if (f != ctxt->value->floatval) {
9532 if (ctxt->value->floatval > 0)
9533 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009534 else {
9535 if (ctxt->value->floatval < 0 && f == 0)
9536 ctxt->value->floatval = xmlXPathNZERO;
9537 else
9538 ctxt->value->floatval = f;
9539 }
9540
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009541 }
Owen Taylor3473f882001-02-23 17:55:21 +00009542#endif
9543}
9544
9545/**
9546 * xmlXPathRoundFunction:
9547 * @ctxt: the XPath Parser context
9548 * @nargs: the number of arguments
9549 *
9550 * Implement the round() XPath function
9551 * number round(number)
9552 * The round function returns the number that is closest to the
9553 * argument and that is an integer. If there are two such numbers,
9554 * then the one that is even is returned.
9555 */
9556void
9557xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9558 double f;
9559
9560 CHECK_ARITY(1);
9561 CAST_TO_NUMBER;
9562 CHECK_TYPE(XPATH_NUMBER);
9563
Daniel Veillardcda96922001-08-21 10:56:31 +00009564 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9565 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9566 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009567 (ctxt->value->floatval == 0.0))
9568 return;
9569
William M. Brack3d426662005-04-19 14:40:28 +00009570 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009571 if (ctxt->value->floatval < 0) {
9572 if (ctxt->value->floatval < f - 0.5)
9573 ctxt->value->floatval = f - 1;
9574 else
9575 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009576 if (ctxt->value->floatval == 0)
9577 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009578 } else {
9579 if (ctxt->value->floatval < f + 0.5)
9580 ctxt->value->floatval = f;
9581 else
9582 ctxt->value->floatval = f + 1;
9583 }
Owen Taylor3473f882001-02-23 17:55:21 +00009584}
9585
9586/************************************************************************
9587 * *
9588 * The Parser *
9589 * *
9590 ************************************************************************/
9591
9592/*
William M. Brack08171912003-12-29 02:52:11 +00009593 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009594 * implementation.
9595 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009596static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009597static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009598static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009599static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009600static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9601 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009602
9603/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009604 * xmlXPathCurrentChar:
9605 * @ctxt: the XPath parser context
9606 * @cur: pointer to the beginning of the char
9607 * @len: pointer to the length of the char read
9608 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009609 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009610 * bytes in the input buffer.
9611 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009612 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009613 */
9614
9615static int
9616xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9617 unsigned char c;
9618 unsigned int val;
9619 const xmlChar *cur;
9620
9621 if (ctxt == NULL)
9622 return(0);
9623 cur = ctxt->cur;
9624
9625 /*
9626 * We are supposed to handle UTF8, check it's valid
9627 * From rfc2044: encoding of the Unicode values on UTF-8:
9628 *
9629 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9630 * 0000 0000-0000 007F 0xxxxxxx
9631 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9632 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9633 *
9634 * Check for the 0x110000 limit too
9635 */
9636 c = *cur;
9637 if (c & 0x80) {
9638 if ((cur[1] & 0xc0) != 0x80)
9639 goto encoding_error;
9640 if ((c & 0xe0) == 0xe0) {
9641
9642 if ((cur[2] & 0xc0) != 0x80)
9643 goto encoding_error;
9644 if ((c & 0xf0) == 0xf0) {
9645 if (((c & 0xf8) != 0xf0) ||
9646 ((cur[3] & 0xc0) != 0x80))
9647 goto encoding_error;
9648 /* 4-byte code */
9649 *len = 4;
9650 val = (cur[0] & 0x7) << 18;
9651 val |= (cur[1] & 0x3f) << 12;
9652 val |= (cur[2] & 0x3f) << 6;
9653 val |= cur[3] & 0x3f;
9654 } else {
9655 /* 3-byte code */
9656 *len = 3;
9657 val = (cur[0] & 0xf) << 12;
9658 val |= (cur[1] & 0x3f) << 6;
9659 val |= cur[2] & 0x3f;
9660 }
9661 } else {
9662 /* 2-byte code */
9663 *len = 2;
9664 val = (cur[0] & 0x1f) << 6;
9665 val |= cur[1] & 0x3f;
9666 }
9667 if (!IS_CHAR(val)) {
9668 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9669 }
9670 return(val);
9671 } else {
9672 /* 1-byte code */
9673 *len = 1;
9674 return((int) *cur);
9675 }
9676encoding_error:
9677 /*
William M. Brack08171912003-12-29 02:52:11 +00009678 * If we detect an UTF8 error that probably means that the
9679 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009680 * declaration header. Report the error and switch the encoding
9681 * to ISO-Latin-1 (if you don't like this policy, just declare the
9682 * encoding !)
9683 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009684 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009685 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009686}
9687
9688/**
Owen Taylor3473f882001-02-23 17:55:21 +00009689 * xmlXPathParseNCName:
9690 * @ctxt: the XPath Parser context
9691 *
9692 * parse an XML namespace non qualified name.
9693 *
9694 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9695 *
9696 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9697 * CombiningChar | Extender
9698 *
9699 * Returns the namespace name or NULL
9700 */
9701
9702xmlChar *
9703xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009704 const xmlChar *in;
9705 xmlChar *ret;
9706 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009707
Daniel Veillarda82b1822004-11-08 16:24:57 +00009708 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009709 /*
9710 * Accelerator for simple ASCII names
9711 */
9712 in = ctxt->cur;
9713 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9714 ((*in >= 0x41) && (*in <= 0x5A)) ||
9715 (*in == '_')) {
9716 in++;
9717 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9718 ((*in >= 0x41) && (*in <= 0x5A)) ||
9719 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009720 (*in == '_') || (*in == '.') ||
9721 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009722 in++;
9723 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9724 (*in == '[') || (*in == ']') || (*in == ':') ||
9725 (*in == '@') || (*in == '*')) {
9726 count = in - ctxt->cur;
9727 if (count == 0)
9728 return(NULL);
9729 ret = xmlStrndup(ctxt->cur, count);
9730 ctxt->cur = in;
9731 return(ret);
9732 }
9733 }
9734 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009735}
9736
Daniel Veillard2156a562001-04-28 12:24:34 +00009737
Owen Taylor3473f882001-02-23 17:55:21 +00009738/**
9739 * xmlXPathParseQName:
9740 * @ctxt: the XPath Parser context
9741 * @prefix: a xmlChar **
9742 *
9743 * parse an XML qualified name
9744 *
9745 * [NS 5] QName ::= (Prefix ':')? LocalPart
9746 *
9747 * [NS 6] Prefix ::= NCName
9748 *
9749 * [NS 7] LocalPart ::= NCName
9750 *
9751 * Returns the function returns the local part, and prefix is updated
9752 * to get the Prefix if any.
9753 */
9754
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009755static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009756xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9757 xmlChar *ret = NULL;
9758
9759 *prefix = NULL;
9760 ret = xmlXPathParseNCName(ctxt);
9761 if (CUR == ':') {
9762 *prefix = ret;
9763 NEXT;
9764 ret = xmlXPathParseNCName(ctxt);
9765 }
9766 return(ret);
9767}
9768
9769/**
9770 * xmlXPathParseName:
9771 * @ctxt: the XPath Parser context
9772 *
9773 * parse an XML name
9774 *
9775 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9776 * CombiningChar | Extender
9777 *
9778 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9779 *
9780 * Returns the namespace name or NULL
9781 */
9782
9783xmlChar *
9784xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009785 const xmlChar *in;
9786 xmlChar *ret;
9787 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009788
Daniel Veillarda82b1822004-11-08 16:24:57 +00009789 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009790 /*
9791 * Accelerator for simple ASCII names
9792 */
9793 in = ctxt->cur;
9794 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9795 ((*in >= 0x41) && (*in <= 0x5A)) ||
9796 (*in == '_') || (*in == ':')) {
9797 in++;
9798 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9799 ((*in >= 0x41) && (*in <= 0x5A)) ||
9800 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009801 (*in == '_') || (*in == '-') ||
9802 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009803 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009804 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009805 count = in - ctxt->cur;
9806 ret = xmlStrndup(ctxt->cur, count);
9807 ctxt->cur = in;
9808 return(ret);
9809 }
9810 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009811 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009812}
9813
Daniel Veillard61d80a22001-04-27 17:13:01 +00009814static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009815xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009816 xmlChar buf[XML_MAX_NAMELEN + 5];
9817 int len = 0, l;
9818 int c;
9819
9820 /*
9821 * Handler for more complex cases
9822 */
9823 c = CUR_CHAR(l);
9824 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009825 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9826 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009827 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009828 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009829 return(NULL);
9830 }
9831
9832 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9833 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
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 COPY_BUF(l,buf,len,c);
9839 NEXTL(l);
9840 c = CUR_CHAR(l);
9841 if (len >= XML_MAX_NAMELEN) {
9842 /*
9843 * Okay someone managed to make a huge name, so he's ready to pay
9844 * for the processing speed.
9845 */
9846 xmlChar *buffer;
9847 int max = len * 2;
9848
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009849 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009850 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009851 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009852 }
9853 memcpy(buffer, buf, len);
9854 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9855 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009856 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009857 (IS_COMBINING(c)) ||
9858 (IS_EXTENDER(c))) {
9859 if (len + 10 > max) {
9860 max *= 2;
9861 buffer = (xmlChar *) xmlRealloc(buffer,
9862 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009863 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009864 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009865 }
9866 }
9867 COPY_BUF(l,buffer,len,c);
9868 NEXTL(l);
9869 c = CUR_CHAR(l);
9870 }
9871 buffer[len] = 0;
9872 return(buffer);
9873 }
9874 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009875 if (len == 0)
9876 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009877 return(xmlStrndup(buf, len));
9878}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009879
9880#define MAX_FRAC 20
9881
William M. Brack372a4452004-02-17 13:09:23 +00009882/*
9883 * These are used as divisors for the fractional part of a number.
9884 * Since the table includes 1.0 (representing '0' fractional digits),
9885 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9886 */
9887static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009888 1.0, 10.0, 100.0, 1000.0, 10000.0,
9889 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9890 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9891 100000000000000.0,
9892 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009893 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009894};
9895
Owen Taylor3473f882001-02-23 17:55:21 +00009896/**
9897 * xmlXPathStringEvalNumber:
9898 * @str: A string to scan
9899 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009900 * [30a] Float ::= Number ('e' Digits?)?
9901 *
Owen Taylor3473f882001-02-23 17:55:21 +00009902 * [30] Number ::= Digits ('.' Digits?)?
9903 * | '.' Digits
9904 * [31] Digits ::= [0-9]+
9905 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009906 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009907 * In complement of the Number expression, this function also handles
9908 * negative values : '-' Number.
9909 *
9910 * Returns the double value.
9911 */
9912double
9913xmlXPathStringEvalNumber(const xmlChar *str) {
9914 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009915 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009916 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009917 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009918 int exponent = 0;
9919 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009920#ifdef __GNUC__
9921 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009922 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009923#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009924 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009925 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009926 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9927 return(xmlXPathNAN);
9928 }
9929 if (*cur == '-') {
9930 isneg = 1;
9931 cur++;
9932 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009933
9934#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009935 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009936 * tmp/temp is a workaround against a gcc compiler bug
9937 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009938 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009939 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009940 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009941 ret = ret * 10;
9942 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009943 ok = 1;
9944 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009945 temp = (double) tmp;
9946 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009947 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009948#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009949 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009950 while ((*cur >= '0') && (*cur <= '9')) {
9951 ret = ret * 10 + (*cur - '0');
9952 ok = 1;
9953 cur++;
9954 }
9955#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009956
Owen Taylor3473f882001-02-23 17:55:21 +00009957 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009958 int v, frac = 0;
9959 double fraction = 0;
9960
Owen Taylor3473f882001-02-23 17:55:21 +00009961 cur++;
9962 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9963 return(xmlXPathNAN);
9964 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009965 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9966 v = (*cur - '0');
9967 fraction = fraction * 10 + v;
9968 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009969 cur++;
9970 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009971 fraction /= my_pow10[frac];
9972 ret = ret + fraction;
9973 while ((*cur >= '0') && (*cur <= '9'))
9974 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009975 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009976 if ((*cur == 'e') || (*cur == 'E')) {
9977 cur++;
9978 if (*cur == '-') {
9979 is_exponent_negative = 1;
9980 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009981 } else if (*cur == '+') {
9982 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009983 }
9984 while ((*cur >= '0') && (*cur <= '9')) {
9985 exponent = exponent * 10 + (*cur - '0');
9986 cur++;
9987 }
9988 }
William M. Brack76e95df2003-10-18 16:20:14 +00009989 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009990 if (*cur != 0) return(xmlXPathNAN);
9991 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009992 if (is_exponent_negative) exponent = -exponent;
9993 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009994 return(ret);
9995}
9996
9997/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009998 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009999 * @ctxt: the XPath Parser context
10000 *
10001 * [30] Number ::= Digits ('.' Digits?)?
10002 * | '.' Digits
10003 * [31] Digits ::= [0-9]+
10004 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010005 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010006 *
10007 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010008static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010009xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10010{
Owen Taylor3473f882001-02-23 17:55:21 +000010011 double ret = 0.0;
10012 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +000010013 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010014 int exponent = 0;
10015 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010016#ifdef __GNUC__
10017 unsigned long tmp = 0;
10018 double temp;
10019#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010020
10021 CHECK_ERROR;
10022 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10023 XP_ERROR(XPATH_NUMBER_ERROR);
10024 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010025#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010026 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010027 * tmp/temp is a workaround against a gcc compiler bug
10028 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010029 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010030 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010031 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010032 ret = ret * 10;
10033 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010034 ok = 1;
10035 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010036 temp = (double) tmp;
10037 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010038 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010039#else
10040 ret = 0;
10041 while ((CUR >= '0') && (CUR <= '9')) {
10042 ret = ret * 10 + (CUR - '0');
10043 ok = 1;
10044 NEXT;
10045 }
10046#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010047 if (CUR == '.') {
10048 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010049 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10050 XP_ERROR(XPATH_NUMBER_ERROR);
10051 }
10052 while ((CUR >= '0') && (CUR <= '9')) {
10053 mult /= 10;
10054 ret = ret + (CUR - '0') * mult;
10055 NEXT;
10056 }
Owen Taylor3473f882001-02-23 17:55:21 +000010057 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010058 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010059 NEXT;
10060 if (CUR == '-') {
10061 is_exponent_negative = 1;
10062 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010063 } else if (CUR == '+') {
10064 NEXT;
10065 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010066 while ((CUR >= '0') && (CUR <= '9')) {
10067 exponent = exponent * 10 + (CUR - '0');
10068 NEXT;
10069 }
10070 if (is_exponent_negative)
10071 exponent = -exponent;
10072 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010073 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010074 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010075 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010076}
10077
10078/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010079 * xmlXPathParseLiteral:
10080 * @ctxt: the XPath Parser context
10081 *
10082 * Parse a Literal
10083 *
10084 * [29] Literal ::= '"' [^"]* '"'
10085 * | "'" [^']* "'"
10086 *
10087 * Returns the value found or NULL in case of error
10088 */
10089static xmlChar *
10090xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10091 const xmlChar *q;
10092 xmlChar *ret = NULL;
10093
10094 if (CUR == '"') {
10095 NEXT;
10096 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010097 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010098 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010099 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010100 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010101 } else {
10102 ret = xmlStrndup(q, CUR_PTR - q);
10103 NEXT;
10104 }
10105 } else if (CUR == '\'') {
10106 NEXT;
10107 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010108 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010109 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010110 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010111 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010112 } else {
10113 ret = xmlStrndup(q, CUR_PTR - q);
10114 NEXT;
10115 }
10116 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010117 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010118 }
10119 return(ret);
10120}
10121
10122/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010123 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010124 * @ctxt: the XPath Parser context
10125 *
10126 * Parse a Literal and push it on the stack.
10127 *
10128 * [29] Literal ::= '"' [^"]* '"'
10129 * | "'" [^']* "'"
10130 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010131 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010132 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010133static void
10134xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010135 const xmlChar *q;
10136 xmlChar *ret = NULL;
10137
10138 if (CUR == '"') {
10139 NEXT;
10140 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010141 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010142 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010143 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010144 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10145 } else {
10146 ret = xmlStrndup(q, CUR_PTR - q);
10147 NEXT;
10148 }
10149 } else if (CUR == '\'') {
10150 NEXT;
10151 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010152 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010153 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010154 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010155 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10156 } else {
10157 ret = xmlStrndup(q, CUR_PTR - q);
10158 NEXT;
10159 }
10160 } else {
10161 XP_ERROR(XPATH_START_LITERAL_ERROR);
10162 }
10163 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010164 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010165 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010166 xmlFree(ret);
10167}
10168
10169/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010170 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010171 * @ctxt: the XPath Parser context
10172 *
10173 * Parse a VariableReference, evaluate it and push it on the stack.
10174 *
10175 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010176 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010177 * of any of the types that are possible for the value of an expression,
10178 * and may also be of additional types not specified here.
10179 *
10180 * Early evaluation is possible since:
10181 * The variable bindings [...] used to evaluate a subexpression are
10182 * always the same as those used to evaluate the containing expression.
10183 *
10184 * [36] VariableReference ::= '$' QName
10185 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010186static void
10187xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010188 xmlChar *name;
10189 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010190
10191 SKIP_BLANKS;
10192 if (CUR != '$') {
10193 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10194 }
10195 NEXT;
10196 name = xmlXPathParseQName(ctxt, &prefix);
10197 if (name == NULL) {
10198 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10199 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010200 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010201 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10202 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010203 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010204 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10205 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10206 }
Owen Taylor3473f882001-02-23 17:55:21 +000010207}
10208
10209/**
10210 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010211 * @name: a name string
10212 *
10213 * Is the name given a NodeType one.
10214 *
10215 * [38] NodeType ::= 'comment'
10216 * | 'text'
10217 * | 'processing-instruction'
10218 * | 'node'
10219 *
10220 * Returns 1 if true 0 otherwise
10221 */
10222int
10223xmlXPathIsNodeType(const xmlChar *name) {
10224 if (name == NULL)
10225 return(0);
10226
Daniel Veillard1971ee22002-01-31 20:29:19 +000010227 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010228 return(1);
10229 if (xmlStrEqual(name, BAD_CAST "text"))
10230 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010231 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010232 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010233 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010234 return(1);
10235 return(0);
10236}
10237
10238/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010239 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010240 * @ctxt: the XPath Parser context
10241 *
10242 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10243 * [17] Argument ::= Expr
10244 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010245 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010246 * pushed on the stack
10247 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010248static void
10249xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010250 xmlChar *name;
10251 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010252 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010253 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010254
10255 name = xmlXPathParseQName(ctxt, &prefix);
10256 if (name == NULL) {
10257 XP_ERROR(XPATH_EXPR_ERROR);
10258 }
10259 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010260#ifdef DEBUG_EXPR
10261 if (prefix == NULL)
10262 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10263 name);
10264 else
10265 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10266 prefix, name);
10267#endif
10268
Owen Taylor3473f882001-02-23 17:55:21 +000010269 if (CUR != '(') {
10270 XP_ERROR(XPATH_EXPR_ERROR);
10271 }
10272 NEXT;
10273 SKIP_BLANKS;
10274
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010275 /*
10276 * Optimization for count(): we don't need the node-set to be sorted.
10277 */
10278 if ((prefix == NULL) && (name[0] == 'c') &&
10279 xmlStrEqual(name, BAD_CAST "count"))
10280 {
10281 sort = 0;
10282 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010283 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010284 if (CUR != ')') {
10285 while (CUR != 0) {
10286 int op1 = ctxt->comp->last;
10287 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010288 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010289 CHECK_ERROR;
10290 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10291 nbargs++;
10292 if (CUR == ')') break;
10293 if (CUR != ',') {
10294 XP_ERROR(XPATH_EXPR_ERROR);
10295 }
10296 NEXT;
10297 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010298 }
Owen Taylor3473f882001-02-23 17:55:21 +000010299 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010300 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10301 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010302 NEXT;
10303 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010304}
10305
10306/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010307 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010308 * @ctxt: the XPath Parser context
10309 *
10310 * [15] PrimaryExpr ::= VariableReference
10311 * | '(' Expr ')'
10312 * | Literal
10313 * | Number
10314 * | FunctionCall
10315 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010317 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010318static void
10319xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010320 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010321 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010322 else if (CUR == '(') {
10323 NEXT;
10324 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010325 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010326 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010327 if (CUR != ')') {
10328 XP_ERROR(XPATH_EXPR_ERROR);
10329 }
10330 NEXT;
10331 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010332 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010333 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010334 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010335 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010336 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010337 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010338 }
10339 SKIP_BLANKS;
10340}
10341
10342/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010343 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010344 * @ctxt: the XPath Parser context
10345 *
10346 * [20] FilterExpr ::= PrimaryExpr
10347 * | FilterExpr Predicate
10348 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010349 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010350 * Square brackets are used to filter expressions in the same way that
10351 * they are used in location paths. It is an error if the expression to
10352 * be filtered does not evaluate to a node-set. The context node list
10353 * used for evaluating the expression in square brackets is the node-set
10354 * to be filtered listed in document order.
10355 */
10356
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010357static void
10358xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10359 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010360 CHECK_ERROR;
10361 SKIP_BLANKS;
10362
10363 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010364 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010365 SKIP_BLANKS;
10366 }
10367
10368
10369}
10370
10371/**
10372 * xmlXPathScanName:
10373 * @ctxt: the XPath Parser context
10374 *
10375 * Trickery: parse an XML name but without consuming the input flow
10376 * Needed to avoid insanity in the parser state.
10377 *
10378 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10379 * CombiningChar | Extender
10380 *
10381 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10382 *
10383 * [6] Names ::= Name (S Name)*
10384 *
10385 * Returns the Name parsed or NULL
10386 */
10387
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010388static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010389xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010390 int len = 0, l;
10391 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010392 const xmlChar *cur;
10393 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010394
Daniel Veillard03226812004-11-01 14:55:21 +000010395 cur = ctxt->cur;
10396
10397 c = CUR_CHAR(l);
10398 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10399 (!IS_LETTER(c) && (c != '_') &&
10400 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010401 return(NULL);
10402 }
10403
Daniel Veillard03226812004-11-01 14:55:21 +000010404 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10405 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10406 (c == '.') || (c == '-') ||
10407 (c == '_') || (c == ':') ||
10408 (IS_COMBINING(c)) ||
10409 (IS_EXTENDER(c)))) {
10410 len += l;
10411 NEXTL(l);
10412 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010413 }
Daniel Veillard03226812004-11-01 14:55:21 +000010414 ret = xmlStrndup(cur, ctxt->cur - cur);
10415 ctxt->cur = cur;
10416 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010417}
10418
10419/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010420 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010421 * @ctxt: the XPath Parser context
10422 *
10423 * [19] PathExpr ::= LocationPath
10424 * | FilterExpr
10425 * | FilterExpr '/' RelativeLocationPath
10426 * | FilterExpr '//' RelativeLocationPath
10427 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010428 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010429 * The / operator and // operators combine an arbitrary expression
10430 * and a relative location path. It is an error if the expression
10431 * does not evaluate to a node-set.
10432 * The / operator does composition in the same way as when / is
10433 * used in a location path. As in location paths, // is short for
10434 * /descendant-or-self::node()/.
10435 */
10436
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010437static void
10438xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010439 int lc = 1; /* Should we branch to LocationPath ? */
10440 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10441
10442 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010443 if ((CUR == '$') || (CUR == '(') ||
10444 (IS_ASCII_DIGIT(CUR)) ||
10445 (CUR == '\'') || (CUR == '"') ||
10446 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010447 lc = 0;
10448 } else if (CUR == '*') {
10449 /* relative or absolute location path */
10450 lc = 1;
10451 } else if (CUR == '/') {
10452 /* relative or absolute location path */
10453 lc = 1;
10454 } else if (CUR == '@') {
10455 /* relative abbreviated attribute location path */
10456 lc = 1;
10457 } else if (CUR == '.') {
10458 /* relative abbreviated attribute location path */
10459 lc = 1;
10460 } else {
10461 /*
10462 * Problem is finding if we have a name here whether it's:
10463 * - a nodetype
10464 * - a function call in which case it's followed by '('
10465 * - an axis in which case it's followed by ':'
10466 * - a element name
10467 * We do an a priori analysis here rather than having to
10468 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010469 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010470 * read/write/debug.
10471 */
10472 SKIP_BLANKS;
10473 name = xmlXPathScanName(ctxt);
10474 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10475#ifdef DEBUG_STEP
10476 xmlGenericError(xmlGenericErrorContext,
10477 "PathExpr: Axis\n");
10478#endif
10479 lc = 1;
10480 xmlFree(name);
10481 } else if (name != NULL) {
10482 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010483
10484
10485 while (NXT(len) != 0) {
10486 if (NXT(len) == '/') {
10487 /* element name */
10488#ifdef DEBUG_STEP
10489 xmlGenericError(xmlGenericErrorContext,
10490 "PathExpr: AbbrRelLocation\n");
10491#endif
10492 lc = 1;
10493 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010494 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010495 /* ignore blanks */
10496 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010497 } else if (NXT(len) == ':') {
10498#ifdef DEBUG_STEP
10499 xmlGenericError(xmlGenericErrorContext,
10500 "PathExpr: AbbrRelLocation\n");
10501#endif
10502 lc = 1;
10503 break;
10504 } else if ((NXT(len) == '(')) {
10505 /* Note Type or Function */
10506 if (xmlXPathIsNodeType(name)) {
10507#ifdef DEBUG_STEP
10508 xmlGenericError(xmlGenericErrorContext,
10509 "PathExpr: Type search\n");
10510#endif
10511 lc = 1;
10512 } else {
10513#ifdef DEBUG_STEP
10514 xmlGenericError(xmlGenericErrorContext,
10515 "PathExpr: function call\n");
10516#endif
10517 lc = 0;
10518 }
10519 break;
10520 } else if ((NXT(len) == '[')) {
10521 /* element name */
10522#ifdef DEBUG_STEP
10523 xmlGenericError(xmlGenericErrorContext,
10524 "PathExpr: AbbrRelLocation\n");
10525#endif
10526 lc = 1;
10527 break;
10528 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10529 (NXT(len) == '=')) {
10530 lc = 1;
10531 break;
10532 } else {
10533 lc = 1;
10534 break;
10535 }
10536 len++;
10537 }
10538 if (NXT(len) == 0) {
10539#ifdef DEBUG_STEP
10540 xmlGenericError(xmlGenericErrorContext,
10541 "PathExpr: AbbrRelLocation\n");
10542#endif
10543 /* element name */
10544 lc = 1;
10545 }
10546 xmlFree(name);
10547 } else {
William M. Brack08171912003-12-29 02:52:11 +000010548 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010549 XP_ERROR(XPATH_EXPR_ERROR);
10550 }
10551 }
10552
10553 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010554 if (CUR == '/') {
10555 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10556 } else {
10557 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010558 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010559 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010560 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010561 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010562 CHECK_ERROR;
10563 if ((CUR == '/') && (NXT(1) == '/')) {
10564 SKIP(2);
10565 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010566
10567 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10568 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10569 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10570
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010571 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010572 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010573 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010574 }
10575 }
10576 SKIP_BLANKS;
10577}
10578
10579/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010580 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010581 * @ctxt: the XPath Parser context
10582 *
10583 * [18] UnionExpr ::= PathExpr
10584 * | UnionExpr '|' PathExpr
10585 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010586 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010587 */
10588
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010589static void
10590xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10591 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010592 CHECK_ERROR;
10593 SKIP_BLANKS;
10594 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595 int op1 = ctxt->comp->last;
10596 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010597
10598 NEXT;
10599 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010600 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010601
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010602 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10603
Owen Taylor3473f882001-02-23 17:55:21 +000010604 SKIP_BLANKS;
10605 }
Owen Taylor3473f882001-02-23 17:55:21 +000010606}
10607
10608/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010609 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010610 * @ctxt: the XPath Parser context
10611 *
10612 * [27] UnaryExpr ::= UnionExpr
10613 * | '-' UnaryExpr
10614 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010615 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010616 */
10617
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010618static void
10619xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010620 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010621 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010622
10623 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010624 while (CUR == '-') {
10625 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010626 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010627 NEXT;
10628 SKIP_BLANKS;
10629 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010630
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010631 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010632 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010633 if (found) {
10634 if (minus)
10635 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10636 else
10637 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010638 }
10639}
10640
10641/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010642 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010643 * @ctxt: the XPath Parser context
10644 *
10645 * [26] MultiplicativeExpr ::= UnaryExpr
10646 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10647 * | MultiplicativeExpr 'div' UnaryExpr
10648 * | MultiplicativeExpr 'mod' UnaryExpr
10649 * [34] MultiplyOperator ::= '*'
10650 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010651 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010652 */
10653
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010654static void
10655xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10656 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010657 CHECK_ERROR;
10658 SKIP_BLANKS;
10659 while ((CUR == '*') ||
10660 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10661 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10662 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010663 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010664
10665 if (CUR == '*') {
10666 op = 0;
10667 NEXT;
10668 } else if (CUR == 'd') {
10669 op = 1;
10670 SKIP(3);
10671 } else if (CUR == 'm') {
10672 op = 2;
10673 SKIP(3);
10674 }
10675 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010676 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010677 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010678 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010679 SKIP_BLANKS;
10680 }
10681}
10682
10683/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010684 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010685 * @ctxt: the XPath Parser context
10686 *
10687 * [25] AdditiveExpr ::= MultiplicativeExpr
10688 * | AdditiveExpr '+' MultiplicativeExpr
10689 * | AdditiveExpr '-' MultiplicativeExpr
10690 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010691 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010692 */
10693
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010694static void
10695xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010696
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010697 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010698 CHECK_ERROR;
10699 SKIP_BLANKS;
10700 while ((CUR == '+') || (CUR == '-')) {
10701 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010702 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010703
10704 if (CUR == '+') plus = 1;
10705 else plus = 0;
10706 NEXT;
10707 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010708 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010709 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010710 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010711 SKIP_BLANKS;
10712 }
10713}
10714
10715/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010716 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010717 * @ctxt: the XPath Parser context
10718 *
10719 * [24] RelationalExpr ::= AdditiveExpr
10720 * | RelationalExpr '<' AdditiveExpr
10721 * | RelationalExpr '>' AdditiveExpr
10722 * | RelationalExpr '<=' AdditiveExpr
10723 * | RelationalExpr '>=' AdditiveExpr
10724 *
10725 * A <= B > C is allowed ? Answer from James, yes with
10726 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10727 * which is basically what got implemented.
10728 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010729 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010730 * on the stack
10731 */
10732
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010733static void
10734xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10735 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010736 CHECK_ERROR;
10737 SKIP_BLANKS;
10738 while ((CUR == '<') ||
10739 (CUR == '>') ||
10740 ((CUR == '<') && (NXT(1) == '=')) ||
10741 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010742 int inf, strict;
10743 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010744
10745 if (CUR == '<') inf = 1;
10746 else inf = 0;
10747 if (NXT(1) == '=') strict = 0;
10748 else strict = 1;
10749 NEXT;
10750 if (!strict) NEXT;
10751 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010752 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010753 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010754 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010755 SKIP_BLANKS;
10756 }
10757}
10758
10759/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010760 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010761 * @ctxt: the XPath Parser context
10762 *
10763 * [23] EqualityExpr ::= RelationalExpr
10764 * | EqualityExpr '=' RelationalExpr
10765 * | EqualityExpr '!=' RelationalExpr
10766 *
10767 * A != B != C is allowed ? Answer from James, yes with
10768 * (RelationalExpr = RelationalExpr) = RelationalExpr
10769 * (RelationalExpr != RelationalExpr) != RelationalExpr
10770 * which is basically what got implemented.
10771 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010772 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010773 *
10774 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010775static void
10776xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10777 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010778 CHECK_ERROR;
10779 SKIP_BLANKS;
10780 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010781 int eq;
10782 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010783
10784 if (CUR == '=') eq = 1;
10785 else eq = 0;
10786 NEXT;
10787 if (!eq) NEXT;
10788 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010789 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010790 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010791 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010792 SKIP_BLANKS;
10793 }
10794}
10795
10796/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010798 * @ctxt: the XPath Parser context
10799 *
10800 * [22] AndExpr ::= EqualityExpr
10801 * | AndExpr 'and' EqualityExpr
10802 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010803 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010804 *
10805 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010806static void
10807xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10808 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010809 CHECK_ERROR;
10810 SKIP_BLANKS;
10811 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010812 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010813 SKIP(3);
10814 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010815 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010816 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010818 SKIP_BLANKS;
10819 }
10820}
10821
10822/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010823 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010824 * @ctxt: the XPath Parser context
10825 *
10826 * [14] Expr ::= OrExpr
10827 * [21] OrExpr ::= AndExpr
10828 * | OrExpr 'or' AndExpr
10829 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010830 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010831 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010832static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010833xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010834 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010835 CHECK_ERROR;
10836 SKIP_BLANKS;
10837 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010838 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010839 SKIP(2);
10840 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010841 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010842 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010843 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10844 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010845 SKIP_BLANKS;
10846 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010847 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010848 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010849 /*
10850 * This is the main place to eliminate sorting for
10851 * operations which don't require a sorted node-set.
10852 * E.g. count().
10853 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010854 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10855 }
Owen Taylor3473f882001-02-23 17:55:21 +000010856}
10857
10858/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010859 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010860 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010861 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010862 *
10863 * [8] Predicate ::= '[' PredicateExpr ']'
10864 * [9] PredicateExpr ::= Expr
10865 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010866 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010867 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010868static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010869xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010870 int op1 = ctxt->comp->last;
10871
10872 SKIP_BLANKS;
10873 if (CUR != '[') {
10874 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10875 }
10876 NEXT;
10877 SKIP_BLANKS;
10878
10879 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010880 /*
10881 * This call to xmlXPathCompileExpr() will deactivate sorting
10882 * of the predicate result.
10883 * TODO: Sorting is still activated for filters, since I'm not
10884 * sure if needed. Normally sorting should not be needed, since
10885 * a filter can only diminish the number of items in a sequence,
10886 * but won't change its order; so if the initial sequence is sorted,
10887 * subsequent sorting is not needed.
10888 */
10889 if (! filter)
10890 xmlXPathCompileExpr(ctxt, 0);
10891 else
10892 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010893 CHECK_ERROR;
10894
10895 if (CUR != ']') {
10896 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10897 }
10898
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010899 if (filter)
10900 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10901 else
10902 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010903
10904 NEXT;
10905 SKIP_BLANKS;
10906}
10907
10908/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010909 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010910 * @ctxt: the XPath Parser context
10911 * @test: pointer to a xmlXPathTestVal
10912 * @type: pointer to a xmlXPathTypeVal
10913 * @prefix: placeholder for a possible name prefix
10914 *
10915 * [7] NodeTest ::= NameTest
10916 * | NodeType '(' ')'
10917 * | 'processing-instruction' '(' Literal ')'
10918 *
10919 * [37] NameTest ::= '*'
10920 * | NCName ':' '*'
10921 * | QName
10922 * [38] NodeType ::= 'comment'
10923 * | 'text'
10924 * | 'processing-instruction'
10925 * | 'node'
10926 *
William M. Brack08171912003-12-29 02:52:11 +000010927 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010928 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010929static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010930xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10931 xmlXPathTypeVal *type, const xmlChar **prefix,
10932 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010933 int blanks;
10934
10935 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10936 STRANGE;
10937 return(NULL);
10938 }
William M. Brack78637da2003-07-31 14:47:38 +000010939 *type = (xmlXPathTypeVal) 0;
10940 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010941 *prefix = NULL;
10942 SKIP_BLANKS;
10943
10944 if ((name == NULL) && (CUR == '*')) {
10945 /*
10946 * All elements
10947 */
10948 NEXT;
10949 *test = NODE_TEST_ALL;
10950 return(NULL);
10951 }
10952
10953 if (name == NULL)
10954 name = xmlXPathParseNCName(ctxt);
10955 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010956 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010957 }
10958
William M. Brack76e95df2003-10-18 16:20:14 +000010959 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010960 SKIP_BLANKS;
10961 if (CUR == '(') {
10962 NEXT;
10963 /*
10964 * NodeType or PI search
10965 */
10966 if (xmlStrEqual(name, BAD_CAST "comment"))
10967 *type = NODE_TYPE_COMMENT;
10968 else if (xmlStrEqual(name, BAD_CAST "node"))
10969 *type = NODE_TYPE_NODE;
10970 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10971 *type = NODE_TYPE_PI;
10972 else if (xmlStrEqual(name, BAD_CAST "text"))
10973 *type = NODE_TYPE_TEXT;
10974 else {
10975 if (name != NULL)
10976 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010977 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010978 }
10979
10980 *test = NODE_TEST_TYPE;
10981
10982 SKIP_BLANKS;
10983 if (*type == NODE_TYPE_PI) {
10984 /*
10985 * Specific case: search a PI by name.
10986 */
Owen Taylor3473f882001-02-23 17:55:21 +000010987 if (name != NULL)
10988 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010989 name = NULL;
10990 if (CUR != ')') {
10991 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010992 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010993 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010994 SKIP_BLANKS;
10995 }
Owen Taylor3473f882001-02-23 17:55:21 +000010996 }
10997 if (CUR != ')') {
10998 if (name != NULL)
10999 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000011000 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011001 }
11002 NEXT;
11003 return(name);
11004 }
11005 *test = NODE_TEST_NAME;
11006 if ((!blanks) && (CUR == ':')) {
11007 NEXT;
11008
11009 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011010 * Since currently the parser context don't have a
11011 * namespace list associated:
11012 * The namespace name for this prefix can be computed
11013 * only at evaluation time. The compilation is done
11014 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011015 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011016#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011017 *prefix = xmlXPathNsLookup(ctxt->context, name);
11018 if (name != NULL)
11019 xmlFree(name);
11020 if (*prefix == NULL) {
11021 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11022 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011023#else
11024 *prefix = name;
11025#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011026
11027 if (CUR == '*') {
11028 /*
11029 * All elements
11030 */
11031 NEXT;
11032 *test = NODE_TEST_ALL;
11033 return(NULL);
11034 }
11035
11036 name = xmlXPathParseNCName(ctxt);
11037 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011038 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011039 }
11040 }
11041 return(name);
11042}
11043
11044/**
11045 * xmlXPathIsAxisName:
11046 * @name: a preparsed name token
11047 *
11048 * [6] AxisName ::= 'ancestor'
11049 * | 'ancestor-or-self'
11050 * | 'attribute'
11051 * | 'child'
11052 * | 'descendant'
11053 * | 'descendant-or-self'
11054 * | 'following'
11055 * | 'following-sibling'
11056 * | 'namespace'
11057 * | 'parent'
11058 * | 'preceding'
11059 * | 'preceding-sibling'
11060 * | 'self'
11061 *
11062 * Returns the axis or 0
11063 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011064static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011065xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011066 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011067 switch (name[0]) {
11068 case 'a':
11069 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11070 ret = AXIS_ANCESTOR;
11071 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11072 ret = AXIS_ANCESTOR_OR_SELF;
11073 if (xmlStrEqual(name, BAD_CAST "attribute"))
11074 ret = AXIS_ATTRIBUTE;
11075 break;
11076 case 'c':
11077 if (xmlStrEqual(name, BAD_CAST "child"))
11078 ret = AXIS_CHILD;
11079 break;
11080 case 'd':
11081 if (xmlStrEqual(name, BAD_CAST "descendant"))
11082 ret = AXIS_DESCENDANT;
11083 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11084 ret = AXIS_DESCENDANT_OR_SELF;
11085 break;
11086 case 'f':
11087 if (xmlStrEqual(name, BAD_CAST "following"))
11088 ret = AXIS_FOLLOWING;
11089 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11090 ret = AXIS_FOLLOWING_SIBLING;
11091 break;
11092 case 'n':
11093 if (xmlStrEqual(name, BAD_CAST "namespace"))
11094 ret = AXIS_NAMESPACE;
11095 break;
11096 case 'p':
11097 if (xmlStrEqual(name, BAD_CAST "parent"))
11098 ret = AXIS_PARENT;
11099 if (xmlStrEqual(name, BAD_CAST "preceding"))
11100 ret = AXIS_PRECEDING;
11101 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11102 ret = AXIS_PRECEDING_SIBLING;
11103 break;
11104 case 's':
11105 if (xmlStrEqual(name, BAD_CAST "self"))
11106 ret = AXIS_SELF;
11107 break;
11108 }
11109 return(ret);
11110}
11111
11112/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011113 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011114 * @ctxt: the XPath Parser context
11115 *
11116 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11117 * | AbbreviatedStep
11118 *
11119 * [12] AbbreviatedStep ::= '.' | '..'
11120 *
11121 * [5] AxisSpecifier ::= AxisName '::'
11122 * | AbbreviatedAxisSpecifier
11123 *
11124 * [13] AbbreviatedAxisSpecifier ::= '@'?
11125 *
11126 * Modified for XPtr range support as:
11127 *
11128 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11129 * | AbbreviatedStep
11130 * | 'range-to' '(' Expr ')' Predicate*
11131 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011132 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011133 * A location step of . is short for self::node(). This is
11134 * particularly useful in conjunction with //. For example, the
11135 * location path .//para is short for
11136 * self::node()/descendant-or-self::node()/child::para
11137 * and so will select all para descendant elements of the context
11138 * node.
11139 * Similarly, a location step of .. is short for parent::node().
11140 * For example, ../title is short for parent::node()/child::title
11141 * and so will select the title children of the parent of the context
11142 * node.
11143 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011144static void
11145xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011146#ifdef LIBXML_XPTR_ENABLED
11147 int rangeto = 0;
11148 int op2 = -1;
11149#endif
11150
Owen Taylor3473f882001-02-23 17:55:21 +000011151 SKIP_BLANKS;
11152 if ((CUR == '.') && (NXT(1) == '.')) {
11153 SKIP(2);
11154 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011155 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11156 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011157 } else if (CUR == '.') {
11158 NEXT;
11159 SKIP_BLANKS;
11160 } else {
11161 xmlChar *name = NULL;
11162 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011163 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011164 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011165 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011166 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011167
11168 /*
11169 * The modification needed for XPointer change to the production
11170 */
11171#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011172 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011173 name = xmlXPathParseNCName(ctxt);
11174 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011175 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011176 xmlFree(name);
11177 SKIP_BLANKS;
11178 if (CUR != '(') {
11179 XP_ERROR(XPATH_EXPR_ERROR);
11180 }
11181 NEXT;
11182 SKIP_BLANKS;
11183
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011184 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011185 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011186 CHECK_ERROR;
11187
11188 SKIP_BLANKS;
11189 if (CUR != ')') {
11190 XP_ERROR(XPATH_EXPR_ERROR);
11191 }
11192 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011193 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011194 goto eval_predicates;
11195 }
11196 }
11197#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011198 if (CUR == '*') {
11199 axis = AXIS_CHILD;
11200 } else {
11201 if (name == NULL)
11202 name = xmlXPathParseNCName(ctxt);
11203 if (name != NULL) {
11204 axis = xmlXPathIsAxisName(name);
11205 if (axis != 0) {
11206 SKIP_BLANKS;
11207 if ((CUR == ':') && (NXT(1) == ':')) {
11208 SKIP(2);
11209 xmlFree(name);
11210 name = NULL;
11211 } else {
11212 /* an element name can conflict with an axis one :-\ */
11213 axis = AXIS_CHILD;
11214 }
Owen Taylor3473f882001-02-23 17:55:21 +000011215 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011216 axis = AXIS_CHILD;
11217 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011218 } else if (CUR == '@') {
11219 NEXT;
11220 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011221 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011222 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011223 }
Owen Taylor3473f882001-02-23 17:55:21 +000011224 }
11225
11226 CHECK_ERROR;
11227
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011228 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011229 if (test == 0)
11230 return;
11231
Daniel Veillarded6c5492005-07-23 15:00:22 +000011232 if ((prefix != NULL) && (ctxt->context != NULL) &&
11233 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11234 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11235 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11236 }
11237 }
Owen Taylor3473f882001-02-23 17:55:21 +000011238#ifdef DEBUG_STEP
11239 xmlGenericError(xmlGenericErrorContext,
11240 "Basis : computing new set\n");
11241#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011242
Owen Taylor3473f882001-02-23 17:55:21 +000011243#ifdef DEBUG_STEP
11244 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011245 if (ctxt->value == NULL)
11246 xmlGenericError(xmlGenericErrorContext, "no value\n");
11247 else if (ctxt->value->nodesetval == NULL)
11248 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11249 else
11250 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011251#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011252
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011253#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011254eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011255#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011256 op1 = ctxt->comp->last;
11257 ctxt->comp->last = -1;
11258
Owen Taylor3473f882001-02-23 17:55:21 +000011259 SKIP_BLANKS;
11260 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011261 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011262 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011263
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011264#ifdef LIBXML_XPTR_ENABLED
11265 if (rangeto) {
11266 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11267 } else
11268#endif
11269 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11270 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011271
Owen Taylor3473f882001-02-23 17:55:21 +000011272 }
11273#ifdef DEBUG_STEP
11274 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011275 if (ctxt->value == NULL)
11276 xmlGenericError(xmlGenericErrorContext, "no value\n");
11277 else if (ctxt->value->nodesetval == NULL)
11278 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11279 else
11280 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11281 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011282#endif
11283}
11284
11285/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011286 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011287 * @ctxt: the XPath Parser context
11288 *
11289 * [3] RelativeLocationPath ::= Step
11290 * | RelativeLocationPath '/' Step
11291 * | AbbreviatedRelativeLocationPath
11292 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11293 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011294 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011295 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011296static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011297xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011298(xmlXPathParserContextPtr ctxt) {
11299 SKIP_BLANKS;
11300 if ((CUR == '/') && (NXT(1) == '/')) {
11301 SKIP(2);
11302 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011303 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11304 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011305 } else if (CUR == '/') {
11306 NEXT;
11307 SKIP_BLANKS;
11308 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011309 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011310 SKIP_BLANKS;
11311 while (CUR == '/') {
11312 if ((CUR == '/') && (NXT(1) == '/')) {
11313 SKIP(2);
11314 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011315 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011316 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011317 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011318 } else if (CUR == '/') {
11319 NEXT;
11320 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011321 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011322 }
11323 SKIP_BLANKS;
11324 }
11325}
11326
11327/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011328 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011329 * @ctxt: the XPath Parser context
11330 *
11331 * [1] LocationPath ::= RelativeLocationPath
11332 * | AbsoluteLocationPath
11333 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11334 * | AbbreviatedAbsoluteLocationPath
11335 * [10] AbbreviatedAbsoluteLocationPath ::=
11336 * '//' RelativeLocationPath
11337 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011338 * Compile a location path
11339 *
Owen Taylor3473f882001-02-23 17:55:21 +000011340 * // is short for /descendant-or-self::node()/. For example,
11341 * //para is short for /descendant-or-self::node()/child::para and
11342 * so will select any para element in the document (even a para element
11343 * that is a document element will be selected by //para since the
11344 * document element node is a child of the root node); div//para is
11345 * short for div/descendant-or-self::node()/child::para and so will
11346 * select all para descendants of div children.
11347 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011348static void
11349xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011350 SKIP_BLANKS;
11351 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011352 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011353 } else {
11354 while (CUR == '/') {
11355 if ((CUR == '/') && (NXT(1) == '/')) {
11356 SKIP(2);
11357 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011358 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11359 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011360 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011361 } else if (CUR == '/') {
11362 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011363 SKIP_BLANKS;
11364 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011365 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011366 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011367 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011368 }
11369 }
11370 }
11371}
11372
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011373/************************************************************************
11374 * *
11375 * XPath precompiled expression evaluation *
11376 * *
11377 ************************************************************************/
11378
Daniel Veillardf06307e2001-07-03 10:35:50 +000011379static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011380xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11381
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011382#ifdef DEBUG_STEP
11383static void
11384xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11385 xmlXPathTestVal test,
11386 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011387{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011388 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011389 switch (axis) {
11390 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011391 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011392 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011393 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011394 xmlGenericError(xmlGenericErrorContext,
11395 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011396 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011397 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011399 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011400 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011401 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011402 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011403 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011404 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011405 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011406 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011407 xmlGenericError(xmlGenericErrorContext,
11408 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011409 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011410 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011411 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011412 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011413 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011414 xmlGenericError(xmlGenericErrorContext,
11415 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011416 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011417 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011418 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011419 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011420 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011421 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011422 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011423 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011424 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011425 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011426 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011427 xmlGenericError(xmlGenericErrorContext,
11428 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011429 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011430 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011431 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011432 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011433 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011434 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011435 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011436 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011437 case NODE_TEST_NONE:
11438 xmlGenericError(xmlGenericErrorContext,
11439 " searching for none !!!\n");
11440 break;
11441 case NODE_TEST_TYPE:
11442 xmlGenericError(xmlGenericErrorContext,
11443 " searching for type %d\n", type);
11444 break;
11445 case NODE_TEST_PI:
11446 xmlGenericError(xmlGenericErrorContext,
11447 " searching for PI !!!\n");
11448 break;
11449 case NODE_TEST_ALL:
11450 xmlGenericError(xmlGenericErrorContext,
11451 " searching for *\n");
11452 break;
11453 case NODE_TEST_NS:
11454 xmlGenericError(xmlGenericErrorContext,
11455 " searching for namespace %s\n",
11456 prefix);
11457 break;
11458 case NODE_TEST_NAME:
11459 xmlGenericError(xmlGenericErrorContext,
11460 " searching for name %s\n", name);
11461 if (prefix != NULL)
11462 xmlGenericError(xmlGenericErrorContext,
11463 " with namespace %s\n", prefix);
11464 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011465 }
11466 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011467}
11468#endif /* DEBUG_STEP */
11469
11470static int
11471xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11472 xmlXPathStepOpPtr op,
11473 xmlNodeSetPtr set,
11474 int contextSize,
11475 int hasNsNodes)
11476{
11477 if (op->ch1 != -1) {
11478 xmlXPathCompExprPtr comp = ctxt->comp;
11479 /*
11480 * Process inner predicates first.
11481 */
11482 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11483 /*
11484 * TODO: raise an internal error.
11485 */
11486 }
11487 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11488 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11489 CHECK_ERROR0;
11490 if (contextSize <= 0)
11491 return(0);
11492 }
11493 if (op->ch2 != -1) {
11494 xmlXPathContextPtr xpctxt = ctxt->context;
11495 xmlNodePtr contextNode, oldContextNode;
11496 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011497 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011498 xmlXPathStepOpPtr exprOp;
11499 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11500
11501#ifdef LIBXML_XPTR_ENABLED
11502 /*
11503 * URGENT TODO: Check the following:
11504 * We don't expect location sets if evaluating prediates, right?
11505 * Only filters should expect location sets, right?
11506 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011507#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011508 /*
11509 * SPEC XPath 1.0:
11510 * "For each node in the node-set to be filtered, the
11511 * PredicateExpr is evaluated with that node as the
11512 * context node, with the number of nodes in the
11513 * node-set as the context size, and with the proximity
11514 * position of the node in the node-set with respect to
11515 * the axis as the context position;"
11516 * @oldset is the node-set" to be filtered.
11517 *
11518 * SPEC XPath 1.0:
11519 * "only predicates change the context position and
11520 * context size (see [2.4 Predicates])."
11521 * Example:
11522 * node-set context pos
11523 * nA 1
11524 * nB 2
11525 * nC 3
11526 * After applying predicate [position() > 1] :
11527 * node-set context pos
11528 * nB 1
11529 * nC 2
11530 */
11531 oldContextNode = xpctxt->node;
11532 oldContextDoc = xpctxt->doc;
11533 /*
11534 * Get the expression of this predicate.
11535 */
11536 exprOp = &ctxt->comp->steps[op->ch2];
11537 newContextSize = 0;
11538 for (i = 0; i < set->nodeNr; i++) {
11539 if (set->nodeTab[i] == NULL)
11540 continue;
11541
11542 contextNode = set->nodeTab[i];
11543 xpctxt->node = contextNode;
11544 xpctxt->contextSize = contextSize;
11545 xpctxt->proximityPosition = ++contextPos;
11546
11547 /*
11548 * Also set the xpath document in case things like
11549 * key() are evaluated in the predicate.
11550 */
11551 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11552 (contextNode->doc != NULL))
11553 xpctxt->doc = contextNode->doc;
11554 /*
11555 * Evaluate the predicate expression with 1 context node
11556 * at a time; this node is packaged into a node set; this
11557 * node set is handed over to the evaluation mechanism.
11558 */
11559 if (contextObj == NULL)
11560 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11561 else
11562 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11563 contextNode);
11564
11565 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011566
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011567 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011568
William M. Brack0bcec062007-02-14 02:15:19 +000011569 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11570 xmlXPathNodeSetClear(set, hasNsNodes);
11571 newContextSize = 0;
11572 goto evaluation_exit;
11573 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011574
11575 if (res != 0) {
11576 newContextSize++;
11577 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011578 /*
11579 * Remove the entry from the initial node set.
11580 */
11581 set->nodeTab[i] = NULL;
11582 if (contextNode->type == XML_NAMESPACE_DECL)
11583 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011584 }
11585 if (ctxt->value == contextObj) {
11586 /*
11587 * Don't free the temporary XPath object holding the
11588 * context node, in order to avoid massive recreation
11589 * inside this loop.
11590 */
11591 valuePop(ctxt);
11592 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11593 } else {
11594 /*
11595 * TODO: The object was lost in the evaluation machinery.
11596 * Can this happen? Maybe in internal-error cases.
11597 */
11598 contextObj = NULL;
11599 }
11600 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011601
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011602 if (contextObj != NULL) {
11603 if (ctxt->value == contextObj)
11604 valuePop(ctxt);
11605 xmlXPathReleaseObject(xpctxt, contextObj);
11606 }
William M. Brack0bcec062007-02-14 02:15:19 +000011607evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011608 if (exprRes != NULL)
11609 xmlXPathReleaseObject(ctxt->context, exprRes);
11610 /*
11611 * Reset/invalidate the context.
11612 */
11613 xpctxt->node = oldContextNode;
11614 xpctxt->doc = oldContextDoc;
11615 xpctxt->contextSize = -1;
11616 xpctxt->proximityPosition = -1;
11617 return(newContextSize);
11618 }
11619 return(contextSize);
11620}
11621
11622static int
11623xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11624 xmlXPathStepOpPtr op,
11625 xmlNodeSetPtr set,
11626 int contextSize,
11627 int minPos,
11628 int maxPos,
11629 int hasNsNodes)
11630{
11631 if (op->ch1 != -1) {
11632 xmlXPathCompExprPtr comp = ctxt->comp;
11633 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11634 /*
11635 * TODO: raise an internal error.
11636 */
11637 }
11638 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11639 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11640 CHECK_ERROR0;
11641 if (contextSize <= 0)
11642 return(0);
11643 }
11644 /*
11645 * Check if the node set contains a sufficient number of nodes for
11646 * the requested range.
11647 */
11648 if (contextSize < minPos) {
11649 xmlXPathNodeSetClear(set, hasNsNodes);
11650 return(0);
11651 }
11652 if (op->ch2 == -1) {
11653 /*
11654 * TODO: Can this ever happen?
11655 */
11656 return (contextSize);
11657 } else {
11658 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011659 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011660 xmlXPathStepOpPtr exprOp;
11661 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11662 xmlNodePtr oldContextNode, contextNode = NULL;
11663 xmlXPathContextPtr xpctxt = ctxt->context;
11664
11665#ifdef LIBXML_XPTR_ENABLED
11666 /*
11667 * URGENT TODO: Check the following:
11668 * We don't expect location sets if evaluating prediates, right?
11669 * Only filters should expect location sets, right?
11670 */
11671#endif /* LIBXML_XPTR_ENABLED */
11672
11673 /*
11674 * Save old context.
11675 */
11676 oldContextNode = xpctxt->node;
11677 oldContextDoc = xpctxt->doc;
11678 /*
11679 * Get the expression of this predicate.
11680 */
11681 exprOp = &ctxt->comp->steps[op->ch2];
11682 for (i = 0; i < set->nodeNr; i++) {
11683 if (set->nodeTab[i] == NULL)
11684 continue;
11685
11686 contextNode = set->nodeTab[i];
11687 xpctxt->node = contextNode;
11688 xpctxt->contextSize = contextSize;
11689 xpctxt->proximityPosition = ++contextPos;
11690
11691 /*
11692 * Initialize the new set.
11693 * Also set the xpath document in case things like
11694 * key() evaluation are attempted on the predicate
11695 */
11696 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11697 (contextNode->doc != NULL))
11698 xpctxt->doc = contextNode->doc;
11699 /*
11700 * Evaluate the predicate expression with 1 context node
11701 * at a time; this node is packaged into a node set; this
11702 * node set is handed over to the evaluation mechanism.
11703 */
11704 if (contextObj == NULL)
11705 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11706 else
11707 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11708 contextNode);
11709
11710 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011711 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011712
11713 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011714 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011715
11716 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011717 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011718
11719 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011720 /*
11721 * Fits in the requested range.
11722 */
11723 newContextSize++;
11724 if (minPos == maxPos) {
11725 /*
11726 * Only 1 node was requested.
11727 */
11728 if (contextNode->type == XML_NAMESPACE_DECL) {
11729 /*
11730 * As always: take care of those nasty
11731 * namespace nodes.
11732 */
11733 set->nodeTab[i] = NULL;
11734 }
11735 xmlXPathNodeSetClear(set, hasNsNodes);
11736 set->nodeNr = 1;
11737 set->nodeTab[0] = contextNode;
11738 goto evaluation_exit;
11739 }
11740 if (pos == maxPos) {
11741 /*
11742 * We are done.
11743 */
11744 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11745 goto evaluation_exit;
11746 }
11747 } else {
11748 /*
11749 * Remove the entry from the initial node set.
11750 */
11751 set->nodeTab[i] = NULL;
11752 if (contextNode->type == XML_NAMESPACE_DECL)
11753 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11754 }
11755 if (exprRes != NULL) {
11756 xmlXPathReleaseObject(ctxt->context, exprRes);
11757 exprRes = NULL;
11758 }
11759 if (ctxt->value == contextObj) {
11760 /*
11761 * Don't free the temporary XPath object holding the
11762 * context node, in order to avoid massive recreation
11763 * inside this loop.
11764 */
11765 valuePop(ctxt);
11766 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11767 } else {
11768 /*
11769 * The object was lost in the evaluation machinery.
11770 * Can this happen? Maybe in case of internal-errors.
11771 */
11772 contextObj = NULL;
11773 }
11774 }
11775 goto evaluation_exit;
11776
11777evaluation_error:
11778 xmlXPathNodeSetClear(set, hasNsNodes);
11779 newContextSize = 0;
11780
11781evaluation_exit:
11782 if (contextObj != NULL) {
11783 if (ctxt->value == contextObj)
11784 valuePop(ctxt);
11785 xmlXPathReleaseObject(xpctxt, contextObj);
11786 }
11787 if (exprRes != NULL)
11788 xmlXPathReleaseObject(ctxt->context, exprRes);
11789 /*
11790 * Reset/invalidate the context.
11791 */
11792 xpctxt->node = oldContextNode;
11793 xpctxt->doc = oldContextDoc;
11794 xpctxt->contextSize = -1;
11795 xpctxt->proximityPosition = -1;
11796 return(newContextSize);
11797 }
11798 return(contextSize);
11799}
11800
11801static int
11802xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11803 xmlXPathStepOpPtr op,
11804 int *maxPos)
11805{
11806
11807 xmlXPathStepOpPtr exprOp;
11808
11809 /*
11810 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11811 */
11812
11813 /*
11814 * If not -1, then ch1 will point to:
11815 * 1) For predicates (XPATH_OP_PREDICATE):
11816 * - an inner predicate operator
11817 * 2) For filters (XPATH_OP_FILTER):
11818 * - an inner filter operater OR
11819 * - an expression selecting the node set.
11820 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11821 */
11822 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11823 return(0);
11824
11825 if (op->ch2 != -1) {
11826 exprOp = &ctxt->comp->steps[op->ch2];
11827 } else
11828 return(0);
11829
11830 if ((exprOp != NULL) &&
11831 (exprOp->op == XPATH_OP_VALUE) &&
11832 (exprOp->value4 != NULL) &&
11833 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11834 {
11835 /*
11836 * We have a "[n]" predicate here.
11837 * TODO: Unfortunately this simplistic test here is not
11838 * able to detect a position() predicate in compound
11839 * expressions like "[@attr = 'a" and position() = 1],
11840 * and even not the usage of position() in
11841 * "[position() = 1]"; thus - obviously - a position-range,
11842 * like it "[position() < 5]", is also not detected.
11843 * Maybe we could rewrite the AST to ease the optimization.
11844 */
11845 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11846
11847 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11848 (float) *maxPos)
11849 {
11850 return(1);
11851 }
11852 }
11853 return(0);
11854}
11855
11856static int
11857xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11858 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011859 xmlNodePtr * first, xmlNodePtr * last,
11860 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011861{
11862
11863#define XP_TEST_HIT \
11864 if (hasAxisRange != 0) { \
11865 if (++pos == maxPos) { \
11866 addNode(seq, cur); \
11867 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011868 } else { \
11869 addNode(seq, cur); \
11870 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011871
11872#define XP_TEST_HIT_NS \
11873 if (hasAxisRange != 0) { \
11874 if (++pos == maxPos) { \
11875 hasNsNodes = 1; \
11876 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11877 goto axis_range_end; } \
11878 } else { \
11879 hasNsNodes = 1; \
11880 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011881 xpctxt->node, (xmlNsPtr) cur); \
11882 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011883
11884 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11885 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11886 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11887 const xmlChar *prefix = op->value4;
11888 const xmlChar *name = op->value5;
11889 const xmlChar *URI = NULL;
11890
11891#ifdef DEBUG_STEP
11892 int nbMatches = 0, prevMatches = 0;
11893#endif
11894 int total = 0, hasNsNodes = 0;
11895 /* The popped object holding the context nodes */
11896 xmlXPathObjectPtr obj;
11897 /* The set of context nodes for the node tests */
11898 xmlNodeSetPtr contextSeq;
11899 int contextIdx;
11900 xmlNodePtr contextNode;
11901 /* The context node for a compound traversal */
11902 xmlNodePtr outerContextNode;
11903 /* The final resulting node set wrt to all context nodes */
11904 xmlNodeSetPtr outSeq;
11905 /*
11906 * The temporary resulting node set wrt 1 context node.
11907 * Used to feed predicate evaluation.
11908 */
11909 xmlNodeSetPtr seq;
11910 xmlNodePtr cur;
11911 /* First predicate operator */
11912 xmlXPathStepOpPtr predOp;
11913 int maxPos; /* The requested position() (when a "[n]" predicate) */
11914 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011915 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011916
11917 xmlXPathTraversalFunction next = NULL;
11918 /* compound axis traversal */
11919 xmlXPathTraversalFunctionExt outerNext = NULL;
11920 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11921 xmlXPathNodeSetMergeFunction mergeAndClear;
11922 xmlNodePtr oldContextNode;
11923 xmlXPathContextPtr xpctxt = ctxt->context;
11924
11925
11926 CHECK_TYPE0(XPATH_NODESET);
11927 obj = valuePop(ctxt);
11928 /*
11929 * Setup namespaces.
11930 */
11931 if (prefix != NULL) {
11932 URI = xmlXPathNsLookup(xpctxt, prefix);
11933 if (URI == NULL) {
11934 xmlXPathReleaseObject(xpctxt, obj);
11935 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11936 }
11937 }
11938 /*
11939 * Setup axis.
11940 *
11941 * MAYBE FUTURE TODO: merging optimizations:
11942 * - If the nodes to be traversed wrt to the initial nodes and
11943 * the current axis cannot overlap, then we could avoid searching
11944 * for duplicates during the merge.
11945 * But the question is how/when to evaluate if they cannot overlap.
11946 * Example: if we know that for two initial nodes, the one is
11947 * not in the ancestor-or-self axis of the other, then we could safely
11948 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11949 * the descendant-or-self axis.
11950 */
11951 addNode = xmlXPathNodeSetAdd;
11952 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11953 switch (axis) {
11954 case AXIS_ANCESTOR:
11955 first = NULL;
11956 next = xmlXPathNextAncestor;
11957 break;
11958 case AXIS_ANCESTOR_OR_SELF:
11959 first = NULL;
11960 next = xmlXPathNextAncestorOrSelf;
11961 break;
11962 case AXIS_ATTRIBUTE:
11963 first = NULL;
11964 last = NULL;
11965 next = xmlXPathNextAttribute;
11966 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11967 break;
11968 case AXIS_CHILD:
11969 last = NULL;
11970 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11971 /*
11972 * This iterator will give us only nodes which can
11973 * hold element nodes.
11974 */
11975 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11976 }
11977 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11978 (type == NODE_TYPE_NODE))
11979 {
11980 /*
11981 * Optimization if an element node type is 'element'.
11982 */
11983 next = xmlXPathNextChildElement;
11984 } else
11985 next = xmlXPathNextChild;
11986 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11987 break;
11988 case AXIS_DESCENDANT:
11989 last = NULL;
11990 next = xmlXPathNextDescendant;
11991 break;
11992 case AXIS_DESCENDANT_OR_SELF:
11993 last = NULL;
11994 next = xmlXPathNextDescendantOrSelf;
11995 break;
11996 case AXIS_FOLLOWING:
11997 last = NULL;
11998 next = xmlXPathNextFollowing;
11999 break;
12000 case AXIS_FOLLOWING_SIBLING:
12001 last = NULL;
12002 next = xmlXPathNextFollowingSibling;
12003 break;
12004 case AXIS_NAMESPACE:
12005 first = NULL;
12006 last = NULL;
12007 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12008 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12009 break;
12010 case AXIS_PARENT:
12011 first = NULL;
12012 next = xmlXPathNextParent;
12013 break;
12014 case AXIS_PRECEDING:
12015 first = NULL;
12016 next = xmlXPathNextPrecedingInternal;
12017 break;
12018 case AXIS_PRECEDING_SIBLING:
12019 first = NULL;
12020 next = xmlXPathNextPrecedingSibling;
12021 break;
12022 case AXIS_SELF:
12023 first = NULL;
12024 last = NULL;
12025 next = xmlXPathNextSelf;
12026 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12027 break;
12028 }
12029
12030#ifdef DEBUG_STEP
12031 xmlXPathDebugDumpStepAxis(axis, test,
12032 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12033#endif
12034
12035 if (next == NULL) {
12036 xmlXPathReleaseObject(xpctxt, obj);
12037 return(0);
12038 }
12039 contextSeq = obj->nodesetval;
12040 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12041 xmlXPathReleaseObject(xpctxt, obj);
12042 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12043 return(0);
12044 }
12045 /*
12046 * Predicate optimization ---------------------------------------------
12047 * If this step has a last predicate, which contains a position(),
12048 * then we'll optimize (although not exactly "position()", but only
12049 * the short-hand form, i.e., "[n]".
12050 *
12051 * Example - expression "/foo[parent::bar][1]":
12052 *
12053 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12054 * ROOT -- op->ch1
12055 * PREDICATE -- op->ch2 (predOp)
12056 * PREDICATE -- predOp->ch1 = [parent::bar]
12057 * SORT
12058 * COLLECT 'parent' 'name' 'node' bar
12059 * NODE
12060 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12061 *
12062 */
12063 maxPos = 0;
12064 predOp = NULL;
12065 hasPredicateRange = 0;
12066 hasAxisRange = 0;
12067 if (op->ch2 != -1) {
12068 /*
12069 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12070 */
12071 predOp = &ctxt->comp->steps[op->ch2];
12072 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12073 if (predOp->ch1 != -1) {
12074 /*
12075 * Use the next inner predicate operator.
12076 */
12077 predOp = &ctxt->comp->steps[predOp->ch1];
12078 hasPredicateRange = 1;
12079 } else {
12080 /*
12081 * There's no other predicate than the [n] predicate.
12082 */
12083 predOp = NULL;
12084 hasAxisRange = 1;
12085 }
12086 }
12087 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012088 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089 /*
12090 * Axis traversal -----------------------------------------------------
12091 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012092 /*
12093 * 2.3 Node Tests
12094 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012095 * - For the namespace axis, the principal node type is namespace.
12096 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012097 *
12098 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012099 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012100 * select all element children of the context node
12101 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012102 oldContextNode = xpctxt->node;
12103 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012104 outSeq = NULL;
12105 seq = NULL;
12106 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012107 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012108 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012109
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012110
12111 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12112 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012113 /*
12114 * This is a compound traversal.
12115 */
12116 if (contextNode == NULL) {
12117 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012118 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012119 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012120 outerContextNode = contextSeq->nodeTab[contextIdx++];
12121 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012122 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012123 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012124 if (contextNode == NULL)
12125 continue;
12126 /*
12127 * Set the context for the main traversal.
12128 */
12129 xpctxt->node = contextNode;
12130 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012131 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012132
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012133 if (seq == NULL) {
12134 seq = xmlXPathNodeSetCreate(NULL);
12135 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012136 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012137 goto error;
12138 }
12139 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012140 /*
12141 * Traverse the axis and test the nodes.
12142 */
12143 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012144 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012145 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012146 do {
12147 cur = next(ctxt, cur);
12148 if (cur == NULL)
12149 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012150
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012151 /*
12152 * QUESTION TODO: What does the "first" and "last" stuff do?
12153 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012154 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012155 if (*first == cur)
12156 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012157 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012158#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012159 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012160#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012161 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012162#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012163 {
12164 break;
12165 }
12166 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012167 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012168 if (*last == cur)
12169 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012170 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012171#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012172 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012173#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012174 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012175#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012176 {
12177 break;
12178 }
12179 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012180
12181 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012182
Daniel Veillardf06307e2001-07-03 10:35:50 +000012183#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012184 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12185#endif
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012186
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012187 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012188 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012189 total = 0;
12190 STRANGE
12191 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012192 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012193 /*
12194 * TODO: Don't we need to use
12195 * xmlXPathNodeSetAddNs() for namespace nodes here?
12196 * Surprisingly, some c14n tests fail, if we do this.
12197 */
12198 if (type == NODE_TYPE_NODE) {
12199 switch (cur->type) {
12200 case XML_DOCUMENT_NODE:
12201 case XML_HTML_DOCUMENT_NODE:
12202#ifdef LIBXML_DOCB_ENABLED
12203 case XML_DOCB_DOCUMENT_NODE:
12204#endif
12205 case XML_ELEMENT_NODE:
12206 case XML_ATTRIBUTE_NODE:
12207 case XML_PI_NODE:
12208 case XML_COMMENT_NODE:
12209 case XML_CDATA_SECTION_NODE:
12210 case XML_TEXT_NODE:
12211 case XML_NAMESPACE_DECL:
12212 XP_TEST_HIT
12213 break;
12214 default:
12215 break;
12216 }
12217 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012218 if (type == XML_NAMESPACE_DECL)
12219 XP_TEST_HIT_NS
12220 else
12221 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012222 } else if ((type == NODE_TYPE_TEXT) &&
12223 (cur->type == XML_CDATA_SECTION_NODE))
12224 {
12225 XP_TEST_HIT
12226 }
12227 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012228 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012229 if ((cur->type == XML_PI_NODE) &&
12230 ((name == NULL) || xmlStrEqual(name, cur->name)))
12231 {
12232 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012233 }
12234 break;
12235 case NODE_TEST_ALL:
12236 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012237 if (cur->type == XML_ATTRIBUTE_NODE)
12238 {
12239 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012240 }
12241 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012242 if (cur->type == XML_NAMESPACE_DECL)
12243 {
12244 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012245 }
12246 } else {
12247 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012248 if (prefix == NULL)
12249 {
12250 XP_TEST_HIT
12251
Daniel Veillardf06307e2001-07-03 10:35:50 +000012252 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012253 (xmlStrEqual(URI, cur->ns->href)))
12254 {
12255 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012256 }
12257 }
12258 }
12259 break;
12260 case NODE_TEST_NS:{
12261 TODO;
12262 break;
12263 }
12264 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012265 if (axis == AXIS_ATTRIBUTE) {
12266 if (cur->type != XML_ATTRIBUTE_NODE)
12267 break;
12268 } else if (axis == AXIS_NAMESPACE) {
12269 if (cur->type != XML_NAMESPACE_DECL)
12270 break;
12271 } else {
12272 if (cur->type != XML_ELEMENT_NODE)
12273 break;
12274 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012275 switch (cur->type) {
12276 case XML_ELEMENT_NODE:
12277 if (xmlStrEqual(name, cur->name)) {
12278 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012279 if (cur->ns == NULL)
12280 {
12281 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012282 }
12283 } else {
12284 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012285 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012286 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012287 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012288 }
12289 }
12290 }
12291 break;
12292 case XML_ATTRIBUTE_NODE:{
12293 xmlAttrPtr attr = (xmlAttrPtr) cur;
12294
12295 if (xmlStrEqual(name, attr->name)) {
12296 if (prefix == NULL) {
12297 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012298 (attr->ns->prefix == NULL))
12299 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012300 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012301 }
12302 } else {
12303 if ((attr->ns != NULL) &&
12304 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012305 attr->ns->href)))
12306 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012307 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012308 }
12309 }
12310 }
12311 break;
12312 }
12313 case XML_NAMESPACE_DECL:
12314 if (cur->type == XML_NAMESPACE_DECL) {
12315 xmlNsPtr ns = (xmlNsPtr) cur;
12316
12317 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012318 && (xmlStrEqual(ns->prefix, name)))
12319 {
12320 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012321 }
12322 }
12323 break;
12324 default:
12325 break;
12326 }
12327 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012328 } /* switch(test) */
12329 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012330
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012331 goto apply_predicates;
12332
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012333axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012334 /*
12335 * We have a "/foo[n]", and position() = n was reached.
12336 * Note that we can have as well "/foo/::parent::foo[1]", so
12337 * a duplicate-aware merge is still needed.
12338 * Merge with the result.
12339 */
12340 if (outSeq == NULL) {
12341 outSeq = seq;
12342 seq = NULL;
12343 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012344 outSeq = mergeAndClear(outSeq, seq, 0);
12345 /*
12346 * Break if only a true/false result was requested.
12347 */
12348 if (toBool)
12349 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012350 continue;
12351
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012352first_hit: /* ---------------------------------------------------------- */
12353 /*
12354 * Break if only a true/false result was requested and
12355 * no predicates existed and a node test succeeded.
12356 */
12357 if (outSeq == NULL) {
12358 outSeq = seq;
12359 seq = NULL;
12360 } else
12361 outSeq = mergeAndClear(outSeq, seq, 0);
12362 break;
12363
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012364#ifdef DEBUG_STEP
12365 if (seq != NULL)
12366 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012367#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012368
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012369apply_predicates: /* --------------------------------------------------- */
12370 /*
12371 * Apply predicates.
12372 */
12373 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12374 /*
12375 * E.g. when we have a "/foo[some expression][n]".
12376 */
12377 /*
12378 * QUESTION TODO: The old predicate evaluation took into
12379 * account location-sets.
12380 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12381 * Do we expect such a set here?
12382 * All what I learned now from the evaluation semantics
12383 * does not indicate that a location-set will be processed
12384 * here, so this looks OK.
12385 */
12386 /*
12387 * Iterate over all predicates, starting with the outermost
12388 * predicate.
12389 * TODO: Problem: we cannot execute the inner predicates first
12390 * since we cannot go back *up* the operator tree!
12391 * Options we have:
12392 * 1) Use of recursive functions (like is it currently done
12393 * via xmlXPathCompOpEval())
12394 * 2) Add a predicate evaluation information stack to the
12395 * context struct
12396 * 3) Change the way the operators are linked; we need a
12397 * "parent" field on xmlXPathStepOp
12398 *
12399 * For the moment, I'll try to solve this with a recursive
12400 * function: xmlXPathCompOpEvalPredicate().
12401 */
12402 size = seq->nodeNr;
12403 if (hasPredicateRange != 0)
12404 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12405 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12406 else
12407 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12408 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012409
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012410 if (ctxt->error != XPATH_EXPRESSION_OK) {
12411 total = 0;
12412 goto error;
12413 }
12414 /*
12415 * Add the filtered set of nodes to the result node set.
12416 */
12417 if (newSize == 0) {
12418 /*
12419 * The predicates filtered all nodes out.
12420 */
12421 xmlXPathNodeSetClear(seq, hasNsNodes);
12422 } else if (seq->nodeNr > 0) {
12423 /*
12424 * Add to result set.
12425 */
12426 if (outSeq == NULL) {
12427 if (size != newSize) {
12428 /*
12429 * We need to merge and clear here, since
12430 * the sequence will contained NULLed entries.
12431 */
12432 outSeq = mergeAndClear(NULL, seq, 1);
12433 } else {
12434 outSeq = seq;
12435 seq = NULL;
12436 }
12437 } else
12438 outSeq = mergeAndClear(outSeq, seq,
12439 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012440 /*
12441 * Break if only a true/false result was requested.
12442 */
12443 if (toBool)
12444 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012445 }
12446 } else if (seq->nodeNr > 0) {
12447 /*
12448 * Add to result set.
12449 */
12450 if (outSeq == NULL) {
12451 outSeq = seq;
12452 seq = NULL;
12453 } else {
12454 outSeq = mergeAndClear(outSeq, seq, 0);
12455 }
12456 }
12457 }
12458
12459error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012460 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012461 /*
12462 * QUESTION TODO: What does this do and why?
12463 * TODO: Do we have to do this also for the "error"
12464 * cleanup further down?
12465 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012466 ctxt->value->boolval = 1;
12467 ctxt->value->user = obj->user;
12468 obj->user = NULL;
12469 obj->boolval = 0;
12470 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012471 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012472
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012473 /*
12474 * Ensure we return at least an emtpy set.
12475 */
12476 if (outSeq == NULL) {
12477 if ((seq != NULL) && (seq->nodeNr == 0))
12478 outSeq = seq;
12479 else
12480 outSeq = xmlXPathNodeSetCreate(NULL);
12481 }
12482 if ((seq != NULL) && (seq != outSeq)) {
12483 xmlXPathFreeNodeSet(seq);
12484 }
12485 /*
12486 * Hand over the result. Better to push the set also in
12487 * case of errors.
12488 */
12489 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12490 /*
12491 * Reset the context node.
12492 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012493 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012494
12495#ifdef DEBUG_STEP
12496 xmlGenericError(xmlGenericErrorContext,
12497 "\nExamined %d nodes, found %d nodes at that step\n",
12498 total, nbMatches);
12499#endif
12500
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012501 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012502}
12503
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012504static int
12505xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12506 xmlXPathStepOpPtr op, xmlNodePtr * first);
12507
Daniel Veillardf06307e2001-07-03 10:35:50 +000012508/**
12509 * xmlXPathCompOpEvalFirst:
12510 * @ctxt: the XPath parser context with the compiled expression
12511 * @op: an XPath compiled operation
12512 * @first: the first elem found so far
12513 *
12514 * Evaluate the Precompiled XPath operation searching only the first
12515 * element in document order
12516 *
12517 * Returns the number of examined objects.
12518 */
12519static int
12520xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12521 xmlXPathStepOpPtr op, xmlNodePtr * first)
12522{
12523 int total = 0, cur;
12524 xmlXPathCompExprPtr comp;
12525 xmlXPathObjectPtr arg1, arg2;
12526
Daniel Veillard556c6682001-10-06 09:59:51 +000012527 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012528 comp = ctxt->comp;
12529 switch (op->op) {
12530 case XPATH_OP_END:
12531 return (0);
12532 case XPATH_OP_UNION:
12533 total =
12534 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12535 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012536 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012537 if ((ctxt->value != NULL)
12538 && (ctxt->value->type == XPATH_NODESET)
12539 && (ctxt->value->nodesetval != NULL)
12540 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12541 /*
12542 * limit tree traversing to first node in the result
12543 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012544 /*
12545 * OPTIMIZE TODO: This implicitely sorts
12546 * the result, even if not needed. E.g. if the argument
12547 * of the count() function, no sorting is needed.
12548 * OPTIMIZE TODO: How do we know if the node-list wasn't
12549 * aready sorted?
12550 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012551 if (ctxt->value->nodesetval->nodeNr > 1)
12552 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012553 *first = ctxt->value->nodesetval->nodeTab[0];
12554 }
12555 cur =
12556 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12557 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012558 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012559 CHECK_TYPE0(XPATH_NODESET);
12560 arg2 = valuePop(ctxt);
12561
12562 CHECK_TYPE0(XPATH_NODESET);
12563 arg1 = valuePop(ctxt);
12564
12565 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12566 arg2->nodesetval);
12567 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012568 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012569 /* optimizer */
12570 if (total > cur)
12571 xmlXPathCompSwap(op);
12572 return (total + cur);
12573 case XPATH_OP_ROOT:
12574 xmlXPathRoot(ctxt);
12575 return (0);
12576 case XPATH_OP_NODE:
12577 if (op->ch1 != -1)
12578 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012579 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012580 if (op->ch2 != -1)
12581 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012582 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012583 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12584 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012585 return (total);
12586 case XPATH_OP_RESET:
12587 if (op->ch1 != -1)
12588 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012589 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012590 if (op->ch2 != -1)
12591 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012592 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012593 ctxt->context->node = NULL;
12594 return (total);
12595 case XPATH_OP_COLLECT:{
12596 if (op->ch1 == -1)
12597 return (total);
12598
12599 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012600 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012601
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012602 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012603 return (total);
12604 }
12605 case XPATH_OP_VALUE:
12606 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012607 xmlXPathCacheObjectCopy(ctxt->context,
12608 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012609 return (0);
12610 case XPATH_OP_SORT:
12611 if (op->ch1 != -1)
12612 total +=
12613 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12614 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012615 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012616 if ((ctxt->value != NULL)
12617 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012618 && (ctxt->value->nodesetval != NULL)
12619 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012620 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12621 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012622#ifdef XP_OPTIMIZED_FILTER_FIRST
12623 case XPATH_OP_FILTER:
12624 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12625 return (total);
12626#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012627 default:
12628 return (xmlXPathCompOpEval(ctxt, op));
12629 }
12630}
12631
12632/**
12633 * xmlXPathCompOpEvalLast:
12634 * @ctxt: the XPath parser context with the compiled expression
12635 * @op: an XPath compiled operation
12636 * @last: the last elem found so far
12637 *
12638 * Evaluate the Precompiled XPath operation searching only the last
12639 * element in document order
12640 *
William M. Brack08171912003-12-29 02:52:11 +000012641 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012642 */
12643static int
12644xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12645 xmlNodePtr * last)
12646{
12647 int total = 0, cur;
12648 xmlXPathCompExprPtr comp;
12649 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012650 xmlNodePtr bak;
12651 xmlDocPtr bakd;
12652 int pp;
12653 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012654
Daniel Veillard556c6682001-10-06 09:59:51 +000012655 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656 comp = ctxt->comp;
12657 switch (op->op) {
12658 case XPATH_OP_END:
12659 return (0);
12660 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012661 bakd = ctxt->context->doc;
12662 bak = ctxt->context->node;
12663 pp = ctxt->context->proximityPosition;
12664 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012665 total =
12666 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012667 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012668 if ((ctxt->value != NULL)
12669 && (ctxt->value->type == XPATH_NODESET)
12670 && (ctxt->value->nodesetval != NULL)
12671 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12672 /*
12673 * limit tree traversing to first node in the result
12674 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012675 if (ctxt->value->nodesetval->nodeNr > 1)
12676 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012677 *last =
12678 ctxt->value->nodesetval->nodeTab[ctxt->value->
12679 nodesetval->nodeNr -
12680 1];
12681 }
William M. Brackce4fc562004-01-22 02:47:18 +000012682 ctxt->context->doc = bakd;
12683 ctxt->context->node = bak;
12684 ctxt->context->proximityPosition = pp;
12685 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012686 cur =
12687 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012688 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012689 if ((ctxt->value != NULL)
12690 && (ctxt->value->type == XPATH_NODESET)
12691 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012692 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012693 }
12694 CHECK_TYPE0(XPATH_NODESET);
12695 arg2 = valuePop(ctxt);
12696
12697 CHECK_TYPE0(XPATH_NODESET);
12698 arg1 = valuePop(ctxt);
12699
12700 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12701 arg2->nodesetval);
12702 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012703 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 /* optimizer */
12705 if (total > cur)
12706 xmlXPathCompSwap(op);
12707 return (total + cur);
12708 case XPATH_OP_ROOT:
12709 xmlXPathRoot(ctxt);
12710 return (0);
12711 case XPATH_OP_NODE:
12712 if (op->ch1 != -1)
12713 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012714 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012715 if (op->ch2 != -1)
12716 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012717 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012718 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12719 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012720 return (total);
12721 case XPATH_OP_RESET:
12722 if (op->ch1 != -1)
12723 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012724 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012725 if (op->ch2 != -1)
12726 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012727 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012728 ctxt->context->node = NULL;
12729 return (total);
12730 case XPATH_OP_COLLECT:{
12731 if (op->ch1 == -1)
12732 return (0);
12733
12734 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012735 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012736
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012737 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012738 return (total);
12739 }
12740 case XPATH_OP_VALUE:
12741 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012742 xmlXPathCacheObjectCopy(ctxt->context,
12743 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012744 return (0);
12745 case XPATH_OP_SORT:
12746 if (op->ch1 != -1)
12747 total +=
12748 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12749 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012750 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012751 if ((ctxt->value != NULL)
12752 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012753 && (ctxt->value->nodesetval != NULL)
12754 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012755 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12756 return (total);
12757 default:
12758 return (xmlXPathCompOpEval(ctxt, op));
12759 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012760}
12761
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012762#ifdef XP_OPTIMIZED_FILTER_FIRST
12763static int
12764xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12765 xmlXPathStepOpPtr op, xmlNodePtr * first)
12766{
12767 int total = 0;
12768 xmlXPathCompExprPtr comp;
12769 xmlXPathObjectPtr res;
12770 xmlXPathObjectPtr obj;
12771 xmlNodeSetPtr oldset;
12772 xmlNodePtr oldnode;
12773 xmlDocPtr oldDoc;
12774 int i;
12775
12776 CHECK_ERROR0;
12777 comp = ctxt->comp;
12778 /*
12779 * Optimization for ()[last()] selection i.e. the last elem
12780 */
12781 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12782 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12783 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12784 int f = comp->steps[op->ch2].ch1;
12785
12786 if ((f != -1) &&
12787 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12788 (comp->steps[f].value5 == NULL) &&
12789 (comp->steps[f].value == 0) &&
12790 (comp->steps[f].value4 != NULL) &&
12791 (xmlStrEqual
12792 (comp->steps[f].value4, BAD_CAST "last"))) {
12793 xmlNodePtr last = NULL;
12794
12795 total +=
12796 xmlXPathCompOpEvalLast(ctxt,
12797 &comp->steps[op->ch1],
12798 &last);
12799 CHECK_ERROR0;
12800 /*
12801 * The nodeset should be in document order,
12802 * Keep only the last value
12803 */
12804 if ((ctxt->value != NULL) &&
12805 (ctxt->value->type == XPATH_NODESET) &&
12806 (ctxt->value->nodesetval != NULL) &&
12807 (ctxt->value->nodesetval->nodeTab != NULL) &&
12808 (ctxt->value->nodesetval->nodeNr > 1)) {
12809 ctxt->value->nodesetval->nodeTab[0] =
12810 ctxt->value->nodesetval->nodeTab[ctxt->
12811 value->
12812 nodesetval->
12813 nodeNr -
12814 1];
12815 ctxt->value->nodesetval->nodeNr = 1;
12816 *first = *(ctxt->value->nodesetval->nodeTab);
12817 }
12818 return (total);
12819 }
12820 }
12821
12822 if (op->ch1 != -1)
12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12824 CHECK_ERROR0;
12825 if (op->ch2 == -1)
12826 return (total);
12827 if (ctxt->value == NULL)
12828 return (total);
12829
12830#ifdef LIBXML_XPTR_ENABLED
12831 oldnode = ctxt->context->node;
12832 /*
12833 * Hum are we filtering the result of an XPointer expression
12834 */
12835 if (ctxt->value->type == XPATH_LOCATIONSET) {
12836 xmlXPathObjectPtr tmp = NULL;
12837 xmlLocationSetPtr newlocset = NULL;
12838 xmlLocationSetPtr oldlocset;
12839
12840 /*
12841 * Extract the old locset, and then evaluate the result of the
12842 * expression for all the element in the locset. use it to grow
12843 * up a new locset.
12844 */
12845 CHECK_TYPE0(XPATH_LOCATIONSET);
12846 obj = valuePop(ctxt);
12847 oldlocset = obj->user;
12848 ctxt->context->node = NULL;
12849
12850 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12851 ctxt->context->contextSize = 0;
12852 ctxt->context->proximityPosition = 0;
12853 if (op->ch2 != -1)
12854 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12855 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012856 if (res != NULL) {
12857 xmlXPathReleaseObject(ctxt->context, res);
12858 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012859 valuePush(ctxt, obj);
12860 CHECK_ERROR0;
12861 return (total);
12862 }
12863 newlocset = xmlXPtrLocationSetCreate(NULL);
12864
12865 for (i = 0; i < oldlocset->locNr; i++) {
12866 /*
12867 * Run the evaluation with a node list made of a
12868 * single item in the nodelocset.
12869 */
12870 ctxt->context->node = oldlocset->locTab[i]->user;
12871 ctxt->context->contextSize = oldlocset->locNr;
12872 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012873 if (tmp == NULL) {
12874 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12875 ctxt->context->node);
12876 } else {
12877 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12878 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012879 }
12880 valuePush(ctxt, tmp);
12881 if (op->ch2 != -1)
12882 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12883 if (ctxt->error != XPATH_EXPRESSION_OK) {
12884 xmlXPathFreeObject(obj);
12885 return(0);
12886 }
12887 /*
12888 * The result of the evaluation need to be tested to
12889 * decided whether the filter succeeded or not
12890 */
12891 res = valuePop(ctxt);
12892 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12893 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012894 xmlXPathCacheObjectCopy(ctxt->context,
12895 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012896 }
12897 /*
12898 * Cleanup
12899 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012900 if (res != NULL) {
12901 xmlXPathReleaseObject(ctxt->context, res);
12902 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012903 if (ctxt->value == tmp) {
12904 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012905 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012906 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012907 * REVISIT TODO: Don't create a temporary nodeset
12908 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012909 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012910 /* OLD: xmlXPathFreeObject(res); */
12911 } else
12912 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012913 ctxt->context->node = NULL;
12914 /*
12915 * Only put the first node in the result, then leave.
12916 */
12917 if (newlocset->locNr > 0) {
12918 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12919 break;
12920 }
12921 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012922 if (tmp != NULL) {
12923 xmlXPathReleaseObject(ctxt->context, tmp);
12924 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012925 /*
12926 * The result is used as the new evaluation locset.
12927 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012928 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012929 ctxt->context->node = NULL;
12930 ctxt->context->contextSize = -1;
12931 ctxt->context->proximityPosition = -1;
12932 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12933 ctxt->context->node = oldnode;
12934 return (total);
12935 }
12936#endif /* LIBXML_XPTR_ENABLED */
12937
12938 /*
12939 * Extract the old set, and then evaluate the result of the
12940 * expression for all the element in the set. use it to grow
12941 * up a new set.
12942 */
12943 CHECK_TYPE0(XPATH_NODESET);
12944 obj = valuePop(ctxt);
12945 oldset = obj->nodesetval;
12946
12947 oldnode = ctxt->context->node;
12948 oldDoc = ctxt->context->doc;
12949 ctxt->context->node = NULL;
12950
12951 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12952 ctxt->context->contextSize = 0;
12953 ctxt->context->proximityPosition = 0;
12954 /* QUESTION TODO: Why was this code commented out?
12955 if (op->ch2 != -1)
12956 total +=
12957 xmlXPathCompOpEval(ctxt,
12958 &comp->steps[op->ch2]);
12959 CHECK_ERROR0;
12960 res = valuePop(ctxt);
12961 if (res != NULL)
12962 xmlXPathFreeObject(res);
12963 */
12964 valuePush(ctxt, obj);
12965 ctxt->context->node = oldnode;
12966 CHECK_ERROR0;
12967 } else {
12968 xmlNodeSetPtr newset;
12969 xmlXPathObjectPtr tmp = NULL;
12970 /*
12971 * Initialize the new set.
12972 * Also set the xpath document in case things like
12973 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012974 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012975 newset = xmlXPathNodeSetCreate(NULL);
12976
12977 for (i = 0; i < oldset->nodeNr; i++) {
12978 /*
12979 * Run the evaluation with a node list made of
12980 * a single item in the nodeset.
12981 */
12982 ctxt->context->node = oldset->nodeTab[i];
12983 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12984 (oldset->nodeTab[i]->doc != NULL))
12985 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012986 if (tmp == NULL) {
12987 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12988 ctxt->context->node);
12989 } else {
12990 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12991 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012992 }
12993 valuePush(ctxt, tmp);
12994 ctxt->context->contextSize = oldset->nodeNr;
12995 ctxt->context->proximityPosition = i + 1;
12996 if (op->ch2 != -1)
12997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12998 if (ctxt->error != XPATH_EXPRESSION_OK) {
12999 xmlXPathFreeNodeSet(newset);
13000 xmlXPathFreeObject(obj);
13001 return(0);
13002 }
13003 /*
13004 * The result of the evaluation needs to be tested to
13005 * decide whether the filter succeeded or not
13006 */
13007 res = valuePop(ctxt);
13008 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13009 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13010 }
13011 /*
13012 * Cleanup
13013 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013014 if (res != NULL) {
13015 xmlXPathReleaseObject(ctxt->context, res);
13016 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013017 if (ctxt->value == tmp) {
13018 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013019 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013020 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013021 * in order to avoid massive recreation inside this
13022 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013023 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013024 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013025 } else
13026 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013027 ctxt->context->node = NULL;
13028 /*
13029 * Only put the first node in the result, then leave.
13030 */
13031 if (newset->nodeNr > 0) {
13032 *first = *(newset->nodeTab);
13033 break;
13034 }
13035 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013036 if (tmp != NULL) {
13037 xmlXPathReleaseObject(ctxt->context, tmp);
13038 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013039 /*
13040 * The result is used as the new evaluation set.
13041 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013042 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013043 ctxt->context->node = NULL;
13044 ctxt->context->contextSize = -1;
13045 ctxt->context->proximityPosition = -1;
13046 /* may want to move this past the '}' later */
13047 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013048 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013049 }
13050 ctxt->context->node = oldnode;
13051 return(total);
13052}
13053#endif /* XP_OPTIMIZED_FILTER_FIRST */
13054
Owen Taylor3473f882001-02-23 17:55:21 +000013055/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013056 * xmlXPathCompOpEval:
13057 * @ctxt: the XPath parser context with the compiled expression
13058 * @op: an XPath compiled operation
13059 *
13060 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013061 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013062 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013063static int
13064xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13065{
13066 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013067 int equal, ret;
13068 xmlXPathCompExprPtr comp;
13069 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013070 xmlNodePtr bak;
13071 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013072 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013073 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013074
Daniel Veillard556c6682001-10-06 09:59:51 +000013075 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013076 comp = ctxt->comp;
13077 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013078 case XPATH_OP_END:
13079 return (0);
13080 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013081 bakd = ctxt->context->doc;
13082 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013083 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013084 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013085 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013086 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013087 xmlXPathBooleanFunction(ctxt, 1);
13088 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13089 return (total);
13090 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013091 ctxt->context->doc = bakd;
13092 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013093 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013094 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013095 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013096 if (ctxt->error) {
13097 xmlXPathFreeObject(arg2);
13098 return(0);
13099 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013100 xmlXPathBooleanFunction(ctxt, 1);
13101 arg1 = valuePop(ctxt);
13102 arg1->boolval &= arg2->boolval;
13103 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013104 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013105 return (total);
13106 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013107 bakd = ctxt->context->doc;
13108 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013109 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013110 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013111 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013112 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013113 xmlXPathBooleanFunction(ctxt, 1);
13114 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13115 return (total);
13116 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013117 ctxt->context->doc = bakd;
13118 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013119 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013120 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013121 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013122 if (ctxt->error) {
13123 xmlXPathFreeObject(arg2);
13124 return(0);
13125 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013126 xmlXPathBooleanFunction(ctxt, 1);
13127 arg1 = valuePop(ctxt);
13128 arg1->boolval |= arg2->boolval;
13129 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013130 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013131 return (total);
13132 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013133 bakd = ctxt->context->doc;
13134 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013135 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013136 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013137 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013138 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013139 ctxt->context->doc = bakd;
13140 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013141 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013142 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013144 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013145 if (op->value)
13146 equal = xmlXPathEqualValues(ctxt);
13147 else
13148 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013149 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013150 return (total);
13151 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013152 bakd = ctxt->context->doc;
13153 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013154 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013155 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013156 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013157 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013158 ctxt->context->doc = bakd;
13159 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013160 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013161 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013162 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013163 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013164 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013165 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013166 return (total);
13167 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013168 bakd = ctxt->context->doc;
13169 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013170 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013171 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013172 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013173 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013174 if (op->ch2 != -1) {
13175 ctxt->context->doc = bakd;
13176 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013177 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013178 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013179 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013180 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013181 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013182 if (op->value == 0)
13183 xmlXPathSubValues(ctxt);
13184 else if (op->value == 1)
13185 xmlXPathAddValues(ctxt);
13186 else if (op->value == 2)
13187 xmlXPathValueFlipSign(ctxt);
13188 else if (op->value == 3) {
13189 CAST_TO_NUMBER;
13190 CHECK_TYPE0(XPATH_NUMBER);
13191 }
13192 return (total);
13193 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013194 bakd = ctxt->context->doc;
13195 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013196 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013197 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013198 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013199 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013200 ctxt->context->doc = bakd;
13201 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013202 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013203 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013204 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013205 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013206 if (op->value == 0)
13207 xmlXPathMultValues(ctxt);
13208 else if (op->value == 1)
13209 xmlXPathDivValues(ctxt);
13210 else if (op->value == 2)
13211 xmlXPathModValues(ctxt);
13212 return (total);
13213 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013214 bakd = ctxt->context->doc;
13215 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013216 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013217 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013219 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013220 ctxt->context->doc = bakd;
13221 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013222 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013223 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013224 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013225 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013226 CHECK_TYPE0(XPATH_NODESET);
13227 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013228
Daniel Veillardf06307e2001-07-03 10:35:50 +000013229 CHECK_TYPE0(XPATH_NODESET);
13230 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013231
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013232 if ((arg1->nodesetval == NULL) ||
13233 ((arg2->nodesetval != NULL) &&
13234 (arg2->nodesetval->nodeNr != 0)))
13235 {
13236 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13237 arg2->nodesetval);
13238 }
13239
Daniel Veillardf06307e2001-07-03 10:35:50 +000013240 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013241 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013242 return (total);
13243 case XPATH_OP_ROOT:
13244 xmlXPathRoot(ctxt);
13245 return (total);
13246 case XPATH_OP_NODE:
13247 if (op->ch1 != -1)
13248 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013249 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013250 if (op->ch2 != -1)
13251 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013252 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013253 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13254 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013255 return (total);
13256 case XPATH_OP_RESET:
13257 if (op->ch1 != -1)
13258 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013259 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 if (op->ch2 != -1)
13261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013262 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 ctxt->context->node = NULL;
13264 return (total);
13265 case XPATH_OP_COLLECT:{
13266 if (op->ch1 == -1)
13267 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013268
Daniel Veillardf06307e2001-07-03 10:35:50 +000013269 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013270 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013271
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013272 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013273 return (total);
13274 }
13275 case XPATH_OP_VALUE:
13276 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013277 xmlXPathCacheObjectCopy(ctxt->context,
13278 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013279 return (total);
13280 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013281 xmlXPathObjectPtr val;
13282
Daniel Veillardf06307e2001-07-03 10:35:50 +000013283 if (op->ch1 != -1)
13284 total +=
13285 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013286 if (op->value5 == NULL) {
13287 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13288 if (val == NULL) {
13289 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13290 return(0);
13291 }
13292 valuePush(ctxt, val);
13293 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013294 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013295
Daniel Veillardf06307e2001-07-03 10:35:50 +000013296 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13297 if (URI == NULL) {
13298 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013299 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013300 op->value4, op->value5);
13301 return (total);
13302 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013303 val = xmlXPathVariableLookupNS(ctxt->context,
13304 op->value4, URI);
13305 if (val == NULL) {
13306 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13307 return(0);
13308 }
13309 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013310 }
13311 return (total);
13312 }
13313 case XPATH_OP_FUNCTION:{
13314 xmlXPathFunction func;
13315 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013316 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013317
13318 if (op->ch1 != -1)
13319 total +=
13320 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013321 if (ctxt->valueNr < op->value) {
13322 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013323 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013324 ctxt->error = XPATH_INVALID_OPERAND;
13325 return (total);
13326 }
13327 for (i = 0; i < op->value; i++)
13328 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13329 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013330 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013331 ctxt->error = XPATH_INVALID_OPERAND;
13332 return (total);
13333 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013334 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013335 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013336 else {
13337 const xmlChar *URI = NULL;
13338
13339 if (op->value5 == NULL)
13340 func =
13341 xmlXPathFunctionLookup(ctxt->context,
13342 op->value4);
13343 else {
13344 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13345 if (URI == NULL) {
13346 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013347 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013348 op->value4, op->value5);
13349 return (total);
13350 }
13351 func = xmlXPathFunctionLookupNS(ctxt->context,
13352 op->value4, URI);
13353 }
13354 if (func == NULL) {
13355 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013356 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 op->value4);
13358 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013360 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013361 op->cacheURI = (void *) URI;
13362 }
13363 oldFunc = ctxt->context->function;
13364 oldFuncURI = ctxt->context->functionURI;
13365 ctxt->context->function = op->value4;
13366 ctxt->context->functionURI = op->cacheURI;
13367 func(ctxt, op->value);
13368 ctxt->context->function = oldFunc;
13369 ctxt->context->functionURI = oldFuncURI;
13370 return (total);
13371 }
13372 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013373 bakd = ctxt->context->doc;
13374 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013375 pp = ctxt->context->proximityPosition;
13376 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013377 if (op->ch1 != -1)
13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013379 ctxt->context->contextSize = cs;
13380 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013381 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013382 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013383 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013384 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013385 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013386 ctxt->context->doc = bakd;
13387 ctxt->context->node = bak;
13388 CHECK_ERROR0;
13389 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013390 return (total);
13391 case XPATH_OP_PREDICATE:
13392 case XPATH_OP_FILTER:{
13393 xmlXPathObjectPtr res;
13394 xmlXPathObjectPtr obj, tmp;
13395 xmlNodeSetPtr newset = NULL;
13396 xmlNodeSetPtr oldset;
13397 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013398 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013399 int i;
13400
13401 /*
13402 * Optimization for ()[1] selection i.e. the first elem
13403 */
13404 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013405#ifdef XP_OPTIMIZED_FILTER_FIRST
13406 /*
13407 * FILTER TODO: Can we assume that the inner processing
13408 * will result in an ordered list if we have an
13409 * XPATH_OP_FILTER?
13410 * What about an additional field or flag on
13411 * xmlXPathObject like @sorted ? This way we wouln'd need
13412 * to assume anything, so it would be more robust and
13413 * easier to optimize.
13414 */
13415 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13416 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13417#else
13418 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13419#endif
13420 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013421 xmlXPathObjectPtr val;
13422
13423 val = comp->steps[op->ch2].value4;
13424 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13425 (val->floatval == 1.0)) {
13426 xmlNodePtr first = NULL;
13427
13428 total +=
13429 xmlXPathCompOpEvalFirst(ctxt,
13430 &comp->steps[op->ch1],
13431 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013432 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013433 /*
13434 * The nodeset should be in document order,
13435 * Keep only the first value
13436 */
13437 if ((ctxt->value != NULL) &&
13438 (ctxt->value->type == XPATH_NODESET) &&
13439 (ctxt->value->nodesetval != NULL) &&
13440 (ctxt->value->nodesetval->nodeNr > 1))
13441 ctxt->value->nodesetval->nodeNr = 1;
13442 return (total);
13443 }
13444 }
13445 /*
13446 * Optimization for ()[last()] selection i.e. the last elem
13447 */
13448 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13449 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13450 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13451 int f = comp->steps[op->ch2].ch1;
13452
13453 if ((f != -1) &&
13454 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13455 (comp->steps[f].value5 == NULL) &&
13456 (comp->steps[f].value == 0) &&
13457 (comp->steps[f].value4 != NULL) &&
13458 (xmlStrEqual
13459 (comp->steps[f].value4, BAD_CAST "last"))) {
13460 xmlNodePtr last = NULL;
13461
13462 total +=
13463 xmlXPathCompOpEvalLast(ctxt,
13464 &comp->steps[op->ch1],
13465 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013466 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013467 /*
13468 * The nodeset should be in document order,
13469 * Keep only the last value
13470 */
13471 if ((ctxt->value != NULL) &&
13472 (ctxt->value->type == XPATH_NODESET) &&
13473 (ctxt->value->nodesetval != NULL) &&
13474 (ctxt->value->nodesetval->nodeTab != NULL) &&
13475 (ctxt->value->nodesetval->nodeNr > 1)) {
13476 ctxt->value->nodesetval->nodeTab[0] =
13477 ctxt->value->nodesetval->nodeTab[ctxt->
13478 value->
13479 nodesetval->
13480 nodeNr -
13481 1];
13482 ctxt->value->nodesetval->nodeNr = 1;
13483 }
13484 return (total);
13485 }
13486 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013487 /*
13488 * Process inner predicates first.
13489 * Example "index[parent::book][1]":
13490 * ...
13491 * PREDICATE <-- we are here "[1]"
13492 * PREDICATE <-- process "[parent::book]" first
13493 * SORT
13494 * COLLECT 'parent' 'name' 'node' book
13495 * NODE
13496 * ELEM Object is a number : 1
13497 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013498 if (op->ch1 != -1)
13499 total +=
13500 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013501 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013502 if (op->ch2 == -1)
13503 return (total);
13504 if (ctxt->value == NULL)
13505 return (total);
13506
13507 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013508
13509#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013510 /*
13511 * Hum are we filtering the result of an XPointer expression
13512 */
13513 if (ctxt->value->type == XPATH_LOCATIONSET) {
13514 xmlLocationSetPtr newlocset = NULL;
13515 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013516
Daniel Veillardf06307e2001-07-03 10:35:50 +000013517 /*
13518 * Extract the old locset, and then evaluate the result of the
13519 * expression for all the element in the locset. use it to grow
13520 * up a new locset.
13521 */
13522 CHECK_TYPE0(XPATH_LOCATIONSET);
13523 obj = valuePop(ctxt);
13524 oldlocset = obj->user;
13525 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013526
Daniel Veillardf06307e2001-07-03 10:35:50 +000013527 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13528 ctxt->context->contextSize = 0;
13529 ctxt->context->proximityPosition = 0;
13530 if (op->ch2 != -1)
13531 total +=
13532 xmlXPathCompOpEval(ctxt,
13533 &comp->steps[op->ch2]);
13534 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013535 if (res != NULL) {
13536 xmlXPathReleaseObject(ctxt->context, res);
13537 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013538 valuePush(ctxt, obj);
13539 CHECK_ERROR0;
13540 return (total);
13541 }
13542 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013543
Daniel Veillardf06307e2001-07-03 10:35:50 +000013544 for (i = 0; i < oldlocset->locNr; i++) {
13545 /*
13546 * Run the evaluation with a node list made of a
13547 * single item in the nodelocset.
13548 */
13549 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013550 ctxt->context->contextSize = oldlocset->locNr;
13551 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013552 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13553 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013554 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013555
Daniel Veillardf06307e2001-07-03 10:35:50 +000013556 if (op->ch2 != -1)
13557 total +=
13558 xmlXPathCompOpEval(ctxt,
13559 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013560 if (ctxt->error != XPATH_EXPRESSION_OK) {
13561 xmlXPathFreeObject(obj);
13562 return(0);
13563 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013564
Daniel Veillardf06307e2001-07-03 10:35:50 +000013565 /*
13566 * The result of the evaluation need to be tested to
13567 * decided whether the filter succeeded or not
13568 */
13569 res = valuePop(ctxt);
13570 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13571 xmlXPtrLocationSetAdd(newlocset,
13572 xmlXPathObjectCopy
13573 (oldlocset->locTab[i]));
13574 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013575
Daniel Veillardf06307e2001-07-03 10:35:50 +000013576 /*
13577 * Cleanup
13578 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013579 if (res != NULL) {
13580 xmlXPathReleaseObject(ctxt->context, res);
13581 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013582 if (ctxt->value == tmp) {
13583 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013584 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013585 }
13586
13587 ctxt->context->node = NULL;
13588 }
13589
13590 /*
13591 * The result is used as the new evaluation locset.
13592 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013593 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013594 ctxt->context->node = NULL;
13595 ctxt->context->contextSize = -1;
13596 ctxt->context->proximityPosition = -1;
13597 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13598 ctxt->context->node = oldnode;
13599 return (total);
13600 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013601#endif /* LIBXML_XPTR_ENABLED */
13602
Daniel Veillardf06307e2001-07-03 10:35:50 +000013603 /*
13604 * Extract the old set, and then evaluate the result of the
13605 * expression for all the element in the set. use it to grow
13606 * up a new set.
13607 */
13608 CHECK_TYPE0(XPATH_NODESET);
13609 obj = valuePop(ctxt);
13610 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013611
Daniel Veillardf06307e2001-07-03 10:35:50 +000013612 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013613 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013614 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013615
Daniel Veillardf06307e2001-07-03 10:35:50 +000013616 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13617 ctxt->context->contextSize = 0;
13618 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013619/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013620 if (op->ch2 != -1)
13621 total +=
13622 xmlXPathCompOpEval(ctxt,
13623 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013624 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013625 res = valuePop(ctxt);
13626 if (res != NULL)
13627 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013628*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013629 valuePush(ctxt, obj);
13630 ctxt->context->node = oldnode;
13631 CHECK_ERROR0;
13632 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013633 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013634 /*
13635 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013636 * Also set the xpath document in case things like
13637 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013638 */
13639 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013640 /*
13641 * SPEC XPath 1.0:
13642 * "For each node in the node-set to be filtered, the
13643 * PredicateExpr is evaluated with that node as the
13644 * context node, with the number of nodes in the
13645 * node-set as the context size, and with the proximity
13646 * position of the node in the node-set with respect to
13647 * the axis as the context position;"
13648 * @oldset is the node-set" to be filtered.
13649 *
13650 * SPEC XPath 1.0:
13651 * "only predicates change the context position and
13652 * context size (see [2.4 Predicates])."
13653 * Example:
13654 * node-set context pos
13655 * nA 1
13656 * nB 2
13657 * nC 3
13658 * After applying predicate [position() > 1] :
13659 * node-set context pos
13660 * nB 1
13661 * nC 2
13662 *
13663 * removed the first node in the node-set, then
13664 * the context position of the
13665 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013666 for (i = 0; i < oldset->nodeNr; i++) {
13667 /*
13668 * Run the evaluation with a node list made of
13669 * a single item in the nodeset.
13670 */
13671 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013672 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13673 (oldset->nodeTab[i]->doc != NULL))
13674 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013675 if (tmp == NULL) {
13676 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677 ctxt->context->node);
13678 } else {
13679 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13680 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013681 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013682 valuePush(ctxt, tmp);
13683 ctxt->context->contextSize = oldset->nodeNr;
13684 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013685 /*
13686 * Evaluate the predicate against the context node.
13687 * Can/should we optimize position() predicates
13688 * here (e.g. "[1]")?
13689 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013690 if (op->ch2 != -1)
13691 total +=
13692 xmlXPathCompOpEval(ctxt,
13693 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013694 if (ctxt->error != XPATH_EXPRESSION_OK) {
13695 xmlXPathFreeNodeSet(newset);
13696 xmlXPathFreeObject(obj);
13697 return(0);
13698 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013699
Daniel Veillardf06307e2001-07-03 10:35:50 +000013700 /*
William M. Brack08171912003-12-29 02:52:11 +000013701 * The result of the evaluation needs to be tested to
13702 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013703 */
13704 /*
13705 * OPTIMIZE TODO: Can we use
13706 * xmlXPathNodeSetAdd*Unique()* instead?
13707 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013708 res = valuePop(ctxt);
13709 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13710 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13711 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013712
Daniel Veillardf06307e2001-07-03 10:35:50 +000013713 /*
13714 * Cleanup
13715 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013716 if (res != NULL) {
13717 xmlXPathReleaseObject(ctxt->context, res);
13718 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013719 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013720 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013721 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013722 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013723 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013724 * in order to avoid massive recreation inside this
13725 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013726 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013727 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013728 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013729 ctxt->context->node = NULL;
13730 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013731 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013732 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013733 /*
13734 * The result is used as the new evaluation set.
13735 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013736 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013737 ctxt->context->node = NULL;
13738 ctxt->context->contextSize = -1;
13739 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013740 /* may want to move this past the '}' later */
13741 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013742 valuePush(ctxt,
13743 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013744 }
13745 ctxt->context->node = oldnode;
13746 return (total);
13747 }
13748 case XPATH_OP_SORT:
13749 if (op->ch1 != -1)
13750 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013751 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013752 if ((ctxt->value != NULL) &&
13753 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013754 (ctxt->value->nodesetval != NULL) &&
13755 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013756 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013757 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013758 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013759 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013760#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013761 case XPATH_OP_RANGETO:{
13762 xmlXPathObjectPtr range;
13763 xmlXPathObjectPtr res, obj;
13764 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013765 xmlLocationSetPtr newlocset = NULL;
13766 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013767 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013768 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013769
Daniel Veillardf06307e2001-07-03 10:35:50 +000013770 if (op->ch1 != -1)
13771 total +=
13772 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13773 if (op->ch2 == -1)
13774 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013775
William M. Brack08171912003-12-29 02:52:11 +000013776 if (ctxt->value->type == XPATH_LOCATIONSET) {
13777 /*
13778 * Extract the old locset, and then evaluate the result of the
13779 * expression for all the element in the locset. use it to grow
13780 * up a new locset.
13781 */
13782 CHECK_TYPE0(XPATH_LOCATIONSET);
13783 obj = valuePop(ctxt);
13784 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013785
William M. Brack08171912003-12-29 02:52:11 +000013786 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013787 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013788 ctxt->context->contextSize = 0;
13789 ctxt->context->proximityPosition = 0;
13790 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13791 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013792 if (res != NULL) {
13793 xmlXPathReleaseObject(ctxt->context, res);
13794 }
William M. Brack08171912003-12-29 02:52:11 +000013795 valuePush(ctxt, obj);
13796 CHECK_ERROR0;
13797 return (total);
13798 }
13799 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013800
William M. Brack08171912003-12-29 02:52:11 +000013801 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013802 /*
William M. Brack08171912003-12-29 02:52:11 +000013803 * Run the evaluation with a node list made of a
13804 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013805 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013806 ctxt->context->node = oldlocset->locTab[i]->user;
13807 ctxt->context->contextSize = oldlocset->locNr;
13808 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013809 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13810 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013811 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013812
Daniel Veillardf06307e2001-07-03 10:35:50 +000013813 if (op->ch2 != -1)
13814 total +=
13815 xmlXPathCompOpEval(ctxt,
13816 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013817 if (ctxt->error != XPATH_EXPRESSION_OK) {
13818 xmlXPathFreeObject(obj);
13819 return(0);
13820 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013821
Daniel Veillardf06307e2001-07-03 10:35:50 +000013822 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013823 if (res->type == XPATH_LOCATIONSET) {
13824 xmlLocationSetPtr rloc =
13825 (xmlLocationSetPtr)res->user;
13826 for (j=0; j<rloc->locNr; j++) {
13827 range = xmlXPtrNewRange(
13828 oldlocset->locTab[i]->user,
13829 oldlocset->locTab[i]->index,
13830 rloc->locTab[j]->user2,
13831 rloc->locTab[j]->index2);
13832 if (range != NULL) {
13833 xmlXPtrLocationSetAdd(newlocset, range);
13834 }
13835 }
13836 } else {
13837 range = xmlXPtrNewRangeNodeObject(
13838 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13839 if (range != NULL) {
13840 xmlXPtrLocationSetAdd(newlocset,range);
13841 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013842 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013843
Daniel Veillardf06307e2001-07-03 10:35:50 +000013844 /*
13845 * Cleanup
13846 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013847 if (res != NULL) {
13848 xmlXPathReleaseObject(ctxt->context, res);
13849 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013850 if (ctxt->value == tmp) {
13851 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013852 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013853 }
13854
13855 ctxt->context->node = NULL;
13856 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013857 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013858 CHECK_TYPE0(XPATH_NODESET);
13859 obj = valuePop(ctxt);
13860 oldset = obj->nodesetval;
13861 ctxt->context->node = NULL;
13862
13863 newlocset = xmlXPtrLocationSetCreate(NULL);
13864
13865 if (oldset != NULL) {
13866 for (i = 0; i < oldset->nodeNr; i++) {
13867 /*
13868 * Run the evaluation with a node list made of a single item
13869 * in the nodeset.
13870 */
13871 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013872 /*
13873 * OPTIMIZE TODO: Avoid recreation for every iteration.
13874 */
13875 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13876 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013877 valuePush(ctxt, tmp);
13878
13879 if (op->ch2 != -1)
13880 total +=
13881 xmlXPathCompOpEval(ctxt,
13882 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013883 if (ctxt->error != XPATH_EXPRESSION_OK) {
13884 xmlXPathFreeObject(obj);
13885 return(0);
13886 }
William M. Brack08171912003-12-29 02:52:11 +000013887
William M. Brack08171912003-12-29 02:52:11 +000013888 res = valuePop(ctxt);
13889 range =
13890 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13891 res);
13892 if (range != NULL) {
13893 xmlXPtrLocationSetAdd(newlocset, range);
13894 }
13895
13896 /*
13897 * Cleanup
13898 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013899 if (res != NULL) {
13900 xmlXPathReleaseObject(ctxt->context, res);
13901 }
William M. Brack08171912003-12-29 02:52:11 +000013902 if (ctxt->value == tmp) {
13903 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013904 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013905 }
13906
13907 ctxt->context->node = NULL;
13908 }
13909 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013910 }
13911
13912 /*
13913 * The result is used as the new evaluation set.
13914 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013915 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013916 ctxt->context->node = NULL;
13917 ctxt->context->contextSize = -1;
13918 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013919 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013920 return (total);
13921 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013922#endif /* LIBXML_XPTR_ENABLED */
13923 }
13924 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013925 "XPath: unknown precompiled operation %d\n", op->op);
13926 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013927}
13928
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013929/**
13930 * xmlXPathCompOpEvalToBoolean:
13931 * @ctxt: the XPath parser context
13932 *
13933 * Evaluates if the expression evaluates to true.
13934 *
13935 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13936 */
13937static int
13938xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013939 xmlXPathStepOpPtr op,
13940 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013941{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013942 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013943
13944start:
13945 /* comp = ctxt->comp; */
13946 switch (op->op) {
13947 case XPATH_OP_END:
13948 return (0);
13949 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013950 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013951 if (isPredicate)
13952 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13953 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013954 case XPATH_OP_SORT:
13955 /*
13956 * We don't need sorting for boolean results. Skip this one.
13957 */
13958 if (op->ch1 != -1) {
13959 op = &ctxt->comp->steps[op->ch1];
13960 goto start;
13961 }
13962 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013963 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013964 if (op->ch1 == -1)
13965 return(0);
13966
13967 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13968 if (ctxt->error != XPATH_EXPRESSION_OK)
13969 return(-1);
13970
13971 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13972 if (ctxt->error != XPATH_EXPRESSION_OK)
13973 return(-1);
13974
13975 resObj = valuePop(ctxt);
13976 if (resObj == NULL)
13977 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013978 break;
13979 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013980 /*
13981 * Fallback to call xmlXPathCompOpEval().
13982 */
13983 xmlXPathCompOpEval(ctxt, op);
13984 if (ctxt->error != XPATH_EXPRESSION_OK)
13985 return(-1);
13986
13987 resObj = valuePop(ctxt);
13988 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013989 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013990 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013991 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013992
13993 if (resObj) {
13994 int res;
13995
13996 if (resObj->type == XPATH_BOOLEAN) {
13997 res = resObj->boolval;
13998 } else if (isPredicate) {
13999 /*
14000 * For predicates a result of type "number" is handled
14001 * differently:
14002 * SPEC XPath 1.0:
14003 * "If the result is a number, the result will be converted
14004 * to true if the number is equal to the context position
14005 * and will be converted to false otherwise;"
14006 */
14007 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14008 } else {
14009 res = xmlXPathCastToBoolean(resObj);
14010 }
14011 xmlXPathReleaseObject(ctxt->context, resObj);
14012 return(res);
14013 }
14014
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014015 return(0);
14016}
14017
Daniel Veillard56de87e2005-02-16 00:22:29 +000014018#ifdef XPATH_STREAMING
14019/**
14020 * xmlXPathRunStreamEval:
14021 * @ctxt: the XPath parser context with the compiled expression
14022 *
14023 * Evaluate the Precompiled Streamable XPath expression in the given context.
14024 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014025static int
14026xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14027 xmlXPathObjectPtr *resultSeq, int toBool)
14028{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014029 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014030 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014031 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014032 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014033 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014034 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014035
14036 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014037
14038 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014039 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014040 max_depth = xmlPatternMaxDepth(comp);
14041 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014042 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014043 if (max_depth == -2)
14044 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014045 min_depth = xmlPatternMinDepth(comp);
14046 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014047 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014048 from_root = xmlPatternFromRoot(comp);
14049 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014050 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014051#if 0
14052 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14053#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014054
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014055 if (! toBool) {
14056 if (resultSeq == NULL)
14057 return(-1);
14058 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14059 if (*resultSeq == NULL)
14060 return(-1);
14061 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014062
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014063 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014064 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014065 */
14066 if (min_depth == 0) {
14067 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014068 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014069 if (toBool)
14070 return(1);
14071 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14072 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014073 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014074 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014075 if (toBool)
14076 return(1);
14077 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014078 }
14079 }
14080 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014081 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014082 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014083
Daniel Veillard56de87e2005-02-16 00:22:29 +000014084 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014085 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014086 } else if (ctxt->node != NULL) {
14087 switch (ctxt->node->type) {
14088 case XML_ELEMENT_NODE:
14089 case XML_DOCUMENT_NODE:
14090 case XML_DOCUMENT_FRAG_NODE:
14091 case XML_HTML_DOCUMENT_NODE:
14092#ifdef LIBXML_DOCB_ENABLED
14093 case XML_DOCB_DOCUMENT_NODE:
14094#endif
14095 cur = ctxt->node;
14096 break;
14097 case XML_ATTRIBUTE_NODE:
14098 case XML_TEXT_NODE:
14099 case XML_CDATA_SECTION_NODE:
14100 case XML_ENTITY_REF_NODE:
14101 case XML_ENTITY_NODE:
14102 case XML_PI_NODE:
14103 case XML_COMMENT_NODE:
14104 case XML_NOTATION_NODE:
14105 case XML_DTD_NODE:
14106 case XML_DOCUMENT_TYPE_NODE:
14107 case XML_ELEMENT_DECL:
14108 case XML_ATTRIBUTE_DECL:
14109 case XML_ENTITY_DECL:
14110 case XML_NAMESPACE_DECL:
14111 case XML_XINCLUDE_START:
14112 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014113 break;
14114 }
14115 limit = cur;
14116 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014117 if (cur == NULL) {
14118 return(0);
14119 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014120
14121 patstream = xmlPatternGetStreamCtxt(comp);
14122 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014123 /*
14124 * QUESTION TODO: Is this an error?
14125 */
14126 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014127 }
14128
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014129 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014130
Daniel Veillard56de87e2005-02-16 00:22:29 +000014131 if (from_root) {
14132 ret = xmlStreamPush(patstream, NULL, NULL);
14133 if (ret < 0) {
14134 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014135 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014136 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014137 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014138 }
14139 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014140 depth = 0;
14141 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014142next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014143 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014144 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014145
14146 switch (cur->type) {
14147 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014148 case XML_TEXT_NODE:
14149 case XML_CDATA_SECTION_NODE:
14150 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014151 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014152 if (cur->type == XML_ELEMENT_NODE) {
14153 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014154 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014155 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014156 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14157 else
14158 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014159
14160 if (ret < 0) {
14161 /* NOP. */
14162 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014163 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014164 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014165 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014166 }
14167 if ((cur->children == NULL) || (depth >= max_depth)) {
14168 ret = xmlStreamPop(patstream);
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 default:
14177 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014178 }
14179
Daniel Veillard56de87e2005-02-16 00:22:29 +000014180scan_children:
14181 if ((cur->children != NULL) && (depth < max_depth)) {
14182 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014183 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014184 */
14185 if (cur->children->type != XML_ENTITY_DECL) {
14186 cur = cur->children;
14187 depth++;
14188 /*
14189 * Skip DTDs
14190 */
14191 if (cur->type != XML_DTD_NODE)
14192 continue;
14193 }
14194 }
14195
14196 if (cur == limit)
14197 break;
14198
14199 while (cur->next != NULL) {
14200 cur = cur->next;
14201 if ((cur->type != XML_ENTITY_DECL) &&
14202 (cur->type != XML_DTD_NODE))
14203 goto next_node;
14204 }
14205
14206 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014207 cur = cur->parent;
14208 depth--;
14209 if ((cur == NULL) || (cur == limit))
14210 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014211 if (cur->type == XML_ELEMENT_NODE) {
14212 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014213 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014214 ((cur->type == XML_TEXT_NODE) ||
14215 (cur->type == XML_CDATA_SECTION_NODE) ||
14216 (cur->type == XML_COMMENT_NODE) ||
14217 (cur->type == XML_PI_NODE)))
14218 {
14219 ret = xmlStreamPop(patstream);
14220 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014221 if (cur->next != NULL) {
14222 cur = cur->next;
14223 break;
14224 }
14225 } while (cur != NULL);
14226
14227 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014228
Daniel Veillard56de87e2005-02-16 00:22:29 +000014229done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014230
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014231#if 0
14232 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014233 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014234#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014235
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014236 if (patstream)
14237 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014238 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014239
14240return_1:
14241 if (patstream)
14242 xmlFreeStreamCtxt(patstream);
14243 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014244}
14245#endif /* XPATH_STREAMING */
14246
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014247/**
14248 * xmlXPathRunEval:
14249 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014250 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014251 *
14252 * Evaluate the Precompiled XPath expression in the given context.
14253 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014254static int
14255xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14256{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014257 xmlXPathCompExprPtr comp;
14258
14259 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014260 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014261
14262 if (ctxt->valueTab == NULL) {
14263 /* Allocate the value stack */
14264 ctxt->valueTab = (xmlXPathObjectPtr *)
14265 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14266 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014267 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014268 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014269 }
14270 ctxt->valueNr = 0;
14271 ctxt->valueMax = 10;
14272 ctxt->value = NULL;
14273 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014274#ifdef XPATH_STREAMING
14275 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014276 int res;
14277
14278 if (toBool) {
14279 /*
14280 * Evaluation to boolean result.
14281 */
14282 res = xmlXPathRunStreamEval(ctxt->context,
14283 ctxt->comp->stream, NULL, 1);
14284 if (res != -1)
14285 return(res);
14286 } else {
14287 xmlXPathObjectPtr resObj = NULL;
14288
14289 /*
14290 * Evaluation to a sequence.
14291 */
14292 res = xmlXPathRunStreamEval(ctxt->context,
14293 ctxt->comp->stream, &resObj, 0);
14294
14295 if ((res != -1) && (resObj != NULL)) {
14296 valuePush(ctxt, resObj);
14297 return(0);
14298 }
14299 if (resObj != NULL)
14300 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014301 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014302 /*
14303 * QUESTION TODO: This falls back to normal XPath evaluation
14304 * if res == -1. Is this intended?
14305 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014306 }
14307#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014308 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014309 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014310 xmlGenericError(xmlGenericErrorContext,
14311 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014312 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014313 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014314 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014315 return(xmlXPathCompOpEvalToBoolean(ctxt,
14316 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014317 else
14318 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14319
14320 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014321}
14322
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014323/************************************************************************
14324 * *
14325 * Public interfaces *
14326 * *
14327 ************************************************************************/
14328
14329/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014330 * xmlXPathEvalPredicate:
14331 * @ctxt: the XPath context
14332 * @res: the Predicate Expression evaluation result
14333 *
14334 * Evaluate a predicate result for the current node.
14335 * A PredicateExpr is evaluated by evaluating the Expr and converting
14336 * the result to a boolean. If the result is a number, the result will
14337 * be converted to true if the number is equal to the position of the
14338 * context node in the context node list (as returned by the position
14339 * function) and will be converted to false otherwise; if the result
14340 * is not a number, then the result will be converted as if by a call
14341 * to the boolean function.
14342 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014343 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014344 */
14345int
14346xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014347 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014348 switch (res->type) {
14349 case XPATH_BOOLEAN:
14350 return(res->boolval);
14351 case XPATH_NUMBER:
14352 return(res->floatval == ctxt->proximityPosition);
14353 case XPATH_NODESET:
14354 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014355 if (res->nodesetval == NULL)
14356 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014357 return(res->nodesetval->nodeNr != 0);
14358 case XPATH_STRING:
14359 return((res->stringval != NULL) &&
14360 (xmlStrlen(res->stringval) != 0));
14361 default:
14362 STRANGE
14363 }
14364 return(0);
14365}
14366
14367/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014368 * xmlXPathEvaluatePredicateResult:
14369 * @ctxt: the XPath Parser context
14370 * @res: the Predicate Expression evaluation result
14371 *
14372 * Evaluate a predicate result for the current node.
14373 * A PredicateExpr is evaluated by evaluating the Expr and converting
14374 * the result to a boolean. If the result is a number, the result will
14375 * be converted to true if the number is equal to the position of the
14376 * context node in the context node list (as returned by the position
14377 * function) and will be converted to false otherwise; if the result
14378 * is not a number, then the result will be converted as if by a call
14379 * to the boolean function.
14380 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014381 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014382 */
14383int
14384xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14385 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014386 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014387 switch (res->type) {
14388 case XPATH_BOOLEAN:
14389 return(res->boolval);
14390 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014391#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014392 return((res->floatval == ctxt->context->proximityPosition) &&
14393 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014394#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014395 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014396#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014397 case XPATH_NODESET:
14398 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014399 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014400 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014401 return(res->nodesetval->nodeNr != 0);
14402 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014403 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014404#ifdef LIBXML_XPTR_ENABLED
14405 case XPATH_LOCATIONSET:{
14406 xmlLocationSetPtr ptr = res->user;
14407 if (ptr == NULL)
14408 return(0);
14409 return (ptr->locNr != 0);
14410 }
14411#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014412 default:
14413 STRANGE
14414 }
14415 return(0);
14416}
14417
Daniel Veillard56de87e2005-02-16 00:22:29 +000014418#ifdef XPATH_STREAMING
14419/**
14420 * xmlXPathTryStreamCompile:
14421 * @ctxt: an XPath context
14422 * @str: the XPath expression
14423 *
14424 * Try to compile the XPath expression as a streamable subset.
14425 *
14426 * Returns the compiled expression or NULL if failed to compile.
14427 */
14428static xmlXPathCompExprPtr
14429xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14430 /*
14431 * Optimization: use streaming patterns when the XPath expression can
14432 * be compiled to a stream lookup
14433 */
14434 xmlPatternPtr stream;
14435 xmlXPathCompExprPtr comp;
14436 xmlDictPtr dict = NULL;
14437 const xmlChar **namespaces = NULL;
14438 xmlNsPtr ns;
14439 int i, j;
14440
14441 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14442 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014443 const xmlChar *tmp;
14444
14445 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014446 * We don't try to handle expressions using the verbose axis
14447 * specifiers ("::"), just the simplied form at this point.
14448 * Additionally, if there is no list of namespaces available and
14449 * there's a ":" in the expression, indicating a prefixed QName,
14450 * then we won't try to compile either. xmlPatterncompile() needs
14451 * to have a list of namespaces at compilation time in order to
14452 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014453 */
14454 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014455 if ((tmp != NULL) &&
14456 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14457 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014458
Daniel Veillard56de87e2005-02-16 00:22:29 +000014459 if (ctxt != NULL) {
14460 dict = ctxt->dict;
14461 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014462 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014463 if (namespaces == NULL) {
14464 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14465 return(NULL);
14466 }
14467 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14468 ns = ctxt->namespaces[j];
14469 namespaces[i++] = ns->href;
14470 namespaces[i++] = ns->prefix;
14471 }
14472 namespaces[i++] = NULL;
14473 namespaces[i++] = NULL;
14474 }
14475 }
14476
William M. Brackea152c02005-06-09 18:12:28 +000014477 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14478 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014479 if (namespaces != NULL) {
14480 xmlFree((xmlChar **)namespaces);
14481 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014482 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14483 comp = xmlXPathNewCompExpr();
14484 if (comp == NULL) {
14485 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14486 return(NULL);
14487 }
14488 comp->stream = stream;
14489 comp->dict = dict;
14490 if (comp->dict)
14491 xmlDictReference(comp->dict);
14492 return(comp);
14493 }
14494 xmlFreePattern(stream);
14495 }
14496 return(NULL);
14497}
14498#endif /* XPATH_STREAMING */
14499
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014500static int
14501xmlXPathCanRewriteDosExpression(xmlChar *expr)
14502{
14503 if (expr == NULL)
14504 return(0);
14505 do {
14506 if ((*expr == '/') && (*(++expr) == '/'))
14507 return(1);
14508 } while (*expr++);
14509 return(0);
14510}
14511static void
14512xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14513{
14514 /*
14515 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14516 * internal representation.
14517 */
14518 if (op->ch1 != -1) {
14519 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14520 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14521 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14522 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14523 {
14524 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014525 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014526 */
14527 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14528
14529 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14530 (prevop->ch1 != -1) &&
14531 ((xmlXPathAxisVal) prevop->value ==
14532 AXIS_DESCENDANT_OR_SELF) &&
14533 (prevop->ch2 == -1) &&
14534 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014535 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14536 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014537 {
14538 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014539 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014540 * Eliminate it.
14541 */
14542 op->ch1 = prevop->ch1;
14543 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14544 }
14545 }
14546 if (op->ch1 != -1)
14547 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14548 }
14549 if (op->ch2 != -1)
14550 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14551}
14552
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014553/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014554 * xmlXPathCtxtCompile:
14555 * @ctxt: an XPath context
14556 * @str: the XPath expression
14557 *
14558 * Compile an XPath expression
14559 *
14560 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14561 * the caller has to free the object.
14562 */
14563xmlXPathCompExprPtr
14564xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14565 xmlXPathParserContextPtr pctxt;
14566 xmlXPathCompExprPtr comp;
14567
Daniel Veillard56de87e2005-02-16 00:22:29 +000014568#ifdef XPATH_STREAMING
14569 comp = xmlXPathTryStreamCompile(ctxt, str);
14570 if (comp != NULL)
14571 return(comp);
14572#endif
14573
Daniel Veillard4773df22004-01-23 13:15:13 +000014574 xmlXPathInit();
14575
14576 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014577 if (pctxt == NULL)
14578 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014579 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014580
14581 if( pctxt->error != XPATH_EXPRESSION_OK )
14582 {
14583 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014584 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014585 }
14586
14587 if (*pctxt->cur != 0) {
14588 /*
14589 * aleksey: in some cases this line prints *second* error message
14590 * (see bug #78858) and probably this should be fixed.
14591 * However, we are not sure that all error messages are printed
14592 * out in other places. It's not critical so we leave it as-is for now
14593 */
14594 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14595 comp = NULL;
14596 } else {
14597 comp = pctxt->comp;
14598 pctxt->comp = NULL;
14599 }
14600 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014601
Daniel Veillard4773df22004-01-23 13:15:13 +000014602 if (comp != NULL) {
14603 comp->expr = xmlStrdup(str);
14604#ifdef DEBUG_EVAL_COUNTS
14605 comp->string = xmlStrdup(str);
14606 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014607#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014608 if ((comp->expr != NULL) &&
14609 (comp->nbStep > 2) &&
14610 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014611 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14612 {
14613 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014614 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014615 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014616 return(comp);
14617}
14618
14619/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014620 * xmlXPathCompile:
14621 * @str: the XPath expression
14622 *
14623 * Compile an XPath expression
14624 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014625 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014626 * the caller has to free the object.
14627 */
14628xmlXPathCompExprPtr
14629xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014630 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014631}
14632
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014633/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014634 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014635 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014636 * @ctxt: the XPath context
14637 * @resObj: the resulting XPath object or NULL
14638 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014639 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014640 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014641 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014642 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014643 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014644 * the caller has to free the object.
14645 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014646static int
14647xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14648 xmlXPathContextPtr ctxt,
14649 xmlXPathObjectPtr *resObj,
14650 int toBool)
14651{
14652 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014653#ifndef LIBXML_THREAD_ENABLED
14654 static int reentance = 0;
14655#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014656 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014657
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014658 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014659
14660 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014661 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014662 xmlXPathInit();
14663
Daniel Veillard81463942001-10-16 12:34:39 +000014664#ifndef LIBXML_THREAD_ENABLED
14665 reentance++;
14666 if (reentance > 1)
14667 xmlXPathDisableOptimizer = 1;
14668#endif
14669
Daniel Veillardf06307e2001-07-03 10:35:50 +000014670#ifdef DEBUG_EVAL_COUNTS
14671 comp->nb++;
14672 if ((comp->string != NULL) && (comp->nb > 100)) {
14673 fprintf(stderr, "100 x %s\n", comp->string);
14674 comp->nb = 0;
14675 }
14676#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014677 pctxt = xmlXPathCompParserContext(comp, ctxt);
14678 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014679
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014680 if (resObj) {
14681 if (pctxt->value == NULL) {
14682 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014683 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014684 *resObj = NULL;
14685 } else {
14686 *resObj = valuePop(pctxt);
14687 }
Owen Taylor3473f882001-02-23 17:55:21 +000014688 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014689
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014690 /*
14691 * Pop all remaining objects from the stack.
14692 */
14693 if (pctxt->valueNr > 0) {
14694 xmlXPathObjectPtr tmp;
14695 int stack = 0;
14696
14697 do {
14698 tmp = valuePop(pctxt);
14699 if (tmp != NULL) {
William M. Brackd2f682a2007-05-15 19:42:08 +000014700 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014701 xmlXPathReleaseObject(ctxt, tmp);
14702 }
14703 } while (tmp != NULL);
14704 if ((stack != 0) &&
14705 ((toBool) || ((resObj) && (*resObj))))
14706 {
14707 xmlGenericError(xmlGenericErrorContext,
14708 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14709 stack);
14710 }
Owen Taylor3473f882001-02-23 17:55:21 +000014711 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014712
14713 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14714 xmlXPathFreeObject(*resObj);
14715 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014716 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014717 pctxt->comp = NULL;
14718 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014719#ifndef LIBXML_THREAD_ENABLED
14720 reentance--;
14721#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014722
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014723 return(res);
14724}
14725
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014726/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014727 * xmlXPathCompiledEval:
14728 * @comp: the compiled XPath expression
14729 * @ctx: the XPath context
14730 *
14731 * Evaluate the Precompiled XPath expression in the given context.
14732 *
14733 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14734 * the caller has to free the object.
14735 */
14736xmlXPathObjectPtr
14737xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14738{
14739 xmlXPathObjectPtr res = NULL;
14740
14741 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14742 return(res);
14743}
14744
14745/**
14746 * xmlXPathCompiledEvalToBoolean:
14747 * @comp: the compiled XPath expression
14748 * @ctxt: the XPath context
14749 *
14750 * Applies the XPath boolean() function on the result of the given
14751 * compiled expression.
14752 *
14753 * Returns 1 if the expression evaluated to true, 0 if to false and
14754 * -1 in API and internal errors.
14755 */
14756int
14757xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14758 xmlXPathContextPtr ctxt)
14759{
14760 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14761}
14762
14763/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014764 * xmlXPathEvalExpr:
14765 * @ctxt: the XPath Parser context
14766 *
14767 * Parse and evaluate an XPath expression in the given context,
14768 * then push the result on the context stack
14769 */
14770void
14771xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014772#ifdef XPATH_STREAMING
14773 xmlXPathCompExprPtr comp;
14774#endif
14775
Daniel Veillarda82b1822004-11-08 16:24:57 +000014776 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014777
14778#ifdef XPATH_STREAMING
14779 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14780 if (comp != NULL) {
14781 if (ctxt->comp != NULL)
14782 xmlXPathFreeCompExpr(ctxt->comp);
14783 ctxt->comp = comp;
14784 if (ctxt->cur != NULL)
14785 while (*ctxt->cur != 0) ctxt->cur++;
14786 } else
14787#endif
14788 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014789 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014790 /*
14791 * In this scenario the expression string will sit in ctxt->base.
14792 */
14793 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14794 (ctxt->comp != NULL) &&
14795 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014796 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014797 (ctxt->comp->last >= 0) &&
14798 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014799 {
14800 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014801 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014802 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014803 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014804 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014805 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014806}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014807
14808/**
14809 * xmlXPathEval:
14810 * @str: the XPath expression
14811 * @ctx: the XPath context
14812 *
14813 * Evaluate the XPath Location Path in the given context.
14814 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014815 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014816 * the caller has to free the object.
14817 */
14818xmlXPathObjectPtr
14819xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14820 xmlXPathParserContextPtr ctxt;
14821 xmlXPathObjectPtr res, tmp, init = NULL;
14822 int stack = 0;
14823
William M. Brackf13f77f2004-11-12 16:03:48 +000014824 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014825
William M. Brackf13f77f2004-11-12 16:03:48 +000014826 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014827
14828 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014829 if (ctxt == NULL)
14830 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014831 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014832
14833 if (ctxt->value == NULL) {
14834 xmlGenericError(xmlGenericErrorContext,
14835 "xmlXPathEval: evaluation failed\n");
14836 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014837 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14838#ifdef XPATH_STREAMING
14839 && (ctxt->comp->stream == NULL)
14840#endif
14841 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014842 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14843 res = NULL;
14844 } else {
14845 res = valuePop(ctxt);
14846 }
14847
14848 do {
14849 tmp = valuePop(ctxt);
14850 if (tmp != NULL) {
14851 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014852 stack++;
14853 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014854 }
14855 } while (tmp != NULL);
14856 if ((stack != 0) && (res != NULL)) {
14857 xmlGenericError(xmlGenericErrorContext,
14858 "xmlXPathEval: %d object left on the stack\n",
14859 stack);
14860 }
14861 if (ctxt->error != XPATH_EXPRESSION_OK) {
14862 xmlXPathFreeObject(res);
14863 res = NULL;
14864 }
14865
Owen Taylor3473f882001-02-23 17:55:21 +000014866 xmlXPathFreeParserContext(ctxt);
14867 return(res);
14868}
14869
14870/**
14871 * xmlXPathEvalExpression:
14872 * @str: the XPath expression
14873 * @ctxt: the XPath context
14874 *
14875 * Evaluate the XPath expression in the given context.
14876 *
14877 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14878 * the caller has to free the object.
14879 */
14880xmlXPathObjectPtr
14881xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14882 xmlXPathParserContextPtr pctxt;
14883 xmlXPathObjectPtr res, tmp;
14884 int stack = 0;
14885
William M. Brackf13f77f2004-11-12 16:03:48 +000014886 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014887
William M. Brackf13f77f2004-11-12 16:03:48 +000014888 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014889
14890 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014891 if (pctxt == NULL)
14892 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014893 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014894
Daniel Veillardc465ffc2006-10-17 19:39:33 +000014895 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000014896 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14897 res = NULL;
14898 } else {
14899 res = valuePop(pctxt);
14900 }
14901 do {
14902 tmp = valuePop(pctxt);
14903 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014904 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014905 stack++;
14906 }
14907 } while (tmp != NULL);
14908 if ((stack != 0) && (res != NULL)) {
14909 xmlGenericError(xmlGenericErrorContext,
14910 "xmlXPathEvalExpression: %d object left on the stack\n",
14911 stack);
14912 }
14913 xmlXPathFreeParserContext(pctxt);
14914 return(res);
14915}
14916
Daniel Veillard42766c02002-08-22 20:52:17 +000014917/************************************************************************
14918 * *
14919 * Extra functions not pertaining to the XPath spec *
14920 * *
14921 ************************************************************************/
14922/**
14923 * xmlXPathEscapeUriFunction:
14924 * @ctxt: the XPath Parser context
14925 * @nargs: the number of arguments
14926 *
14927 * Implement the escape-uri() XPath function
14928 * string escape-uri(string $str, bool $escape-reserved)
14929 *
14930 * This function applies the URI escaping rules defined in section 2 of [RFC
14931 * 2396] to the string supplied as $uri-part, which typically represents all
14932 * or part of a URI. The effect of the function is to replace any special
14933 * character in the string by an escape sequence of the form %xx%yy...,
14934 * where xxyy... is the hexadecimal representation of the octets used to
14935 * represent the character in UTF-8.
14936 *
14937 * The set of characters that are escaped depends on the setting of the
14938 * boolean argument $escape-reserved.
14939 *
14940 * If $escape-reserved is true, all characters are escaped other than lower
14941 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14942 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14943 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14944 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14945 * A-F).
14946 *
14947 * If $escape-reserved is false, the behavior differs in that characters
14948 * referred to in [RFC 2396] as reserved characters are not escaped. These
14949 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14950 *
14951 * [RFC 2396] does not define whether escaped URIs should use lower case or
14952 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14953 * compared using string comparison functions, this function must always use
14954 * the upper-case letters A-F.
14955 *
14956 * Generally, $escape-reserved should be set to true when escaping a string
14957 * that is to form a single part of a URI, and to false when escaping an
14958 * entire URI or URI reference.
14959 *
14960 * In the case of non-ascii characters, the string is encoded according to
14961 * utf-8 and then converted according to RFC 2396.
14962 *
14963 * Examples
14964 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14965 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14966 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14967 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14968 *
14969 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014970static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014971xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14972 xmlXPathObjectPtr str;
14973 int escape_reserved;
14974 xmlBufferPtr target;
14975 xmlChar *cptr;
14976 xmlChar escape[4];
14977
14978 CHECK_ARITY(2);
14979
14980 escape_reserved = xmlXPathPopBoolean(ctxt);
14981
14982 CAST_TO_STRING;
14983 str = valuePop(ctxt);
14984
14985 target = xmlBufferCreate();
14986
14987 escape[0] = '%';
14988 escape[3] = 0;
14989
14990 if (target) {
14991 for (cptr = str->stringval; *cptr; cptr++) {
14992 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14993 (*cptr >= 'a' && *cptr <= 'z') ||
14994 (*cptr >= '0' && *cptr <= '9') ||
14995 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14996 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14997 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14998 (*cptr == '%' &&
14999 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15000 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15001 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15002 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15003 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15004 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15005 (!escape_reserved &&
15006 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15007 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15008 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15009 *cptr == ','))) {
15010 xmlBufferAdd(target, cptr, 1);
15011 } else {
15012 if ((*cptr >> 4) < 10)
15013 escape[1] = '0' + (*cptr >> 4);
15014 else
15015 escape[1] = 'A' - 10 + (*cptr >> 4);
15016 if ((*cptr & 0xF) < 10)
15017 escape[2] = '0' + (*cptr & 0xF);
15018 else
15019 escape[2] = 'A' - 10 + (*cptr & 0xF);
15020
15021 xmlBufferAdd(target, &escape[0], 3);
15022 }
15023 }
15024 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015025 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15026 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015027 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015028 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015029}
15030
Owen Taylor3473f882001-02-23 17:55:21 +000015031/**
15032 * xmlXPathRegisterAllFunctions:
15033 * @ctxt: the XPath context
15034 *
15035 * Registers all default XPath functions in this context
15036 */
15037void
15038xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15039{
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15041 xmlXPathBooleanFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15043 xmlXPathCeilingFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15045 xmlXPathCountFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15047 xmlXPathConcatFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15049 xmlXPathContainsFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15051 xmlXPathIdFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15053 xmlXPathFalseFunction);
15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15055 xmlXPathFloorFunction);
15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15057 xmlXPathLastFunction);
15058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15059 xmlXPathLangFunction);
15060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15061 xmlXPathLocalNameFunction);
15062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15063 xmlXPathNotFunction);
15064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15065 xmlXPathNameFunction);
15066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15067 xmlXPathNamespaceURIFunction);
15068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15069 xmlXPathNormalizeFunction);
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15071 xmlXPathNumberFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15073 xmlXPathPositionFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15075 xmlXPathRoundFunction);
15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15077 xmlXPathStringFunction);
15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15079 xmlXPathStringLengthFunction);
15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15081 xmlXPathStartsWithFunction);
15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15083 xmlXPathSubstringFunction);
15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15085 xmlXPathSubstringBeforeFunction);
15086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15087 xmlXPathSubstringAfterFunction);
15088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15089 xmlXPathSumFunction);
15090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15091 xmlXPathTrueFunction);
15092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15093 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015094
15095 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15096 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15097 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015098}
15099
15100#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015101#define bottom_xpath
15102#include "elfgcchack.h"