blob: 209c2e90d59ed9ba1de7115e5442d60f85c8e742 [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
3197 if (node1 == node2->prev)
3198 return(1);
3199 if (node1 == node2->next)
3200 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003201 /*
3202 * compute depth to root
3203 */
3204 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3205 if (cur == node1)
3206 return(1);
3207 depth2++;
3208 }
3209 root = cur;
3210 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3211 if (cur == node2)
3212 return(-1);
3213 depth1++;
3214 }
3215 /*
3216 * Distinct document (or distinct entities :-( ) case.
3217 */
3218 if (root != cur) {
3219 return(-2);
3220 }
3221 /*
3222 * get the nearest common ancestor.
3223 */
3224 while (depth1 > depth2) {
3225 depth1--;
3226 node1 = node1->parent;
3227 }
3228 while (depth2 > depth1) {
3229 depth2--;
3230 node2 = node2->parent;
3231 }
3232 while (node1->parent != node2->parent) {
3233 node1 = node1->parent;
3234 node2 = node2->parent;
3235 /* should not happen but just in case ... */
3236 if ((node1 == NULL) || (node2 == NULL))
3237 return(-2);
3238 }
3239 /*
3240 * Find who's first.
3241 */
3242 if (node1 == node2->prev)
3243 return(1);
3244 if (node1 == node2->next)
3245 return(-1);
3246 /*
3247 * Speedup using document order if availble.
3248 */
3249 if ((node1->type == XML_ELEMENT_NODE) &&
3250 (node2->type == XML_ELEMENT_NODE) &&
3251 (0 > (long) node1->content) &&
3252 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003253 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003254
3255 l1 = -((long) node1->content);
3256 l2 = -((long) node2->content);
3257 if (l1 < l2)
3258 return(1);
3259 if (l1 > l2)
3260 return(-1);
3261 }
3262
3263 for (cur = node1->next;cur != NULL;cur = cur->next)
3264 if (cur == node2)
3265 return(1);
3266 return(-1); /* assume there is no sibling list corruption */
3267}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003268#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003269
Owen Taylor3473f882001-02-23 17:55:21 +00003270/**
3271 * xmlXPathNodeSetSort:
3272 * @set: the node set
3273 *
3274 * Sort the node set in document order
3275 */
3276void
3277xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003278 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003279 xmlNodePtr tmp;
3280
3281 if (set == NULL)
3282 return;
3283
3284 /* Use Shell's sort to sort the node-set */
3285 len = set->nodeNr;
3286 for (incr = len / 2; incr > 0; incr /= 2) {
3287 for (i = incr; i < len; i++) {
3288 j = i - incr;
3289 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003290#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003291 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3292 set->nodeTab[j + incr]) == -1)
3293#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003294 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003295 set->nodeTab[j + incr]) == -1)
3296#endif
3297 {
Owen Taylor3473f882001-02-23 17:55:21 +00003298 tmp = set->nodeTab[j];
3299 set->nodeTab[j] = set->nodeTab[j + incr];
3300 set->nodeTab[j + incr] = tmp;
3301 j -= incr;
3302 } else
3303 break;
3304 }
3305 }
3306 }
3307}
3308
3309#define XML_NODESET_DEFAULT 10
3310/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003311 * xmlXPathNodeSetDupNs:
3312 * @node: the parent node of the namespace XPath node
3313 * @ns: the libxml namespace declaration node.
3314 *
3315 * Namespace node in libxml don't match the XPath semantic. In a node set
3316 * the namespace nodes are duplicated and the next pointer is set to the
3317 * parent node in the XPath semantic.
3318 *
3319 * Returns the newly created object.
3320 */
3321static xmlNodePtr
3322xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3323 xmlNsPtr cur;
3324
3325 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3326 return(NULL);
3327 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3328 return((xmlNodePtr) ns);
3329
3330 /*
3331 * Allocate a new Namespace and fill the fields.
3332 */
3333 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3334 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003335 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003336 return(NULL);
3337 }
3338 memset(cur, 0, sizeof(xmlNs));
3339 cur->type = XML_NAMESPACE_DECL;
3340 if (ns->href != NULL)
3341 cur->href = xmlStrdup(ns->href);
3342 if (ns->prefix != NULL)
3343 cur->prefix = xmlStrdup(ns->prefix);
3344 cur->next = (xmlNsPtr) node;
3345 return((xmlNodePtr) cur);
3346}
3347
3348/**
3349 * xmlXPathNodeSetFreeNs:
3350 * @ns: the XPath namespace node found in a nodeset.
3351 *
William M. Brack08171912003-12-29 02:52:11 +00003352 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003353 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003354 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003355 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003356void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003357xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3358 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3359 return;
3360
3361 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3362 if (ns->href != NULL)
3363 xmlFree((xmlChar *)ns->href);
3364 if (ns->prefix != NULL)
3365 xmlFree((xmlChar *)ns->prefix);
3366 xmlFree(ns);
3367 }
3368}
3369
3370/**
Owen Taylor3473f882001-02-23 17:55:21 +00003371 * xmlXPathNodeSetCreate:
3372 * @val: an initial xmlNodePtr, or NULL
3373 *
3374 * Create a new xmlNodeSetPtr of type double and of value @val
3375 *
3376 * Returns the newly created object.
3377 */
3378xmlNodeSetPtr
3379xmlXPathNodeSetCreate(xmlNodePtr val) {
3380 xmlNodeSetPtr ret;
3381
3382 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3383 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003384 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003385 return(NULL);
3386 }
3387 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3388 if (val != NULL) {
3389 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3390 sizeof(xmlNodePtr));
3391 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003392 xmlXPathErrMemory(NULL, "creating nodeset\n");
3393 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003394 return(NULL);
3395 }
3396 memset(ret->nodeTab, 0 ,
3397 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3398 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003399 if (val->type == XML_NAMESPACE_DECL) {
3400 xmlNsPtr ns = (xmlNsPtr) val;
3401
3402 ret->nodeTab[ret->nodeNr++] =
3403 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3404 } else
3405 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003406 }
3407 return(ret);
3408}
3409
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003410/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003411 * xmlXPathNodeSetCreateSize:
3412 * @size: the initial size of the set
3413 *
3414 * Create a new xmlNodeSetPtr of type double and of value @val
3415 *
3416 * Returns the newly created object.
3417 */
3418static xmlNodeSetPtr
3419xmlXPathNodeSetCreateSize(int size) {
3420 xmlNodeSetPtr ret;
3421
3422 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3423 if (ret == NULL) {
3424 xmlXPathErrMemory(NULL, "creating nodeset\n");
3425 return(NULL);
3426 }
3427 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3428 if (size < XML_NODESET_DEFAULT)
3429 size = XML_NODESET_DEFAULT;
3430 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3431 if (ret->nodeTab == NULL) {
3432 xmlXPathErrMemory(NULL, "creating nodeset\n");
3433 xmlFree(ret);
3434 return(NULL);
3435 }
3436 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3437 ret->nodeMax = size;
3438 return(ret);
3439}
3440
3441/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003442 * xmlXPathNodeSetContains:
3443 * @cur: the node-set
3444 * @val: the node
3445 *
3446 * checks whether @cur contains @val
3447 *
3448 * Returns true (1) if @cur contains @val, false (0) otherwise
3449 */
3450int
3451xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3452 int i;
3453
Daniel Veillarda82b1822004-11-08 16:24:57 +00003454 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003455 if (val->type == XML_NAMESPACE_DECL) {
3456 for (i = 0; i < cur->nodeNr; i++) {
3457 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3458 xmlNsPtr ns1, ns2;
3459
3460 ns1 = (xmlNsPtr) val;
3461 ns2 = (xmlNsPtr) cur->nodeTab[i];
3462 if (ns1 == ns2)
3463 return(1);
3464 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3465 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3466 return(1);
3467 }
3468 }
3469 } else {
3470 for (i = 0; i < cur->nodeNr; i++) {
3471 if (cur->nodeTab[i] == val)
3472 return(1);
3473 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003474 }
3475 return(0);
3476}
3477
3478/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003479 * xmlXPathNodeSetAddNs:
3480 * @cur: the initial node set
3481 * @node: the hosting node
3482 * @ns: a the namespace node
3483 *
3484 * add a new namespace node to an existing NodeSet
3485 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003486void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003487xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3488 int i;
3489
Daniel Veillarda82b1822004-11-08 16:24:57 +00003490
3491 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3492 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003493 (node->type != XML_ELEMENT_NODE))
3494 return;
3495
William M. Brack08171912003-12-29 02:52:11 +00003496 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003497 /*
William M. Brack08171912003-12-29 02:52:11 +00003498 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003499 */
3500 for (i = 0;i < cur->nodeNr;i++) {
3501 if ((cur->nodeTab[i] != NULL) &&
3502 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003503 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003504 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3505 return;
3506 }
3507
3508 /*
3509 * grow the nodeTab if needed
3510 */
3511 if (cur->nodeMax == 0) {
3512 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3513 sizeof(xmlNodePtr));
3514 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003515 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003516 return;
3517 }
3518 memset(cur->nodeTab, 0 ,
3519 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3520 cur->nodeMax = XML_NODESET_DEFAULT;
3521 } else if (cur->nodeNr == cur->nodeMax) {
3522 xmlNodePtr *temp;
3523
3524 cur->nodeMax *= 2;
3525 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3526 sizeof(xmlNodePtr));
3527 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003528 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003529 return;
3530 }
3531 cur->nodeTab = temp;
3532 }
3533 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3534}
3535
3536/**
Owen Taylor3473f882001-02-23 17:55:21 +00003537 * xmlXPathNodeSetAdd:
3538 * @cur: the initial node set
3539 * @val: a new xmlNodePtr
3540 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003541 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003542 */
3543void
3544xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3545 int i;
3546
Daniel Veillarda82b1822004-11-08 16:24:57 +00003547 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003548
Daniel Veillardef0b4502003-03-24 13:57:34 +00003549#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003550 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3551 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003552#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003553
William M. Brack08171912003-12-29 02:52:11 +00003554 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003555 /*
William M. Brack08171912003-12-29 02:52:11 +00003556 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003557 */
3558 for (i = 0;i < cur->nodeNr;i++)
3559 if (cur->nodeTab[i] == val) return;
3560
3561 /*
3562 * grow the nodeTab if needed
3563 */
3564 if (cur->nodeMax == 0) {
3565 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3566 sizeof(xmlNodePtr));
3567 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003568 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003569 return;
3570 }
3571 memset(cur->nodeTab, 0 ,
3572 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3573 cur->nodeMax = XML_NODESET_DEFAULT;
3574 } else if (cur->nodeNr == cur->nodeMax) {
3575 xmlNodePtr *temp;
3576
3577 cur->nodeMax *= 2;
3578 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3579 sizeof(xmlNodePtr));
3580 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003581 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003582 return;
3583 }
3584 cur->nodeTab = temp;
3585 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003586 if (val->type == XML_NAMESPACE_DECL) {
3587 xmlNsPtr ns = (xmlNsPtr) val;
3588
3589 cur->nodeTab[cur->nodeNr++] =
3590 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3591 } else
3592 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003593}
3594
3595/**
3596 * xmlXPathNodeSetAddUnique:
3597 * @cur: the initial node set
3598 * @val: a new xmlNodePtr
3599 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003600 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003601 * when we are sure the node is not already in the set.
3602 */
3603void
3604xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003605 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003606
Daniel Veillardef0b4502003-03-24 13:57:34 +00003607#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003608 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3609 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003610#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003611
William M. Brack08171912003-12-29 02:52:11 +00003612 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003613 /*
3614 * grow the nodeTab if needed
3615 */
3616 if (cur->nodeMax == 0) {
3617 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3618 sizeof(xmlNodePtr));
3619 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003620 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003621 return;
3622 }
3623 memset(cur->nodeTab, 0 ,
3624 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3625 cur->nodeMax = XML_NODESET_DEFAULT;
3626 } else if (cur->nodeNr == cur->nodeMax) {
3627 xmlNodePtr *temp;
3628
3629 cur->nodeMax *= 2;
3630 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3631 sizeof(xmlNodePtr));
3632 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003633 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003634 return;
3635 }
3636 cur->nodeTab = temp;
3637 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003638 if (val->type == XML_NAMESPACE_DECL) {
3639 xmlNsPtr ns = (xmlNsPtr) val;
3640
3641 cur->nodeTab[cur->nodeNr++] =
3642 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3643 } else
3644 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003645}
3646
3647/**
3648 * xmlXPathNodeSetMerge:
3649 * @val1: the first NodeSet or NULL
3650 * @val2: the second NodeSet
3651 *
3652 * Merges two nodesets, all nodes from @val2 are added to @val1
3653 * if @val1 is NULL, a new set is created and copied from @val2
3654 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003655 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003656 */
3657xmlNodeSetPtr
3658xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003659 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003660 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003661
3662 if (val2 == NULL) return(val1);
3663 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003664 val1 = xmlXPathNodeSetCreate(NULL);
3665#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003666 /*
3667 * TODO: The optimization won't work in every case, since
3668 * those nasty namespace nodes need to be added with
3669 * xmlXPathNodeSetDupNs() to the set; thus a pure
3670 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003671 * If there was a flag on the nodesetval, indicating that
3672 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003673 */
3674 /*
3675 * Optimization: Create an equally sized node-set
3676 * and memcpy the content.
3677 */
3678 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3679 if (val1 == NULL)
3680 return(NULL);
3681 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003682 if (val2->nodeNr == 1)
3683 *(val1->nodeTab) = *(val2->nodeTab);
3684 else {
3685 memcpy(val1->nodeTab, val2->nodeTab,
3686 val2->nodeNr * sizeof(xmlNodePtr));
3687 }
3688 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003689 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003690 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003691#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003692 }
3693
William M. Brack08171912003-12-29 02:52:11 +00003694 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003695 initNr = val1->nodeNr;
3696
3697 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003698 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003699 /*
William M. Brack08171912003-12-29 02:52:11 +00003700 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003701 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003702 skip = 0;
3703 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003704 n1 = val1->nodeTab[j];
3705 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003706 skip = 1;
3707 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003708 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3709 (n2->type == XML_NAMESPACE_DECL)) {
3710 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3711 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3712 ((xmlNsPtr) n2)->prefix)))
3713 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003714 skip = 1;
3715 break;
3716 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003717 }
3718 }
3719 if (skip)
3720 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003721
3722 /*
3723 * grow the nodeTab if needed
3724 */
3725 if (val1->nodeMax == 0) {
3726 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3727 sizeof(xmlNodePtr));
3728 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003729 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003730 return(NULL);
3731 }
3732 memset(val1->nodeTab, 0 ,
3733 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3734 val1->nodeMax = XML_NODESET_DEFAULT;
3735 } else if (val1->nodeNr == val1->nodeMax) {
3736 xmlNodePtr *temp;
3737
3738 val1->nodeMax *= 2;
3739 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3740 sizeof(xmlNodePtr));
3741 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003742 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003743 return(NULL);
3744 }
3745 val1->nodeTab = temp;
3746 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003747 if (n2->type == XML_NAMESPACE_DECL) {
3748 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003749
3750 val1->nodeTab[val1->nodeNr++] =
3751 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3752 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003753 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003754 }
3755
3756 return(val1);
3757}
3758
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003759#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003760/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003761 * xmlXPathNodeSetMergeUnique:
3762 * @val1: the first NodeSet or NULL
3763 * @val2: the second NodeSet
3764 *
3765 * Merges two nodesets, all nodes from @val2 are added to @val1
3766 * if @val1 is NULL, a new set is created and copied from @val2
3767 *
3768 * Returns @val1 once extended or NULL in case of error.
3769 */
3770static xmlNodeSetPtr
3771xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003772 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003773
3774 if (val2 == NULL) return(val1);
3775 if (val1 == NULL) {
3776 val1 = xmlXPathNodeSetCreate(NULL);
3777 }
3778
William M. Brack08171912003-12-29 02:52:11 +00003779 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003780
3781 for (i = 0;i < val2->nodeNr;i++) {
3782 /*
3783 * grow the nodeTab if needed
3784 */
3785 if (val1->nodeMax == 0) {
3786 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3787 sizeof(xmlNodePtr));
3788 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003789 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003790 return(NULL);
3791 }
3792 memset(val1->nodeTab, 0 ,
3793 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3794 val1->nodeMax = XML_NODESET_DEFAULT;
3795 } else if (val1->nodeNr == val1->nodeMax) {
3796 xmlNodePtr *temp;
3797
3798 val1->nodeMax *= 2;
3799 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3800 sizeof(xmlNodePtr));
3801 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003802 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003803 return(NULL);
3804 }
3805 val1->nodeTab = temp;
3806 }
3807 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3808 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3809
3810 val1->nodeTab[val1->nodeNr++] =
3811 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3812 } else
3813 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3814 }
3815
3816 return(val1);
3817}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003818#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3819
3820/**
3821 * xmlXPathNodeSetMergeAndClear:
3822 * @set1: the first NodeSet or NULL
3823 * @set2: the second NodeSet
3824 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3825 *
3826 * Merges two nodesets, all nodes from @set2 are added to @set1
3827 * if @set1 is NULL, a new set is created and copied from @set2.
3828 * Checks for duplicate nodes. Clears set2.
3829 *
3830 * Returns @set1 once extended or NULL in case of error.
3831 */
3832static xmlNodeSetPtr
3833xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3834 int hasNullEntries)
3835{
3836 if ((set1 == NULL) && (hasNullEntries == 0)) {
3837 /*
3838 * Note that doing a memcpy of the list, namespace nodes are
3839 * just assigned to set1, since set2 is cleared anyway.
3840 */
3841 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3842 if (set1 == NULL)
3843 return(NULL);
3844 if (set2->nodeNr != 0) {
3845 memcpy(set1->nodeTab, set2->nodeTab,
3846 set2->nodeNr * sizeof(xmlNodePtr));
3847 set1->nodeNr = set2->nodeNr;
3848 }
3849 } else {
3850 int i, j, initNbSet1;
3851 xmlNodePtr n1, n2;
3852
3853 if (set1 == NULL)
3854 set1 = xmlXPathNodeSetCreate(NULL);
3855
3856 initNbSet1 = set1->nodeNr;
3857 for (i = 0;i < set2->nodeNr;i++) {
3858 n2 = set2->nodeTab[i];
3859 /*
3860 * Skip NULLed entries.
3861 */
3862 if (n2 == NULL)
3863 continue;
3864 /*
3865 * Skip duplicates.
3866 */
3867 for (j = 0; j < initNbSet1; j++) {
3868 n1 = set1->nodeTab[j];
3869 if (n1 == n2) {
3870 goto skip_node;
3871 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3872 (n2->type == XML_NAMESPACE_DECL))
3873 {
3874 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3875 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3876 ((xmlNsPtr) n2)->prefix)))
3877 {
3878 /*
3879 * Free the namespace node.
3880 */
3881 set2->nodeTab[i] = NULL;
3882 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3883 goto skip_node;
3884 }
3885 }
3886 }
3887 /*
3888 * grow the nodeTab if needed
3889 */
3890 if (set1->nodeMax == 0) {
3891 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3892 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3893 if (set1->nodeTab == NULL) {
3894 xmlXPathErrMemory(NULL, "merging nodeset\n");
3895 return(NULL);
3896 }
3897 memset(set1->nodeTab, 0,
3898 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3899 set1->nodeMax = XML_NODESET_DEFAULT;
3900 } else if (set1->nodeNr >= set1->nodeMax) {
3901 xmlNodePtr *temp;
3902
3903 set1->nodeMax *= 2;
3904 temp = (xmlNodePtr *) xmlRealloc(
3905 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3906 if (temp == NULL) {
3907 xmlXPathErrMemory(NULL, "merging nodeset\n");
3908 return(NULL);
3909 }
3910 set1->nodeTab = temp;
3911 }
3912 if (n2->type == XML_NAMESPACE_DECL) {
3913 xmlNsPtr ns = (xmlNsPtr) n2;
3914
3915 set1->nodeTab[set1->nodeNr++] =
3916 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3917 } else
3918 set1->nodeTab[set1->nodeNr++] = n2;
3919skip_node:
3920 {}
3921 }
3922 }
3923 set2->nodeNr = 0;
3924 return(set1);
3925}
3926
3927/**
3928 * xmlXPathNodeSetMergeAndClearNoDupls:
3929 * @set1: the first NodeSet or NULL
3930 * @set2: the second NodeSet
3931 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3932 *
3933 * Merges two nodesets, all nodes from @set2 are added to @set1
3934 * if @set1 is NULL, a new set is created and copied from @set2.
3935 * Doesn't chack for duplicate nodes. Clears set2.
3936 *
3937 * Returns @set1 once extended or NULL in case of error.
3938 */
3939static xmlNodeSetPtr
3940xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3941 int hasNullEntries)
3942{
3943 if (set2 == NULL)
3944 return(set1);
3945 if ((set1 == NULL) && (hasNullEntries == 0)) {
3946 /*
3947 * Note that doing a memcpy of the list, namespace nodes are
3948 * just assigned to set1, since set2 is cleared anyway.
3949 */
3950 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3951 if (set1 == NULL)
3952 return(NULL);
3953 if (set2->nodeNr != 0) {
3954 memcpy(set1->nodeTab, set2->nodeTab,
3955 set2->nodeNr * sizeof(xmlNodePtr));
3956 set1->nodeNr = set2->nodeNr;
3957 }
3958 } else {
3959 int i;
3960 xmlNodePtr n2;
3961
3962 if (set1 == NULL)
3963 set1 = xmlXPathNodeSetCreate(NULL);
3964
3965 for (i = 0;i < set2->nodeNr;i++) {
3966 n2 = set2->nodeTab[i];
3967 /*
3968 * Skip NULLed entries.
3969 */
3970 if (n2 == NULL)
3971 continue;
3972 if (set1->nodeMax == 0) {
3973 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3974 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3975 if (set1->nodeTab == NULL) {
3976 xmlXPathErrMemory(NULL, "merging nodeset\n");
3977 return(NULL);
3978 }
3979 memset(set1->nodeTab, 0,
3980 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3981 set1->nodeMax = XML_NODESET_DEFAULT;
3982 } else if (set1->nodeNr >= set1->nodeMax) {
3983 xmlNodePtr *temp;
3984
3985 set1->nodeMax *= 2;
3986 temp = (xmlNodePtr *) xmlRealloc(
3987 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3988 if (temp == NULL) {
3989 xmlXPathErrMemory(NULL, "merging nodeset\n");
3990 return(NULL);
3991 }
3992 set1->nodeTab = temp;
3993 }
3994 set1->nodeTab[set1->nodeNr++] = n2;
3995 }
3996 }
3997 set2->nodeNr = 0;
3998 return(set1);
3999}
Daniel Veillard75be0132002-03-13 10:03:35 +00004000
4001/**
Owen Taylor3473f882001-02-23 17:55:21 +00004002 * xmlXPathNodeSetDel:
4003 * @cur: the initial node set
4004 * @val: an xmlNodePtr
4005 *
4006 * Removes an xmlNodePtr from an existing NodeSet
4007 */
4008void
4009xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4010 int i;
4011
4012 if (cur == NULL) return;
4013 if (val == NULL) return;
4014
4015 /*
William M. Brack08171912003-12-29 02:52:11 +00004016 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004017 */
4018 for (i = 0;i < cur->nodeNr;i++)
4019 if (cur->nodeTab[i] == val) break;
4020
William M. Brack08171912003-12-29 02:52:11 +00004021 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004022#ifdef DEBUG
4023 xmlGenericError(xmlGenericErrorContext,
4024 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4025 val->name);
4026#endif
4027 return;
4028 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004029 if ((cur->nodeTab[i] != NULL) &&
4030 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4031 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004032 cur->nodeNr--;
4033 for (;i < cur->nodeNr;i++)
4034 cur->nodeTab[i] = cur->nodeTab[i + 1];
4035 cur->nodeTab[cur->nodeNr] = NULL;
4036}
4037
4038/**
4039 * xmlXPathNodeSetRemove:
4040 * @cur: the initial node set
4041 * @val: the index to remove
4042 *
4043 * Removes an entry from an existing NodeSet list.
4044 */
4045void
4046xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4047 if (cur == NULL) return;
4048 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004049 if ((cur->nodeTab[val] != NULL) &&
4050 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4051 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004052 cur->nodeNr--;
4053 for (;val < cur->nodeNr;val++)
4054 cur->nodeTab[val] = cur->nodeTab[val + 1];
4055 cur->nodeTab[cur->nodeNr] = NULL;
4056}
4057
4058/**
4059 * xmlXPathFreeNodeSet:
4060 * @obj: the xmlNodeSetPtr to free
4061 *
4062 * Free the NodeSet compound (not the actual nodes !).
4063 */
4064void
4065xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4066 if (obj == NULL) return;
4067 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004068 int i;
4069
William M. Brack08171912003-12-29 02:52:11 +00004070 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004071 for (i = 0;i < obj->nodeNr;i++)
4072 if ((obj->nodeTab[i] != NULL) &&
4073 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004075 xmlFree(obj->nodeTab);
4076 }
Owen Taylor3473f882001-02-23 17:55:21 +00004077 xmlFree(obj);
4078}
4079
4080/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004081 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004082 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004083 *
4084 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4085 * are feed), but does *not* free the list itself. Sets the length of the
4086 * list to 0.
4087 */
4088static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004089xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4090{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004091 if ((set == NULL) || (set->nodeNr <= 0))
4092 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004093 else if (hasNsNodes) {
4094 int i;
4095 xmlNodePtr node;
4096
4097 for (i = 0; i < set->nodeNr; i++) {
4098 node = set->nodeTab[i];
4099 if ((node != NULL) &&
4100 (node->type == XML_NAMESPACE_DECL))
4101 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4102 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004103 }
4104 set->nodeNr = 0;
4105}
4106
4107/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004108 * xmlXPathNodeSetClearFromPos:
4109 * @set: the node set to be cleared
4110 * @pos: the start position to clear from
4111 *
4112 * Clears the list from temporary XPath objects (e.g. namespace nodes
4113 * are feed) starting with the entry at @pos, but does *not* free the list
4114 * itself. Sets the length of the list to @pos.
4115 */
4116static void
4117xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4118{
4119 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4120 return;
4121 else if ((hasNsNodes)) {
4122 int i;
4123 xmlNodePtr node;
4124
4125 for (i = pos; i < set->nodeNr; i++) {
4126 node = set->nodeTab[i];
4127 if ((node != NULL) &&
4128 (node->type == XML_NAMESPACE_DECL))
4129 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4130 }
4131 }
4132 set->nodeNr = pos;
4133}
4134
4135/**
Owen Taylor3473f882001-02-23 17:55:21 +00004136 * xmlXPathFreeValueTree:
4137 * @obj: the xmlNodeSetPtr to free
4138 *
4139 * Free the NodeSet compound and the actual tree, this is different
4140 * from xmlXPathFreeNodeSet()
4141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004142static void
Owen Taylor3473f882001-02-23 17:55:21 +00004143xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4144 int i;
4145
4146 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004147
4148 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004149 for (i = 0;i < obj->nodeNr;i++) {
4150 if (obj->nodeTab[i] != NULL) {
4151 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4152 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4153 } else {
4154 xmlFreeNodeList(obj->nodeTab[i]);
4155 }
4156 }
4157 }
Owen Taylor3473f882001-02-23 17:55:21 +00004158 xmlFree(obj->nodeTab);
4159 }
Owen Taylor3473f882001-02-23 17:55:21 +00004160 xmlFree(obj);
4161}
4162
4163#if defined(DEBUG) || defined(DEBUG_STEP)
4164/**
4165 * xmlGenericErrorContextNodeSet:
4166 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004167 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004168 *
4169 * Quick display of a NodeSet
4170 */
4171void
4172xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4173 int i;
4174
4175 if (output == NULL) output = xmlGenericErrorContext;
4176 if (obj == NULL) {
4177 fprintf(output, "NodeSet == NULL !\n");
4178 return;
4179 }
4180 if (obj->nodeNr == 0) {
4181 fprintf(output, "NodeSet is empty\n");
4182 return;
4183 }
4184 if (obj->nodeTab == NULL) {
4185 fprintf(output, " nodeTab == NULL !\n");
4186 return;
4187 }
4188 for (i = 0; i < obj->nodeNr; i++) {
4189 if (obj->nodeTab[i] == NULL) {
4190 fprintf(output, " NULL !\n");
4191 return;
4192 }
4193 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4194 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4195 fprintf(output, " /");
4196 else if (obj->nodeTab[i]->name == NULL)
4197 fprintf(output, " noname!");
4198 else fprintf(output, " %s", obj->nodeTab[i]->name);
4199 }
4200 fprintf(output, "\n");
4201}
4202#endif
4203
4204/**
4205 * xmlXPathNewNodeSet:
4206 * @val: the NodePtr value
4207 *
4208 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4209 * it with the single Node @val
4210 *
4211 * Returns the newly created object.
4212 */
4213xmlXPathObjectPtr
4214xmlXPathNewNodeSet(xmlNodePtr val) {
4215 xmlXPathObjectPtr ret;
4216
4217 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4218 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004219 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004220 return(NULL);
4221 }
4222 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4223 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004224 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004225 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004226 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004227#ifdef XP_DEBUG_OBJ_USAGE
4228 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4229#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004230 return(ret);
4231}
4232
4233/**
4234 * xmlXPathNewValueTree:
4235 * @val: the NodePtr value
4236 *
4237 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4238 * it with the tree root @val
4239 *
4240 * Returns the newly created object.
4241 */
4242xmlXPathObjectPtr
4243xmlXPathNewValueTree(xmlNodePtr val) {
4244 xmlXPathObjectPtr ret;
4245
4246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004248 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004249 return(NULL);
4250 }
4251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4252 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004253 ret->boolval = 1;
4254 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004255 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004256#ifdef XP_DEBUG_OBJ_USAGE
4257 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4258#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004259 return(ret);
4260}
4261
4262/**
4263 * xmlXPathNewNodeSetList:
4264 * @val: an existing NodeSet
4265 *
4266 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4267 * it with the Nodeset @val
4268 *
4269 * Returns the newly created object.
4270 */
4271xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004272xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4273{
Owen Taylor3473f882001-02-23 17:55:21 +00004274 xmlXPathObjectPtr ret;
4275 int i;
4276
4277 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004278 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004279 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004280 ret = xmlXPathNewNodeSet(NULL);
4281 else {
4282 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4283 for (i = 1; i < val->nodeNr; ++i)
4284 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4285 }
Owen Taylor3473f882001-02-23 17:55:21 +00004286
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004287 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004288}
4289
4290/**
4291 * xmlXPathWrapNodeSet:
4292 * @val: the NodePtr value
4293 *
4294 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4295 *
4296 * Returns the newly created object.
4297 */
4298xmlXPathObjectPtr
4299xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4300 xmlXPathObjectPtr ret;
4301
4302 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4303 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004304 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004305 return(NULL);
4306 }
4307 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4308 ret->type = XPATH_NODESET;
4309 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004310#ifdef XP_DEBUG_OBJ_USAGE
4311 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4312#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004313 return(ret);
4314}
4315
4316/**
4317 * xmlXPathFreeNodeSetList:
4318 * @obj: an existing NodeSetList object
4319 *
4320 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4321 * the list contrary to xmlXPathFreeObject().
4322 */
4323void
4324xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4325 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004326#ifdef XP_DEBUG_OBJ_USAGE
4327 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4328#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004329 xmlFree(obj);
4330}
4331
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004332/**
4333 * xmlXPathDifference:
4334 * @nodes1: a node-set
4335 * @nodes2: a node-set
4336 *
4337 * Implements the EXSLT - Sets difference() function:
4338 * node-set set:difference (node-set, node-set)
4339 *
4340 * Returns the difference between the two node sets, or nodes1 if
4341 * nodes2 is empty
4342 */
4343xmlNodeSetPtr
4344xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4345 xmlNodeSetPtr ret;
4346 int i, l1;
4347 xmlNodePtr cur;
4348
4349 if (xmlXPathNodeSetIsEmpty(nodes2))
4350 return(nodes1);
4351
4352 ret = xmlXPathNodeSetCreate(NULL);
4353 if (xmlXPathNodeSetIsEmpty(nodes1))
4354 return(ret);
4355
4356 l1 = xmlXPathNodeSetGetLength(nodes1);
4357
4358 for (i = 0; i < l1; i++) {
4359 cur = xmlXPathNodeSetItem(nodes1, i);
4360 if (!xmlXPathNodeSetContains(nodes2, cur))
4361 xmlXPathNodeSetAddUnique(ret, cur);
4362 }
4363 return(ret);
4364}
4365
4366/**
4367 * xmlXPathIntersection:
4368 * @nodes1: a node-set
4369 * @nodes2: a node-set
4370 *
4371 * Implements the EXSLT - Sets intersection() function:
4372 * node-set set:intersection (node-set, node-set)
4373 *
4374 * Returns a node set comprising the nodes that are within both the
4375 * node sets passed as arguments
4376 */
4377xmlNodeSetPtr
4378xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4379 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4380 int i, l1;
4381 xmlNodePtr cur;
4382
4383 if (xmlXPathNodeSetIsEmpty(nodes1))
4384 return(ret);
4385 if (xmlXPathNodeSetIsEmpty(nodes2))
4386 return(ret);
4387
4388 l1 = xmlXPathNodeSetGetLength(nodes1);
4389
4390 for (i = 0; i < l1; i++) {
4391 cur = xmlXPathNodeSetItem(nodes1, i);
4392 if (xmlXPathNodeSetContains(nodes2, cur))
4393 xmlXPathNodeSetAddUnique(ret, cur);
4394 }
4395 return(ret);
4396}
4397
4398/**
4399 * xmlXPathDistinctSorted:
4400 * @nodes: a node-set, sorted by document order
4401 *
4402 * Implements the EXSLT - Sets distinct() function:
4403 * node-set set:distinct (node-set)
4404 *
4405 * Returns a subset of the nodes contained in @nodes, or @nodes if
4406 * it is empty
4407 */
4408xmlNodeSetPtr
4409xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4410 xmlNodeSetPtr ret;
4411 xmlHashTablePtr hash;
4412 int i, l;
4413 xmlChar * strval;
4414 xmlNodePtr cur;
4415
4416 if (xmlXPathNodeSetIsEmpty(nodes))
4417 return(nodes);
4418
4419 ret = xmlXPathNodeSetCreate(NULL);
4420 l = xmlXPathNodeSetGetLength(nodes);
4421 hash = xmlHashCreate (l);
4422 for (i = 0; i < l; i++) {
4423 cur = xmlXPathNodeSetItem(nodes, i);
4424 strval = xmlXPathCastNodeToString(cur);
4425 if (xmlHashLookup(hash, strval) == NULL) {
4426 xmlHashAddEntry(hash, strval, strval);
4427 xmlXPathNodeSetAddUnique(ret, cur);
4428 } else {
4429 xmlFree(strval);
4430 }
4431 }
4432 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4433 return(ret);
4434}
4435
4436/**
4437 * xmlXPathDistinct:
4438 * @nodes: a node-set
4439 *
4440 * Implements the EXSLT - Sets distinct() function:
4441 * node-set set:distinct (node-set)
4442 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4443 * is called with the sorted node-set
4444 *
4445 * Returns a subset of the nodes contained in @nodes, or @nodes if
4446 * it is empty
4447 */
4448xmlNodeSetPtr
4449xmlXPathDistinct (xmlNodeSetPtr nodes) {
4450 if (xmlXPathNodeSetIsEmpty(nodes))
4451 return(nodes);
4452
4453 xmlXPathNodeSetSort(nodes);
4454 return(xmlXPathDistinctSorted(nodes));
4455}
4456
4457/**
4458 * xmlXPathHasSameNodes:
4459 * @nodes1: a node-set
4460 * @nodes2: a node-set
4461 *
4462 * Implements the EXSLT - Sets has-same-nodes function:
4463 * boolean set:has-same-node(node-set, node-set)
4464 *
4465 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4466 * otherwise
4467 */
4468int
4469xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4470 int i, l;
4471 xmlNodePtr cur;
4472
4473 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4474 xmlXPathNodeSetIsEmpty(nodes2))
4475 return(0);
4476
4477 l = xmlXPathNodeSetGetLength(nodes1);
4478 for (i = 0; i < l; i++) {
4479 cur = xmlXPathNodeSetItem(nodes1, i);
4480 if (xmlXPathNodeSetContains(nodes2, cur))
4481 return(1);
4482 }
4483 return(0);
4484}
4485
4486/**
4487 * xmlXPathNodeLeadingSorted:
4488 * @nodes: a node-set, sorted by document order
4489 * @node: a node
4490 *
4491 * Implements the EXSLT - Sets leading() function:
4492 * node-set set:leading (node-set, node-set)
4493 *
4494 * Returns the nodes in @nodes that precede @node in document order,
4495 * @nodes if @node is NULL or an empty node-set if @nodes
4496 * doesn't contain @node
4497 */
4498xmlNodeSetPtr
4499xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4500 int i, l;
4501 xmlNodePtr cur;
4502 xmlNodeSetPtr ret;
4503
4504 if (node == NULL)
4505 return(nodes);
4506
4507 ret = xmlXPathNodeSetCreate(NULL);
4508 if (xmlXPathNodeSetIsEmpty(nodes) ||
4509 (!xmlXPathNodeSetContains(nodes, node)))
4510 return(ret);
4511
4512 l = xmlXPathNodeSetGetLength(nodes);
4513 for (i = 0; i < l; i++) {
4514 cur = xmlXPathNodeSetItem(nodes, i);
4515 if (cur == node)
4516 break;
4517 xmlXPathNodeSetAddUnique(ret, cur);
4518 }
4519 return(ret);
4520}
4521
4522/**
4523 * xmlXPathNodeLeading:
4524 * @nodes: a node-set
4525 * @node: a node
4526 *
4527 * Implements the EXSLT - Sets leading() function:
4528 * node-set set:leading (node-set, node-set)
4529 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4530 * is called.
4531 *
4532 * Returns the nodes in @nodes that precede @node in document order,
4533 * @nodes if @node is NULL or an empty node-set if @nodes
4534 * doesn't contain @node
4535 */
4536xmlNodeSetPtr
4537xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4538 xmlXPathNodeSetSort(nodes);
4539 return(xmlXPathNodeLeadingSorted(nodes, node));
4540}
4541
4542/**
4543 * xmlXPathLeadingSorted:
4544 * @nodes1: a node-set, sorted by document order
4545 * @nodes2: a node-set, sorted by document order
4546 *
4547 * Implements the EXSLT - Sets leading() function:
4548 * node-set set:leading (node-set, node-set)
4549 *
4550 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4551 * in document order, @nodes1 if @nodes2 is NULL or empty or
4552 * an empty node-set if @nodes1 doesn't contain @nodes2
4553 */
4554xmlNodeSetPtr
4555xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4556 if (xmlXPathNodeSetIsEmpty(nodes2))
4557 return(nodes1);
4558 return(xmlXPathNodeLeadingSorted(nodes1,
4559 xmlXPathNodeSetItem(nodes2, 1)));
4560}
4561
4562/**
4563 * xmlXPathLeading:
4564 * @nodes1: a node-set
4565 * @nodes2: a node-set
4566 *
4567 * Implements the EXSLT - Sets leading() function:
4568 * node-set set:leading (node-set, node-set)
4569 * @nodes1 and @nodes2 are sorted by document order, then
4570 * #exslSetsLeadingSorted is called.
4571 *
4572 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4573 * in document order, @nodes1 if @nodes2 is NULL or empty or
4574 * an empty node-set if @nodes1 doesn't contain @nodes2
4575 */
4576xmlNodeSetPtr
4577xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4578 if (xmlXPathNodeSetIsEmpty(nodes2))
4579 return(nodes1);
4580 if (xmlXPathNodeSetIsEmpty(nodes1))
4581 return(xmlXPathNodeSetCreate(NULL));
4582 xmlXPathNodeSetSort(nodes1);
4583 xmlXPathNodeSetSort(nodes2);
4584 return(xmlXPathNodeLeadingSorted(nodes1,
4585 xmlXPathNodeSetItem(nodes2, 1)));
4586}
4587
4588/**
4589 * xmlXPathNodeTrailingSorted:
4590 * @nodes: a node-set, sorted by document order
4591 * @node: a node
4592 *
4593 * Implements the EXSLT - Sets trailing() function:
4594 * node-set set:trailing (node-set, node-set)
4595 *
4596 * Returns the nodes in @nodes that follow @node in document order,
4597 * @nodes if @node is NULL or an empty node-set if @nodes
4598 * doesn't contain @node
4599 */
4600xmlNodeSetPtr
4601xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4602 int i, l;
4603 xmlNodePtr cur;
4604 xmlNodeSetPtr ret;
4605
4606 if (node == NULL)
4607 return(nodes);
4608
4609 ret = xmlXPathNodeSetCreate(NULL);
4610 if (xmlXPathNodeSetIsEmpty(nodes) ||
4611 (!xmlXPathNodeSetContains(nodes, node)))
4612 return(ret);
4613
4614 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004615 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004616 cur = xmlXPathNodeSetItem(nodes, i);
4617 if (cur == node)
4618 break;
4619 xmlXPathNodeSetAddUnique(ret, cur);
4620 }
4621 return(ret);
4622}
4623
4624/**
4625 * xmlXPathNodeTrailing:
4626 * @nodes: a node-set
4627 * @node: a node
4628 *
4629 * Implements the EXSLT - Sets trailing() function:
4630 * node-set set:trailing (node-set, node-set)
4631 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4632 * is called.
4633 *
4634 * Returns the nodes in @nodes that follow @node in document order,
4635 * @nodes if @node is NULL or an empty node-set if @nodes
4636 * doesn't contain @node
4637 */
4638xmlNodeSetPtr
4639xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4640 xmlXPathNodeSetSort(nodes);
4641 return(xmlXPathNodeTrailingSorted(nodes, node));
4642}
4643
4644/**
4645 * xmlXPathTrailingSorted:
4646 * @nodes1: a node-set, sorted by document order
4647 * @nodes2: a node-set, sorted by document order
4648 *
4649 * Implements the EXSLT - Sets trailing() function:
4650 * node-set set:trailing (node-set, node-set)
4651 *
4652 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4653 * in document order, @nodes1 if @nodes2 is NULL or empty or
4654 * an empty node-set if @nodes1 doesn't contain @nodes2
4655 */
4656xmlNodeSetPtr
4657xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4658 if (xmlXPathNodeSetIsEmpty(nodes2))
4659 return(nodes1);
4660 return(xmlXPathNodeTrailingSorted(nodes1,
4661 xmlXPathNodeSetItem(nodes2, 0)));
4662}
4663
4664/**
4665 * xmlXPathTrailing:
4666 * @nodes1: a node-set
4667 * @nodes2: a node-set
4668 *
4669 * Implements the EXSLT - Sets trailing() function:
4670 * node-set set:trailing (node-set, node-set)
4671 * @nodes1 and @nodes2 are sorted by document order, then
4672 * #xmlXPathTrailingSorted is called.
4673 *
4674 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4675 * in document order, @nodes1 if @nodes2 is NULL or empty or
4676 * an empty node-set if @nodes1 doesn't contain @nodes2
4677 */
4678xmlNodeSetPtr
4679xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4680 if (xmlXPathNodeSetIsEmpty(nodes2))
4681 return(nodes1);
4682 if (xmlXPathNodeSetIsEmpty(nodes1))
4683 return(xmlXPathNodeSetCreate(NULL));
4684 xmlXPathNodeSetSort(nodes1);
4685 xmlXPathNodeSetSort(nodes2);
4686 return(xmlXPathNodeTrailingSorted(nodes1,
4687 xmlXPathNodeSetItem(nodes2, 0)));
4688}
4689
Owen Taylor3473f882001-02-23 17:55:21 +00004690/************************************************************************
4691 * *
4692 * Routines to handle extra functions *
4693 * *
4694 ************************************************************************/
4695
4696/**
4697 * xmlXPathRegisterFunc:
4698 * @ctxt: the XPath context
4699 * @name: the function name
4700 * @f: the function implementation or NULL
4701 *
4702 * Register a new function. If @f is NULL it unregisters the function
4703 *
4704 * Returns 0 in case of success, -1 in case of error
4705 */
4706int
4707xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4708 xmlXPathFunction f) {
4709 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4710}
4711
4712/**
4713 * xmlXPathRegisterFuncNS:
4714 * @ctxt: the XPath context
4715 * @name: the function name
4716 * @ns_uri: the function namespace URI
4717 * @f: the function implementation or NULL
4718 *
4719 * Register a new function. If @f is NULL it unregisters the function
4720 *
4721 * Returns 0 in case of success, -1 in case of error
4722 */
4723int
4724xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4725 const xmlChar *ns_uri, xmlXPathFunction f) {
4726 if (ctxt == NULL)
4727 return(-1);
4728 if (name == NULL)
4729 return(-1);
4730
4731 if (ctxt->funcHash == NULL)
4732 ctxt->funcHash = xmlHashCreate(0);
4733 if (ctxt->funcHash == NULL)
4734 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004735 if (f == NULL)
4736 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004737 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004738}
4739
4740/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004741 * xmlXPathRegisterFuncLookup:
4742 * @ctxt: the XPath context
4743 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004744 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004745 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004746 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004747 */
4748void
4749xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4750 xmlXPathFuncLookupFunc f,
4751 void *funcCtxt) {
4752 if (ctxt == NULL)
4753 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004754 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004755 ctxt->funcLookupData = funcCtxt;
4756}
4757
4758/**
Owen Taylor3473f882001-02-23 17:55:21 +00004759 * xmlXPathFunctionLookup:
4760 * @ctxt: the XPath context
4761 * @name: the function name
4762 *
4763 * Search in the Function array of the context for the given
4764 * function.
4765 *
4766 * Returns the xmlXPathFunction or NULL if not found
4767 */
4768xmlXPathFunction
4769xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004770 if (ctxt == NULL)
4771 return (NULL);
4772
4773 if (ctxt->funcLookupFunc != NULL) {
4774 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004775 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004776
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004777 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004778 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004779 if (ret != NULL)
4780 return(ret);
4781 }
Owen Taylor3473f882001-02-23 17:55:21 +00004782 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4783}
4784
4785/**
4786 * xmlXPathFunctionLookupNS:
4787 * @ctxt: the XPath context
4788 * @name: the function name
4789 * @ns_uri: the function namespace URI
4790 *
4791 * Search in the Function array of the context for the given
4792 * function.
4793 *
4794 * Returns the xmlXPathFunction or NULL if not found
4795 */
4796xmlXPathFunction
4797xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4798 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004799 xmlXPathFunction ret;
4800
Owen Taylor3473f882001-02-23 17:55:21 +00004801 if (ctxt == NULL)
4802 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004803 if (name == NULL)
4804 return(NULL);
4805
Thomas Broyerba4ad322001-07-26 16:55:21 +00004806 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004807 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004808
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004809 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004810 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004811 if (ret != NULL)
4812 return(ret);
4813 }
4814
4815 if (ctxt->funcHash == NULL)
4816 return(NULL);
4817
William M. Brackad0e67c2004-12-01 14:35:10 +00004818 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4819 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004820}
4821
4822/**
4823 * xmlXPathRegisteredFuncsCleanup:
4824 * @ctxt: the XPath context
4825 *
4826 * Cleanup the XPath context data associated to registered functions
4827 */
4828void
4829xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4830 if (ctxt == NULL)
4831 return;
4832
4833 xmlHashFree(ctxt->funcHash, NULL);
4834 ctxt->funcHash = NULL;
4835}
4836
4837/************************************************************************
4838 * *
William M. Brack08171912003-12-29 02:52:11 +00004839 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004840 * *
4841 ************************************************************************/
4842
4843/**
4844 * xmlXPathRegisterVariable:
4845 * @ctxt: the XPath context
4846 * @name: the variable name
4847 * @value: the variable value or NULL
4848 *
4849 * Register a new variable value. If @value is NULL it unregisters
4850 * the variable
4851 *
4852 * Returns 0 in case of success, -1 in case of error
4853 */
4854int
4855xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4856 xmlXPathObjectPtr value) {
4857 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4858}
4859
4860/**
4861 * xmlXPathRegisterVariableNS:
4862 * @ctxt: the XPath context
4863 * @name: the variable name
4864 * @ns_uri: the variable namespace URI
4865 * @value: the variable value or NULL
4866 *
4867 * Register a new variable value. If @value is NULL it unregisters
4868 * the variable
4869 *
4870 * Returns 0 in case of success, -1 in case of error
4871 */
4872int
4873xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4874 const xmlChar *ns_uri,
4875 xmlXPathObjectPtr value) {
4876 if (ctxt == NULL)
4877 return(-1);
4878 if (name == NULL)
4879 return(-1);
4880
4881 if (ctxt->varHash == NULL)
4882 ctxt->varHash = xmlHashCreate(0);
4883 if (ctxt->varHash == NULL)
4884 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004885 if (value == NULL)
4886 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4887 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004888 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4889 (void *) value,
4890 (xmlHashDeallocator)xmlXPathFreeObject));
4891}
4892
4893/**
4894 * xmlXPathRegisterVariableLookup:
4895 * @ctxt: the XPath context
4896 * @f: the lookup function
4897 * @data: the lookup data
4898 *
4899 * register an external mechanism to do variable lookup
4900 */
4901void
4902xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4903 xmlXPathVariableLookupFunc f, void *data) {
4904 if (ctxt == NULL)
4905 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004906 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004907 ctxt->varLookupData = data;
4908}
4909
4910/**
4911 * xmlXPathVariableLookup:
4912 * @ctxt: the XPath context
4913 * @name: the variable name
4914 *
4915 * Search in the Variable array of the context for the given
4916 * variable value.
4917 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004918 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004919 */
4920xmlXPathObjectPtr
4921xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4922 if (ctxt == NULL)
4923 return(NULL);
4924
4925 if (ctxt->varLookupFunc != NULL) {
4926 xmlXPathObjectPtr ret;
4927
4928 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4929 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004930 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004931 }
4932 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4933}
4934
4935/**
4936 * xmlXPathVariableLookupNS:
4937 * @ctxt: the XPath context
4938 * @name: the variable name
4939 * @ns_uri: the variable namespace URI
4940 *
4941 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004942 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004943 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004944 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004945 */
4946xmlXPathObjectPtr
4947xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4948 const xmlChar *ns_uri) {
4949 if (ctxt == NULL)
4950 return(NULL);
4951
4952 if (ctxt->varLookupFunc != NULL) {
4953 xmlXPathObjectPtr ret;
4954
4955 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4956 (ctxt->varLookupData, name, ns_uri);
4957 if (ret != NULL) return(ret);
4958 }
4959
4960 if (ctxt->varHash == NULL)
4961 return(NULL);
4962 if (name == NULL)
4963 return(NULL);
4964
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004965 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004966 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004967}
4968
4969/**
4970 * xmlXPathRegisteredVariablesCleanup:
4971 * @ctxt: the XPath context
4972 *
4973 * Cleanup the XPath context data associated to registered variables
4974 */
4975void
4976xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4977 if (ctxt == NULL)
4978 return;
4979
Daniel Veillard76d66f42001-05-16 21:05:17 +00004980 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004981 ctxt->varHash = NULL;
4982}
4983
4984/**
4985 * xmlXPathRegisterNs:
4986 * @ctxt: the XPath context
4987 * @prefix: the namespace prefix
4988 * @ns_uri: the namespace name
4989 *
4990 * Register a new namespace. If @ns_uri is NULL it unregisters
4991 * the namespace
4992 *
4993 * Returns 0 in case of success, -1 in case of error
4994 */
4995int
4996xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4997 const xmlChar *ns_uri) {
4998 if (ctxt == NULL)
4999 return(-1);
5000 if (prefix == NULL)
5001 return(-1);
5002
5003 if (ctxt->nsHash == NULL)
5004 ctxt->nsHash = xmlHashCreate(10);
5005 if (ctxt->nsHash == NULL)
5006 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005007 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005008 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005009 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005010 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005011 (xmlHashDeallocator)xmlFree));
5012}
5013
5014/**
5015 * xmlXPathNsLookup:
5016 * @ctxt: the XPath context
5017 * @prefix: the namespace prefix value
5018 *
5019 * Search in the namespace declaration array of the context for the given
5020 * namespace name associated to the given prefix
5021 *
5022 * Returns the value or NULL if not found
5023 */
5024const xmlChar *
5025xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5026 if (ctxt == NULL)
5027 return(NULL);
5028 if (prefix == NULL)
5029 return(NULL);
5030
5031#ifdef XML_XML_NAMESPACE
5032 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5033 return(XML_XML_NAMESPACE);
5034#endif
5035
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005036 if (ctxt->namespaces != NULL) {
5037 int i;
5038
5039 for (i = 0;i < ctxt->nsNr;i++) {
5040 if ((ctxt->namespaces[i] != NULL) &&
5041 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5042 return(ctxt->namespaces[i]->href);
5043 }
5044 }
Owen Taylor3473f882001-02-23 17:55:21 +00005045
5046 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5047}
5048
5049/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005050 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005051 * @ctxt: the XPath context
5052 *
5053 * Cleanup the XPath context data associated to registered variables
5054 */
5055void
5056xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5057 if (ctxt == NULL)
5058 return;
5059
Daniel Veillard42766c02002-08-22 20:52:17 +00005060 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005061 ctxt->nsHash = NULL;
5062}
5063
5064/************************************************************************
5065 * *
5066 * Routines to handle Values *
5067 * *
5068 ************************************************************************/
5069
William M. Brack08171912003-12-29 02:52:11 +00005070/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005071
5072/**
5073 * xmlXPathNewFloat:
5074 * @val: the double value
5075 *
5076 * Create a new xmlXPathObjectPtr of type double and of value @val
5077 *
5078 * Returns the newly created object.
5079 */
5080xmlXPathObjectPtr
5081xmlXPathNewFloat(double val) {
5082 xmlXPathObjectPtr ret;
5083
5084 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5085 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005086 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005087 return(NULL);
5088 }
5089 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5090 ret->type = XPATH_NUMBER;
5091 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005092#ifdef XP_DEBUG_OBJ_USAGE
5093 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5094#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005095 return(ret);
5096}
5097
5098/**
5099 * xmlXPathNewBoolean:
5100 * @val: the boolean value
5101 *
5102 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5103 *
5104 * Returns the newly created object.
5105 */
5106xmlXPathObjectPtr
5107xmlXPathNewBoolean(int val) {
5108 xmlXPathObjectPtr ret;
5109
5110 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5111 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005112 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005113 return(NULL);
5114 }
5115 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5116 ret->type = XPATH_BOOLEAN;
5117 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005118#ifdef XP_DEBUG_OBJ_USAGE
5119 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5120#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005121 return(ret);
5122}
5123
5124/**
5125 * xmlXPathNewString:
5126 * @val: the xmlChar * value
5127 *
5128 * Create a new xmlXPathObjectPtr of type string and of value @val
5129 *
5130 * Returns the newly created object.
5131 */
5132xmlXPathObjectPtr
5133xmlXPathNewString(const xmlChar *val) {
5134 xmlXPathObjectPtr ret;
5135
5136 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5137 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005138 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005139 return(NULL);
5140 }
5141 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5142 ret->type = XPATH_STRING;
5143 if (val != NULL)
5144 ret->stringval = xmlStrdup(val);
5145 else
5146 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005147#ifdef XP_DEBUG_OBJ_USAGE
5148 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5149#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005150 return(ret);
5151}
5152
5153/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005154 * xmlXPathWrapString:
5155 * @val: the xmlChar * value
5156 *
5157 * Wraps the @val string into an XPath object.
5158 *
5159 * Returns the newly created object.
5160 */
5161xmlXPathObjectPtr
5162xmlXPathWrapString (xmlChar *val) {
5163 xmlXPathObjectPtr ret;
5164
5165 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5166 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005167 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005168 return(NULL);
5169 }
5170 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5171 ret->type = XPATH_STRING;
5172 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005173#ifdef XP_DEBUG_OBJ_USAGE
5174 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5175#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005176 return(ret);
5177}
5178
5179/**
Owen Taylor3473f882001-02-23 17:55:21 +00005180 * xmlXPathNewCString:
5181 * @val: the char * value
5182 *
5183 * Create a new xmlXPathObjectPtr of type string and of value @val
5184 *
5185 * Returns the newly created object.
5186 */
5187xmlXPathObjectPtr
5188xmlXPathNewCString(const char *val) {
5189 xmlXPathObjectPtr ret;
5190
5191 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5192 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005193 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005194 return(NULL);
5195 }
5196 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5197 ret->type = XPATH_STRING;
5198 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005199#ifdef XP_DEBUG_OBJ_USAGE
5200 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5201#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005202 return(ret);
5203}
5204
5205/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005206 * xmlXPathWrapCString:
5207 * @val: the char * value
5208 *
5209 * Wraps a string into an XPath object.
5210 *
5211 * Returns the newly created object.
5212 */
5213xmlXPathObjectPtr
5214xmlXPathWrapCString (char * val) {
5215 return(xmlXPathWrapString((xmlChar *)(val)));
5216}
5217
5218/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005219 * xmlXPathWrapExternal:
5220 * @val: the user data
5221 *
5222 * Wraps the @val data into an XPath object.
5223 *
5224 * Returns the newly created object.
5225 */
5226xmlXPathObjectPtr
5227xmlXPathWrapExternal (void *val) {
5228 xmlXPathObjectPtr ret;
5229
5230 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5231 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005232 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005233 return(NULL);
5234 }
5235 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236 ret->type = XPATH_USERS;
5237 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005238#ifdef XP_DEBUG_OBJ_USAGE
5239 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5240#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005241 return(ret);
5242}
5243
5244/**
Owen Taylor3473f882001-02-23 17:55:21 +00005245 * xmlXPathObjectCopy:
5246 * @val: the original object
5247 *
5248 * allocate a new copy of a given object
5249 *
5250 * Returns the newly created object.
5251 */
5252xmlXPathObjectPtr
5253xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5254 xmlXPathObjectPtr ret;
5255
5256 if (val == NULL)
5257 return(NULL);
5258
5259 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5260 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005261 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005262 return(NULL);
5263 }
5264 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005265#ifdef XP_DEBUG_OBJ_USAGE
5266 xmlXPathDebugObjUsageRequested(NULL, val->type);
5267#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005268 switch (val->type) {
5269 case XPATH_BOOLEAN:
5270 case XPATH_NUMBER:
5271 case XPATH_POINT:
5272 case XPATH_RANGE:
5273 break;
5274 case XPATH_STRING:
5275 ret->stringval = xmlStrdup(val->stringval);
5276 break;
5277 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005278#if 0
5279/*
5280 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5281 this previous handling is no longer correct, and can cause some serious
5282 problems (ref. bug 145547)
5283*/
Owen Taylor3473f882001-02-23 17:55:21 +00005284 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005285 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005286 xmlNodePtr cur, tmp;
5287 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005288
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005289 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005290 top = xmlNewDoc(NULL);
5291 top->name = (char *)
5292 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005293 ret->user = top;
5294 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005295 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005296 cur = val->nodesetval->nodeTab[0]->children;
5297 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005298 tmp = xmlDocCopyNode(cur, top, 1);
5299 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005300 cur = cur->next;
5301 }
5302 }
William M. Bracke9449c52004-07-11 14:41:20 +00005303
Daniel Veillard9adc0462003-03-24 18:39:54 +00005304 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005305 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005306 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005307 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005308 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005309#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005310 case XPATH_NODESET:
5311 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005312 /* Do not deallocate the copied tree value */
5313 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005314 break;
5315 case XPATH_LOCATIONSET:
5316#ifdef LIBXML_XPTR_ENABLED
5317 {
5318 xmlLocationSetPtr loc = val->user;
5319 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5320 break;
5321 }
5322#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005323 case XPATH_USERS:
5324 ret->user = val->user;
5325 break;
5326 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005327 xmlGenericError(xmlGenericErrorContext,
5328 "xmlXPathObjectCopy: unsupported type %d\n",
5329 val->type);
5330 break;
5331 }
5332 return(ret);
5333}
5334
5335/**
5336 * xmlXPathFreeObject:
5337 * @obj: the object to free
5338 *
5339 * Free up an xmlXPathObjectPtr object.
5340 */
5341void
5342xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5343 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005344 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005345 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005346#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005347 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005348 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005349 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005350 } else
5351#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005352 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005353 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005354 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005355 } else {
5356 if (obj->nodesetval != NULL)
5357 xmlXPathFreeNodeSet(obj->nodesetval);
5358 }
Owen Taylor3473f882001-02-23 17:55:21 +00005359#ifdef LIBXML_XPTR_ENABLED
5360 } else if (obj->type == XPATH_LOCATIONSET) {
5361 if (obj->user != NULL)
5362 xmlXPtrFreeLocationSet(obj->user);
5363#endif
5364 } else if (obj->type == XPATH_STRING) {
5365 if (obj->stringval != NULL)
5366 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005367 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005368#ifdef XP_DEBUG_OBJ_USAGE
5369 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5370#endif
5371 xmlFree(obj);
5372}
Owen Taylor3473f882001-02-23 17:55:21 +00005373
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005374/**
5375 * xmlXPathReleaseObject:
5376 * @obj: the xmlXPathObjectPtr to free or to cache
5377 *
5378 * Depending on the state of the cache this frees the given
5379 * XPath object or stores it in the cache.
5380 */
5381static void
5382xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5383{
5384#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5385 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5386 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5387
5388#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5389
5390 if (obj == NULL)
5391 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005392 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005393 xmlXPathFreeObject(obj);
5394 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005395 xmlXPathContextCachePtr cache =
5396 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005397
5398 switch (obj->type) {
5399 case XPATH_NODESET:
5400 case XPATH_XSLT_TREE:
5401 if (obj->nodesetval != NULL) {
5402 if (obj->boolval) {
5403 /*
5404 * It looks like the @boolval is used for
5405 * evaluation if this an XSLT Result Tree Fragment.
5406 * TODO: Check if this assumption is correct.
5407 */
5408 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5409 xmlXPathFreeValueTree(obj->nodesetval);
5410 obj->nodesetval = NULL;
5411 } else if ((obj->nodesetval->nodeMax <= 40) &&
5412 (XP_CACHE_WANTS(cache->nodesetObjs,
5413 cache->maxNodeset)))
5414 {
5415 XP_CACHE_ADD(cache->nodesetObjs, obj);
5416 goto obj_cached;
5417 } else {
5418 xmlXPathFreeNodeSet(obj->nodesetval);
5419 obj->nodesetval = NULL;
5420 }
5421 }
5422 break;
5423 case XPATH_STRING:
5424 if (obj->stringval != NULL)
5425 xmlFree(obj->stringval);
5426
5427 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5428 XP_CACHE_ADD(cache->stringObjs, obj);
5429 goto obj_cached;
5430 }
5431 break;
5432 case XPATH_BOOLEAN:
5433 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5434 XP_CACHE_ADD(cache->booleanObjs, obj);
5435 goto obj_cached;
5436 }
5437 break;
5438 case XPATH_NUMBER:
5439 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5440 XP_CACHE_ADD(cache->numberObjs, obj);
5441 goto obj_cached;
5442 }
5443 break;
5444#ifdef LIBXML_XPTR_ENABLED
5445 case XPATH_LOCATIONSET:
5446 if (obj->user != NULL) {
5447 xmlXPtrFreeLocationSet(obj->user);
5448 }
5449 goto free_obj;
5450#endif
5451 default:
5452 goto free_obj;
5453 }
5454
5455 /*
5456 * Fallback to adding to the misc-objects slot.
5457 */
5458 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5459 XP_CACHE_ADD(cache->miscObjs, obj);
5460 } else
5461 goto free_obj;
5462
5463obj_cached:
5464
5465#ifdef XP_DEBUG_OBJ_USAGE
5466 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5467#endif
5468
5469 if (obj->nodesetval != NULL) {
5470 xmlNodeSetPtr tmpset = obj->nodesetval;
5471
5472 /*
5473 * TODO: Due to those nasty ns-nodes, we need to traverse
5474 * the list and free the ns-nodes.
5475 * URGENT TODO: Check if it's actually slowing things down.
5476 * Maybe we shouldn't try to preserve the list.
5477 */
5478 if (tmpset->nodeNr > 1) {
5479 int i;
5480 xmlNodePtr node;
5481
5482 for (i = 0; i < tmpset->nodeNr; i++) {
5483 node = tmpset->nodeTab[i];
5484 if ((node != NULL) &&
5485 (node->type == XML_NAMESPACE_DECL))
5486 {
5487 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5488 }
5489 }
5490 } else if (tmpset->nodeNr == 1) {
5491 if ((tmpset->nodeTab[0] != NULL) &&
5492 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5493 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5494 }
5495 tmpset->nodeNr = 0;
5496 memset(obj, 0, sizeof(xmlXPathObject));
5497 obj->nodesetval = tmpset;
5498 } else
5499 memset(obj, 0, sizeof(xmlXPathObject));
5500
5501 return;
5502
5503free_obj:
5504 /*
5505 * Cache is full; free the object.
5506 */
5507 if (obj->nodesetval != NULL)
5508 xmlXPathFreeNodeSet(obj->nodesetval);
5509#ifdef XP_DEBUG_OBJ_USAGE
5510 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5511#endif
5512 xmlFree(obj);
5513 }
5514 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005515}
5516
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005517
5518/************************************************************************
5519 * *
5520 * Type Casting Routines *
5521 * *
5522 ************************************************************************/
5523
5524/**
5525 * xmlXPathCastBooleanToString:
5526 * @val: a boolean
5527 *
5528 * Converts a boolean to its string value.
5529 *
5530 * Returns a newly allocated string.
5531 */
5532xmlChar *
5533xmlXPathCastBooleanToString (int val) {
5534 xmlChar *ret;
5535 if (val)
5536 ret = xmlStrdup((const xmlChar *) "true");
5537 else
5538 ret = xmlStrdup((const xmlChar *) "false");
5539 return(ret);
5540}
5541
5542/**
5543 * xmlXPathCastNumberToString:
5544 * @val: a number
5545 *
5546 * Converts a number to its string value.
5547 *
5548 * Returns a newly allocated string.
5549 */
5550xmlChar *
5551xmlXPathCastNumberToString (double val) {
5552 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005553 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005554 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005555 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005556 break;
5557 case -1:
5558 ret = xmlStrdup((const xmlChar *) "-Infinity");
5559 break;
5560 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005561 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005562 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005563 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5564 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005565 } else {
5566 /* could be improved */
5567 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005568 xmlXPathFormatNumber(val, buf, 99);
5569 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005570 ret = xmlStrdup((const xmlChar *) buf);
5571 }
5572 }
5573 return(ret);
5574}
5575
5576/**
5577 * xmlXPathCastNodeToString:
5578 * @node: a node
5579 *
5580 * Converts a node to its string value.
5581 *
5582 * Returns a newly allocated string.
5583 */
5584xmlChar *
5585xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005586xmlChar *ret;
5587 if ((ret = xmlNodeGetContent(node)) == NULL)
5588 ret = xmlStrdup((const xmlChar *) "");
5589 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005590}
5591
5592/**
5593 * xmlXPathCastNodeSetToString:
5594 * @ns: a node-set
5595 *
5596 * Converts a node-set to its string value.
5597 *
5598 * Returns a newly allocated string.
5599 */
5600xmlChar *
5601xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5602 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5603 return(xmlStrdup((const xmlChar *) ""));
5604
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005605 if (ns->nodeNr > 1)
5606 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005607 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5608}
5609
5610/**
5611 * xmlXPathCastToString:
5612 * @val: an XPath object
5613 *
5614 * Converts an existing object to its string() equivalent
5615 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005616 * Returns the allocated string value of the object, NULL in case of error.
5617 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005618 */
5619xmlChar *
5620xmlXPathCastToString(xmlXPathObjectPtr val) {
5621 xmlChar *ret = NULL;
5622
5623 if (val == NULL)
5624 return(xmlStrdup((const xmlChar *) ""));
5625 switch (val->type) {
5626 case XPATH_UNDEFINED:
5627#ifdef DEBUG_EXPR
5628 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5629#endif
5630 ret = xmlStrdup((const xmlChar *) "");
5631 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005632 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005633 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005634 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5635 break;
5636 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005637 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005638 case XPATH_BOOLEAN:
5639 ret = xmlXPathCastBooleanToString(val->boolval);
5640 break;
5641 case XPATH_NUMBER: {
5642 ret = xmlXPathCastNumberToString(val->floatval);
5643 break;
5644 }
5645 case XPATH_USERS:
5646 case XPATH_POINT:
5647 case XPATH_RANGE:
5648 case XPATH_LOCATIONSET:
5649 TODO
5650 ret = xmlStrdup((const xmlChar *) "");
5651 break;
5652 }
5653 return(ret);
5654}
5655
5656/**
5657 * xmlXPathConvertString:
5658 * @val: an XPath object
5659 *
5660 * Converts an existing object to its string() equivalent
5661 *
5662 * Returns the new object, the old one is freed (or the operation
5663 * is done directly on @val)
5664 */
5665xmlXPathObjectPtr
5666xmlXPathConvertString(xmlXPathObjectPtr val) {
5667 xmlChar *res = NULL;
5668
5669 if (val == NULL)
5670 return(xmlXPathNewCString(""));
5671
5672 switch (val->type) {
5673 case XPATH_UNDEFINED:
5674#ifdef DEBUG_EXPR
5675 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5676#endif
5677 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005678 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005679 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005680 res = xmlXPathCastNodeSetToString(val->nodesetval);
5681 break;
5682 case XPATH_STRING:
5683 return(val);
5684 case XPATH_BOOLEAN:
5685 res = xmlXPathCastBooleanToString(val->boolval);
5686 break;
5687 case XPATH_NUMBER:
5688 res = xmlXPathCastNumberToString(val->floatval);
5689 break;
5690 case XPATH_USERS:
5691 case XPATH_POINT:
5692 case XPATH_RANGE:
5693 case XPATH_LOCATIONSET:
5694 TODO;
5695 break;
5696 }
5697 xmlXPathFreeObject(val);
5698 if (res == NULL)
5699 return(xmlXPathNewCString(""));
5700 return(xmlXPathWrapString(res));
5701}
5702
5703/**
5704 * xmlXPathCastBooleanToNumber:
5705 * @val: a boolean
5706 *
5707 * Converts a boolean to its number value
5708 *
5709 * Returns the number value
5710 */
5711double
5712xmlXPathCastBooleanToNumber(int val) {
5713 if (val)
5714 return(1.0);
5715 return(0.0);
5716}
5717
5718/**
5719 * xmlXPathCastStringToNumber:
5720 * @val: a string
5721 *
5722 * Converts a string to its number value
5723 *
5724 * Returns the number value
5725 */
5726double
5727xmlXPathCastStringToNumber(const xmlChar * val) {
5728 return(xmlXPathStringEvalNumber(val));
5729}
5730
5731/**
5732 * xmlXPathCastNodeToNumber:
5733 * @node: a node
5734 *
5735 * Converts a node to its number value
5736 *
5737 * Returns the number value
5738 */
5739double
5740xmlXPathCastNodeToNumber (xmlNodePtr node) {
5741 xmlChar *strval;
5742 double ret;
5743
5744 if (node == NULL)
5745 return(xmlXPathNAN);
5746 strval = xmlXPathCastNodeToString(node);
5747 if (strval == NULL)
5748 return(xmlXPathNAN);
5749 ret = xmlXPathCastStringToNumber(strval);
5750 xmlFree(strval);
5751
5752 return(ret);
5753}
5754
5755/**
5756 * xmlXPathCastNodeSetToNumber:
5757 * @ns: a node-set
5758 *
5759 * Converts a node-set to its number value
5760 *
5761 * Returns the number value
5762 */
5763double
5764xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5765 xmlChar *str;
5766 double ret;
5767
5768 if (ns == NULL)
5769 return(xmlXPathNAN);
5770 str = xmlXPathCastNodeSetToString(ns);
5771 ret = xmlXPathCastStringToNumber(str);
5772 xmlFree(str);
5773 return(ret);
5774}
5775
5776/**
5777 * xmlXPathCastToNumber:
5778 * @val: an XPath object
5779 *
5780 * Converts an XPath object to its number value
5781 *
5782 * Returns the number value
5783 */
5784double
5785xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5786 double ret = 0.0;
5787
5788 if (val == NULL)
5789 return(xmlXPathNAN);
5790 switch (val->type) {
5791 case XPATH_UNDEFINED:
5792#ifdef DEGUB_EXPR
5793 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5794#endif
5795 ret = xmlXPathNAN;
5796 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005797 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005798 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005799 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5800 break;
5801 case XPATH_STRING:
5802 ret = xmlXPathCastStringToNumber(val->stringval);
5803 break;
5804 case XPATH_NUMBER:
5805 ret = val->floatval;
5806 break;
5807 case XPATH_BOOLEAN:
5808 ret = xmlXPathCastBooleanToNumber(val->boolval);
5809 break;
5810 case XPATH_USERS:
5811 case XPATH_POINT:
5812 case XPATH_RANGE:
5813 case XPATH_LOCATIONSET:
5814 TODO;
5815 ret = xmlXPathNAN;
5816 break;
5817 }
5818 return(ret);
5819}
5820
5821/**
5822 * xmlXPathConvertNumber:
5823 * @val: an XPath object
5824 *
5825 * Converts an existing object to its number() equivalent
5826 *
5827 * Returns the new object, the old one is freed (or the operation
5828 * is done directly on @val)
5829 */
5830xmlXPathObjectPtr
5831xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5832 xmlXPathObjectPtr ret;
5833
5834 if (val == NULL)
5835 return(xmlXPathNewFloat(0.0));
5836 if (val->type == XPATH_NUMBER)
5837 return(val);
5838 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5839 xmlXPathFreeObject(val);
5840 return(ret);
5841}
5842
5843/**
5844 * xmlXPathCastNumberToBoolean:
5845 * @val: a number
5846 *
5847 * Converts a number to its boolean value
5848 *
5849 * Returns the boolean value
5850 */
5851int
5852xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005853 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005854 return(0);
5855 return(1);
5856}
5857
5858/**
5859 * xmlXPathCastStringToBoolean:
5860 * @val: a string
5861 *
5862 * Converts a string to its boolean value
5863 *
5864 * Returns the boolean value
5865 */
5866int
5867xmlXPathCastStringToBoolean (const xmlChar *val) {
5868 if ((val == NULL) || (xmlStrlen(val) == 0))
5869 return(0);
5870 return(1);
5871}
5872
5873/**
5874 * xmlXPathCastNodeSetToBoolean:
5875 * @ns: a node-set
5876 *
5877 * Converts a node-set to its boolean value
5878 *
5879 * Returns the boolean value
5880 */
5881int
5882xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5883 if ((ns == NULL) || (ns->nodeNr == 0))
5884 return(0);
5885 return(1);
5886}
5887
5888/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005889 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005890 * @val: an XPath object
5891 *
5892 * Converts an XPath object to its boolean value
5893 *
5894 * Returns the boolean value
5895 */
5896int
5897xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5898 int ret = 0;
5899
5900 if (val == NULL)
5901 return(0);
5902 switch (val->type) {
5903 case XPATH_UNDEFINED:
5904#ifdef DEBUG_EXPR
5905 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5906#endif
5907 ret = 0;
5908 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005909 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005910 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005911 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5912 break;
5913 case XPATH_STRING:
5914 ret = xmlXPathCastStringToBoolean(val->stringval);
5915 break;
5916 case XPATH_NUMBER:
5917 ret = xmlXPathCastNumberToBoolean(val->floatval);
5918 break;
5919 case XPATH_BOOLEAN:
5920 ret = val->boolval;
5921 break;
5922 case XPATH_USERS:
5923 case XPATH_POINT:
5924 case XPATH_RANGE:
5925 case XPATH_LOCATIONSET:
5926 TODO;
5927 ret = 0;
5928 break;
5929 }
5930 return(ret);
5931}
5932
5933
5934/**
5935 * xmlXPathConvertBoolean:
5936 * @val: an XPath object
5937 *
5938 * Converts an existing object to its boolean() equivalent
5939 *
5940 * Returns the new object, the old one is freed (or the operation
5941 * is done directly on @val)
5942 */
5943xmlXPathObjectPtr
5944xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5945 xmlXPathObjectPtr ret;
5946
5947 if (val == NULL)
5948 return(xmlXPathNewBoolean(0));
5949 if (val->type == XPATH_BOOLEAN)
5950 return(val);
5951 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5952 xmlXPathFreeObject(val);
5953 return(ret);
5954}
5955
Owen Taylor3473f882001-02-23 17:55:21 +00005956/************************************************************************
5957 * *
5958 * Routines to handle XPath contexts *
5959 * *
5960 ************************************************************************/
5961
5962/**
5963 * xmlXPathNewContext:
5964 * @doc: the XML document
5965 *
5966 * Create a new xmlXPathContext
5967 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005968 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005969 */
5970xmlXPathContextPtr
5971xmlXPathNewContext(xmlDocPtr doc) {
5972 xmlXPathContextPtr ret;
5973
5974 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5975 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005976 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005977 return(NULL);
5978 }
5979 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5980 ret->doc = doc;
5981 ret->node = NULL;
5982
5983 ret->varHash = NULL;
5984
5985 ret->nb_types = 0;
5986 ret->max_types = 0;
5987 ret->types = NULL;
5988
5989 ret->funcHash = xmlHashCreate(0);
5990
5991 ret->nb_axis = 0;
5992 ret->max_axis = 0;
5993 ret->axis = NULL;
5994
5995 ret->nsHash = NULL;
5996 ret->user = NULL;
5997
5998 ret->contextSize = -1;
5999 ret->proximityPosition = -1;
6000
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006001#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006002 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006003 xmlXPathFreeContext(ret);
6004 return(NULL);
6005 }
6006#endif
6007
6008 xmlXPathRegisterAllFunctions(ret);
6009
Owen Taylor3473f882001-02-23 17:55:21 +00006010 return(ret);
6011}
6012
6013/**
6014 * xmlXPathFreeContext:
6015 * @ctxt: the context to free
6016 *
6017 * Free up an xmlXPathContext
6018 */
6019void
6020xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006021 if (ctxt == NULL) return;
6022
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006023 if (ctxt->cache != NULL)
6024 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006025 xmlXPathRegisteredNsCleanup(ctxt);
6026 xmlXPathRegisteredFuncsCleanup(ctxt);
6027 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006028 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006029 xmlFree(ctxt);
6030}
6031
6032/************************************************************************
6033 * *
6034 * Routines to handle XPath parser contexts *
6035 * *
6036 ************************************************************************/
6037
6038#define CHECK_CTXT(ctxt) \
6039 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006040 __xmlRaiseError(NULL, NULL, NULL, \
6041 NULL, NULL, XML_FROM_XPATH, \
6042 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6043 __FILE__, __LINE__, \
6044 NULL, NULL, NULL, 0, 0, \
6045 "NULL context pointer\n"); \
6046 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006047 } \
6048
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006049#define CHECK_CTXT_NEG(ctxt) \
6050 if (ctxt == NULL) { \
6051 __xmlRaiseError(NULL, NULL, NULL, \
6052 NULL, NULL, XML_FROM_XPATH, \
6053 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6054 __FILE__, __LINE__, \
6055 NULL, NULL, NULL, 0, 0, \
6056 "NULL context pointer\n"); \
6057 return(-1); \
6058 } \
6059
Owen Taylor3473f882001-02-23 17:55:21 +00006060
6061#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006062 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6063 (ctxt->doc->children == NULL)) { \
6064 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006065 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006066 }
Owen Taylor3473f882001-02-23 17:55:21 +00006067
6068
6069/**
6070 * xmlXPathNewParserContext:
6071 * @str: the XPath expression
6072 * @ctxt: the XPath context
6073 *
6074 * Create a new xmlXPathParserContext
6075 *
6076 * Returns the xmlXPathParserContext just allocated.
6077 */
6078xmlXPathParserContextPtr
6079xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6080 xmlXPathParserContextPtr ret;
6081
6082 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6083 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006084 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006085 return(NULL);
6086 }
6087 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6088 ret->cur = ret->base = str;
6089 ret->context = ctxt;
6090
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006091 ret->comp = xmlXPathNewCompExpr();
6092 if (ret->comp == NULL) {
6093 xmlFree(ret->valueTab);
6094 xmlFree(ret);
6095 return(NULL);
6096 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006097 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6098 ret->comp->dict = ctxt->dict;
6099 xmlDictReference(ret->comp->dict);
6100 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006101
6102 return(ret);
6103}
6104
6105/**
6106 * xmlXPathCompParserContext:
6107 * @comp: the XPath compiled expression
6108 * @ctxt: the XPath context
6109 *
6110 * Create a new xmlXPathParserContext when processing a compiled expression
6111 *
6112 * Returns the xmlXPathParserContext just allocated.
6113 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006114static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006115xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6116 xmlXPathParserContextPtr ret;
6117
6118 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6119 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006120 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006121 return(NULL);
6122 }
6123 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6124
Owen Taylor3473f882001-02-23 17:55:21 +00006125 /* Allocate the value stack */
6126 ret->valueTab = (xmlXPathObjectPtr *)
6127 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006128 if (ret->valueTab == NULL) {
6129 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006130 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006131 return(NULL);
6132 }
Owen Taylor3473f882001-02-23 17:55:21 +00006133 ret->valueNr = 0;
6134 ret->valueMax = 10;
6135 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006136
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006137 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006138 ret->comp = comp;
6139
Owen Taylor3473f882001-02-23 17:55:21 +00006140 return(ret);
6141}
6142
6143/**
6144 * xmlXPathFreeParserContext:
6145 * @ctxt: the context to free
6146 *
6147 * Free up an xmlXPathParserContext
6148 */
6149void
6150xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6151 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006152 xmlFree(ctxt->valueTab);
6153 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006154 if (ctxt->comp != NULL) {
6155#ifdef XPATH_STREAMING
6156 if (ctxt->comp->stream != NULL) {
6157 xmlFreePatternList(ctxt->comp->stream);
6158 ctxt->comp->stream = NULL;
6159 }
6160#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006161 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006162 }
Owen Taylor3473f882001-02-23 17:55:21 +00006163 xmlFree(ctxt);
6164}
6165
6166/************************************************************************
6167 * *
6168 * The implicit core function library *
6169 * *
6170 ************************************************************************/
6171
Owen Taylor3473f882001-02-23 17:55:21 +00006172/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006173 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006174 * @node: a node pointer
6175 *
6176 * Function computing the beginning of the string value of the node,
6177 * used to speed up comparisons
6178 *
6179 * Returns an int usable as a hash
6180 */
6181static unsigned int
6182xmlXPathNodeValHash(xmlNodePtr node) {
6183 int len = 2;
6184 const xmlChar * string = NULL;
6185 xmlNodePtr tmp = NULL;
6186 unsigned int ret = 0;
6187
6188 if (node == NULL)
6189 return(0);
6190
Daniel Veillard9adc0462003-03-24 18:39:54 +00006191 if (node->type == XML_DOCUMENT_NODE) {
6192 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6193 if (tmp == NULL)
6194 node = node->children;
6195 else
6196 node = tmp;
6197
6198 if (node == NULL)
6199 return(0);
6200 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006201
6202 switch (node->type) {
6203 case XML_COMMENT_NODE:
6204 case XML_PI_NODE:
6205 case XML_CDATA_SECTION_NODE:
6206 case XML_TEXT_NODE:
6207 string = node->content;
6208 if (string == NULL)
6209 return(0);
6210 if (string[0] == 0)
6211 return(0);
6212 return(((unsigned int) string[0]) +
6213 (((unsigned int) string[1]) << 8));
6214 case XML_NAMESPACE_DECL:
6215 string = ((xmlNsPtr)node)->href;
6216 if (string == NULL)
6217 return(0);
6218 if (string[0] == 0)
6219 return(0);
6220 return(((unsigned int) string[0]) +
6221 (((unsigned int) string[1]) << 8));
6222 case XML_ATTRIBUTE_NODE:
6223 tmp = ((xmlAttrPtr) node)->children;
6224 break;
6225 case XML_ELEMENT_NODE:
6226 tmp = node->children;
6227 break;
6228 default:
6229 return(0);
6230 }
6231 while (tmp != NULL) {
6232 switch (tmp->type) {
6233 case XML_COMMENT_NODE:
6234 case XML_PI_NODE:
6235 case XML_CDATA_SECTION_NODE:
6236 case XML_TEXT_NODE:
6237 string = tmp->content;
6238 break;
6239 case XML_NAMESPACE_DECL:
6240 string = ((xmlNsPtr)tmp)->href;
6241 break;
6242 default:
6243 break;
6244 }
6245 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006246 if (len == 1) {
6247 return(ret + (((unsigned int) string[0]) << 8));
6248 }
6249 if (string[1] == 0) {
6250 len = 1;
6251 ret = (unsigned int) string[0];
6252 } else {
6253 return(((unsigned int) string[0]) +
6254 (((unsigned int) string[1]) << 8));
6255 }
6256 }
6257 /*
6258 * Skip to next node
6259 */
6260 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6261 if (tmp->children->type != XML_ENTITY_DECL) {
6262 tmp = tmp->children;
6263 continue;
6264 }
6265 }
6266 if (tmp == node)
6267 break;
6268
6269 if (tmp->next != NULL) {
6270 tmp = tmp->next;
6271 continue;
6272 }
6273
6274 do {
6275 tmp = tmp->parent;
6276 if (tmp == NULL)
6277 break;
6278 if (tmp == node) {
6279 tmp = NULL;
6280 break;
6281 }
6282 if (tmp->next != NULL) {
6283 tmp = tmp->next;
6284 break;
6285 }
6286 } while (tmp != NULL);
6287 }
6288 return(ret);
6289}
6290
6291/**
6292 * xmlXPathStringHash:
6293 * @string: a string
6294 *
6295 * Function computing the beginning of the string value of the node,
6296 * used to speed up comparisons
6297 *
6298 * Returns an int usable as a hash
6299 */
6300static unsigned int
6301xmlXPathStringHash(const xmlChar * string) {
6302 if (string == NULL)
6303 return((unsigned int) 0);
6304 if (string[0] == 0)
6305 return(0);
6306 return(((unsigned int) string[0]) +
6307 (((unsigned int) string[1]) << 8));
6308}
6309
6310/**
Owen Taylor3473f882001-02-23 17:55:21 +00006311 * xmlXPathCompareNodeSetFloat:
6312 * @ctxt: the XPath Parser context
6313 * @inf: less than (1) or greater than (0)
6314 * @strict: is the comparison strict
6315 * @arg: the node set
6316 * @f: the value
6317 *
6318 * Implement the compare operation between a nodeset and a number
6319 * @ns < @val (1, 1, ...
6320 * @ns <= @val (1, 0, ...
6321 * @ns > @val (0, 1, ...
6322 * @ns >= @val (0, 0, ...
6323 *
6324 * If one object to be compared is a node-set and the other is a number,
6325 * then the comparison will be true if and only if there is a node in the
6326 * node-set such that the result of performing the comparison on the number
6327 * to be compared and on the result of converting the string-value of that
6328 * node to a number using the number function is true.
6329 *
6330 * Returns 0 or 1 depending on the results of the test.
6331 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006332static int
Owen Taylor3473f882001-02-23 17:55:21 +00006333xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6334 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6335 int i, ret = 0;
6336 xmlNodeSetPtr ns;
6337 xmlChar *str2;
6338
6339 if ((f == NULL) || (arg == NULL) ||
6340 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006341 xmlXPathReleaseObject(ctxt->context, arg);
6342 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006343 return(0);
6344 }
6345 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006346 if (ns != NULL) {
6347 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006348 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006349 if (str2 != NULL) {
6350 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006351 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006352 xmlFree(str2);
6353 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006354 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006355 ret = xmlXPathCompareValues(ctxt, inf, strict);
6356 if (ret)
6357 break;
6358 }
6359 }
Owen Taylor3473f882001-02-23 17:55:21 +00006360 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006361 xmlXPathReleaseObject(ctxt->context, arg);
6362 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006363 return(ret);
6364}
6365
6366/**
6367 * xmlXPathCompareNodeSetString:
6368 * @ctxt: the XPath Parser context
6369 * @inf: less than (1) or greater than (0)
6370 * @strict: is the comparison strict
6371 * @arg: the node set
6372 * @s: the value
6373 *
6374 * Implement the compare operation between a nodeset and a string
6375 * @ns < @val (1, 1, ...
6376 * @ns <= @val (1, 0, ...
6377 * @ns > @val (0, 1, ...
6378 * @ns >= @val (0, 0, ...
6379 *
6380 * If one object to be compared is a node-set and the other is a string,
6381 * then the comparison will be true if and only if there is a node in
6382 * the node-set such that the result of performing the comparison on the
6383 * string-value of the node and the other string is true.
6384 *
6385 * Returns 0 or 1 depending on the results of the test.
6386 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006387static int
Owen Taylor3473f882001-02-23 17:55:21 +00006388xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6389 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6390 int i, ret = 0;
6391 xmlNodeSetPtr ns;
6392 xmlChar *str2;
6393
6394 if ((s == NULL) || (arg == NULL) ||
6395 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006396 xmlXPathReleaseObject(ctxt->context, arg);
6397 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006398 return(0);
6399 }
6400 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006401 if (ns != NULL) {
6402 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006403 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006404 if (str2 != NULL) {
6405 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006406 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006407 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006408 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006409 ret = xmlXPathCompareValues(ctxt, inf, strict);
6410 if (ret)
6411 break;
6412 }
6413 }
Owen Taylor3473f882001-02-23 17:55:21 +00006414 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006415 xmlXPathReleaseObject(ctxt->context, arg);
6416 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006417 return(ret);
6418}
6419
6420/**
6421 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006422 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006423 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006424 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006425 * @arg2: the second node set object
6426 *
6427 * Implement the compare operation on nodesets:
6428 *
6429 * If both objects to be compared are node-sets, then the comparison
6430 * will be true if and only if there is a node in the first node-set
6431 * and a node in the second node-set such that the result of performing
6432 * the comparison on the string-values of the two nodes is true.
6433 * ....
6434 * When neither object to be compared is a node-set and the operator
6435 * is <=, <, >= or >, then the objects are compared by converting both
6436 * objects to numbers and comparing the numbers according to IEEE 754.
6437 * ....
6438 * The number function converts its argument to a number as follows:
6439 * - a string that consists of optional whitespace followed by an
6440 * optional minus sign followed by a Number followed by whitespace
6441 * is converted to the IEEE 754 number that is nearest (according
6442 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6443 * represented by the string; any other string is converted to NaN
6444 *
6445 * Conclusion all nodes need to be converted first to their string value
6446 * and then the comparison must be done when possible
6447 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006448static int
6449xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006450 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6451 int i, j, init = 0;
6452 double val1;
6453 double *values2;
6454 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006455 xmlNodeSetPtr ns1;
6456 xmlNodeSetPtr ns2;
6457
6458 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006459 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6460 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006461 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006462 }
Owen Taylor3473f882001-02-23 17:55:21 +00006463 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006464 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6465 xmlXPathFreeObject(arg1);
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
6470 ns1 = arg1->nodesetval;
6471 ns2 = arg2->nodesetval;
6472
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006473 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006474 xmlXPathFreeObject(arg1);
6475 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006476 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006477 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006478 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006479 xmlXPathFreeObject(arg1);
6480 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006481 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006482 }
Owen Taylor3473f882001-02-23 17:55:21 +00006483
6484 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6485 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006486 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006487 xmlXPathFreeObject(arg1);
6488 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006489 return(0);
6490 }
6491 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006492 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006493 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006494 continue;
6495 for (j = 0;j < ns2->nodeNr;j++) {
6496 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006497 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006498 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006499 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006500 continue;
6501 if (inf && strict)
6502 ret = (val1 < values2[j]);
6503 else if (inf && !strict)
6504 ret = (val1 <= values2[j]);
6505 else if (!inf && strict)
6506 ret = (val1 > values2[j]);
6507 else if (!inf && !strict)
6508 ret = (val1 >= values2[j]);
6509 if (ret)
6510 break;
6511 }
6512 if (ret)
6513 break;
6514 init = 1;
6515 }
6516 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006517 xmlXPathFreeObject(arg1);
6518 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006519 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006520}
6521
6522/**
6523 * xmlXPathCompareNodeSetValue:
6524 * @ctxt: the XPath Parser context
6525 * @inf: less than (1) or greater than (0)
6526 * @strict: is the comparison strict
6527 * @arg: the node set
6528 * @val: the value
6529 *
6530 * Implement the compare operation between a nodeset and a value
6531 * @ns < @val (1, 1, ...
6532 * @ns <= @val (1, 0, ...
6533 * @ns > @val (0, 1, ...
6534 * @ns >= @val (0, 0, ...
6535 *
6536 * If one object to be compared is a node-set and the other is a boolean,
6537 * then the comparison will be true if and only if the result of performing
6538 * the comparison on the boolean and on the result of converting
6539 * the node-set to a boolean using the boolean function is true.
6540 *
6541 * Returns 0 or 1 depending on the results of the test.
6542 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006543static int
Owen Taylor3473f882001-02-23 17:55:21 +00006544xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6545 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6546 if ((val == NULL) || (arg == NULL) ||
6547 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6548 return(0);
6549
6550 switch(val->type) {
6551 case XPATH_NUMBER:
6552 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6553 case XPATH_NODESET:
6554 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006555 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006556 case XPATH_STRING:
6557 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6558 case XPATH_BOOLEAN:
6559 valuePush(ctxt, arg);
6560 xmlXPathBooleanFunction(ctxt, 1);
6561 valuePush(ctxt, val);
6562 return(xmlXPathCompareValues(ctxt, inf, strict));
6563 default:
6564 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006565 }
6566 return(0);
6567}
6568
6569/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006570 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006571 * @arg: the nodeset object argument
6572 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006573 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006574 *
6575 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6576 * If one object to be compared is a node-set and the other is a string,
6577 * then the comparison will be true if and only if there is a node in
6578 * the node-set such that the result of performing the comparison on the
6579 * string-value of the node and the other string is true.
6580 *
6581 * Returns 0 or 1 depending on the results of the test.
6582 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006583static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006584xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006585{
Owen Taylor3473f882001-02-23 17:55:21 +00006586 int i;
6587 xmlNodeSetPtr ns;
6588 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006589 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006590
6591 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006592 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6593 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006594 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006595 /*
6596 * A NULL nodeset compared with a string is always false
6597 * (since there is no node equal, and no node not equal)
6598 */
6599 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006600 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006601 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006602 for (i = 0; i < ns->nodeNr; i++) {
6603 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6604 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6605 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6606 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006607 if (neq)
6608 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006609 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006610 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6611 if (neq)
6612 continue;
6613 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006614 } else if (neq) {
6615 if (str2 != NULL)
6616 xmlFree(str2);
6617 return (1);
6618 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006619 if (str2 != NULL)
6620 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006621 } else if (neq)
6622 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006623 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006624 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006625}
6626
6627/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006628 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006629 * @arg: the nodeset object argument
6630 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006631 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006632 *
6633 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6634 * If one object to be compared is a node-set and the other is a number,
6635 * then the comparison will be true if and only if there is a node in
6636 * the node-set such that the result of performing the comparison on the
6637 * number to be compared and on the result of converting the string-value
6638 * of that node to a number using the number function is true.
6639 *
6640 * Returns 0 or 1 depending on the results of the test.
6641 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006642static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006643xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6644 xmlXPathObjectPtr arg, double f, int neq) {
6645 int i, ret=0;
6646 xmlNodeSetPtr ns;
6647 xmlChar *str2;
6648 xmlXPathObjectPtr val;
6649 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006650
6651 if ((arg == NULL) ||
6652 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6653 return(0);
6654
William M. Brack0c022ad2002-07-12 00:56:01 +00006655 ns = arg->nodesetval;
6656 if (ns != NULL) {
6657 for (i=0;i<ns->nodeNr;i++) {
6658 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6659 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006660 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006661 xmlFree(str2);
6662 xmlXPathNumberFunction(ctxt, 1);
6663 val = valuePop(ctxt);
6664 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006665 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006666 if (!xmlXPathIsNaN(v)) {
6667 if ((!neq) && (v==f)) {
6668 ret = 1;
6669 break;
6670 } else if ((neq) && (v!=f)) {
6671 ret = 1;
6672 break;
6673 }
William M. Brack32f0f712005-07-14 07:00:33 +00006674 } else { /* NaN is unequal to any value */
6675 if (neq)
6676 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006677 }
6678 }
6679 }
6680 }
6681
6682 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006683}
6684
6685
6686/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006687 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006688 * @arg1: first nodeset object argument
6689 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006690 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006691 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006692 * Implement the equal / not equal operation on XPath nodesets:
6693 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006694 * If both objects to be compared are node-sets, then the comparison
6695 * will be true if and only if there is a node in the first node-set and
6696 * a node in the second node-set such that the result of performing the
6697 * comparison on the string-values of the two nodes is true.
6698 *
6699 * (needless to say, this is a costly operation)
6700 *
6701 * Returns 0 or 1 depending on the results of the test.
6702 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006703static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006704xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006705 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006706 unsigned int *hashs1;
6707 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006708 xmlChar **values1;
6709 xmlChar **values2;
6710 int ret = 0;
6711 xmlNodeSetPtr ns1;
6712 xmlNodeSetPtr ns2;
6713
6714 if ((arg1 == NULL) ||
6715 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6716 return(0);
6717 if ((arg2 == NULL) ||
6718 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6719 return(0);
6720
6721 ns1 = arg1->nodesetval;
6722 ns2 = arg2->nodesetval;
6723
Daniel Veillard911f49a2001-04-07 15:39:35 +00006724 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006725 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006726 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006727 return(0);
6728
6729 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006730 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006731 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006732 if (neq == 0)
6733 for (i = 0;i < ns1->nodeNr;i++)
6734 for (j = 0;j < ns2->nodeNr;j++)
6735 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6736 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006737
6738 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006739 if (values1 == NULL) {
6740 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006741 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006742 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006743 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6744 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006745 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006746 xmlFree(values1);
6747 return(0);
6748 }
Owen Taylor3473f882001-02-23 17:55:21 +00006749 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6750 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6751 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006752 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006753 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006754 xmlFree(values1);
6755 return(0);
6756 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006757 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6758 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006759 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006760 xmlFree(hashs1);
6761 xmlFree(values1);
6762 xmlFree(values2);
6763 return(0);
6764 }
Owen Taylor3473f882001-02-23 17:55:21 +00006765 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6766 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006767 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006768 for (j = 0;j < ns2->nodeNr;j++) {
6769 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006770 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006771 if (hashs1[i] != hashs2[j]) {
6772 if (neq) {
6773 ret = 1;
6774 break;
6775 }
6776 }
6777 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006778 if (values1[i] == NULL)
6779 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6780 if (values2[j] == NULL)
6781 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006782 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006783 if (ret)
6784 break;
6785 }
Owen Taylor3473f882001-02-23 17:55:21 +00006786 }
6787 if (ret)
6788 break;
6789 }
6790 for (i = 0;i < ns1->nodeNr;i++)
6791 if (values1[i] != NULL)
6792 xmlFree(values1[i]);
6793 for (j = 0;j < ns2->nodeNr;j++)
6794 if (values2[j] != NULL)
6795 xmlFree(values2[j]);
6796 xmlFree(values1);
6797 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006798 xmlFree(hashs1);
6799 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006800 return(ret);
6801}
6802
William M. Brack0c022ad2002-07-12 00:56:01 +00006803static int
6804xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6805 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006806 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006807 /*
6808 *At this point we are assured neither arg1 nor arg2
6809 *is a nodeset, so we can just pick the appropriate routine.
6810 */
Owen Taylor3473f882001-02-23 17:55:21 +00006811 switch (arg1->type) {
6812 case XPATH_UNDEFINED:
6813#ifdef DEBUG_EXPR
6814 xmlGenericError(xmlGenericErrorContext,
6815 "Equal: undefined\n");
6816#endif
6817 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006818 case XPATH_BOOLEAN:
6819 switch (arg2->type) {
6820 case XPATH_UNDEFINED:
6821#ifdef DEBUG_EXPR
6822 xmlGenericError(xmlGenericErrorContext,
6823 "Equal: undefined\n");
6824#endif
6825 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006826 case XPATH_BOOLEAN:
6827#ifdef DEBUG_EXPR
6828 xmlGenericError(xmlGenericErrorContext,
6829 "Equal: %d boolean %d \n",
6830 arg1->boolval, arg2->boolval);
6831#endif
6832 ret = (arg1->boolval == arg2->boolval);
6833 break;
6834 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006835 ret = (arg1->boolval ==
6836 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006837 break;
6838 case XPATH_STRING:
6839 if ((arg2->stringval == NULL) ||
6840 (arg2->stringval[0] == 0)) ret = 0;
6841 else
6842 ret = 1;
6843 ret = (arg1->boolval == ret);
6844 break;
6845 case XPATH_USERS:
6846 case XPATH_POINT:
6847 case XPATH_RANGE:
6848 case XPATH_LOCATIONSET:
6849 TODO
6850 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006851 case XPATH_NODESET:
6852 case XPATH_XSLT_TREE:
6853 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006854 }
6855 break;
6856 case XPATH_NUMBER:
6857 switch (arg2->type) {
6858 case XPATH_UNDEFINED:
6859#ifdef DEBUG_EXPR
6860 xmlGenericError(xmlGenericErrorContext,
6861 "Equal: undefined\n");
6862#endif
6863 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006864 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006865 ret = (arg2->boolval==
6866 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006867 break;
6868 case XPATH_STRING:
6869 valuePush(ctxt, arg2);
6870 xmlXPathNumberFunction(ctxt, 1);
6871 arg2 = valuePop(ctxt);
6872 /* no break on purpose */
6873 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006874 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006875 if (xmlXPathIsNaN(arg1->floatval) ||
6876 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006877 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006878 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6879 if (xmlXPathIsInf(arg2->floatval) == 1)
6880 ret = 1;
6881 else
6882 ret = 0;
6883 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6884 if (xmlXPathIsInf(arg2->floatval) == -1)
6885 ret = 1;
6886 else
6887 ret = 0;
6888 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6889 if (xmlXPathIsInf(arg1->floatval) == 1)
6890 ret = 1;
6891 else
6892 ret = 0;
6893 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6894 if (xmlXPathIsInf(arg1->floatval) == -1)
6895 ret = 1;
6896 else
6897 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006898 } else {
6899 ret = (arg1->floatval == arg2->floatval);
6900 }
Owen Taylor3473f882001-02-23 17:55:21 +00006901 break;
6902 case XPATH_USERS:
6903 case XPATH_POINT:
6904 case XPATH_RANGE:
6905 case XPATH_LOCATIONSET:
6906 TODO
6907 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006908 case XPATH_NODESET:
6909 case XPATH_XSLT_TREE:
6910 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006911 }
6912 break;
6913 case XPATH_STRING:
6914 switch (arg2->type) {
6915 case XPATH_UNDEFINED:
6916#ifdef DEBUG_EXPR
6917 xmlGenericError(xmlGenericErrorContext,
6918 "Equal: undefined\n");
6919#endif
6920 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006921 case XPATH_BOOLEAN:
6922 if ((arg1->stringval == NULL) ||
6923 (arg1->stringval[0] == 0)) ret = 0;
6924 else
6925 ret = 1;
6926 ret = (arg2->boolval == ret);
6927 break;
6928 case XPATH_STRING:
6929 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6930 break;
6931 case XPATH_NUMBER:
6932 valuePush(ctxt, arg1);
6933 xmlXPathNumberFunction(ctxt, 1);
6934 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006935 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006936 if (xmlXPathIsNaN(arg1->floatval) ||
6937 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006938 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006939 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6940 if (xmlXPathIsInf(arg2->floatval) == 1)
6941 ret = 1;
6942 else
6943 ret = 0;
6944 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6945 if (xmlXPathIsInf(arg2->floatval) == -1)
6946 ret = 1;
6947 else
6948 ret = 0;
6949 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6950 if (xmlXPathIsInf(arg1->floatval) == 1)
6951 ret = 1;
6952 else
6953 ret = 0;
6954 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6955 if (xmlXPathIsInf(arg1->floatval) == -1)
6956 ret = 1;
6957 else
6958 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006959 } else {
6960 ret = (arg1->floatval == arg2->floatval);
6961 }
Owen Taylor3473f882001-02-23 17:55:21 +00006962 break;
6963 case XPATH_USERS:
6964 case XPATH_POINT:
6965 case XPATH_RANGE:
6966 case XPATH_LOCATIONSET:
6967 TODO
6968 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006969 case XPATH_NODESET:
6970 case XPATH_XSLT_TREE:
6971 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006972 }
6973 break;
6974 case XPATH_USERS:
6975 case XPATH_POINT:
6976 case XPATH_RANGE:
6977 case XPATH_LOCATIONSET:
6978 TODO
6979 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006980 case XPATH_NODESET:
6981 case XPATH_XSLT_TREE:
6982 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006983 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006984 xmlXPathReleaseObject(ctxt->context, arg1);
6985 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006986 return(ret);
6987}
6988
William M. Brack0c022ad2002-07-12 00:56:01 +00006989/**
6990 * xmlXPathEqualValues:
6991 * @ctxt: the XPath Parser context
6992 *
6993 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6994 *
6995 * Returns 0 or 1 depending on the results of the test.
6996 */
6997int
6998xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6999 xmlXPathObjectPtr arg1, arg2, argtmp;
7000 int ret = 0;
7001
Daniel Veillard6128c012004-11-08 17:16:15 +00007002 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007003 arg2 = valuePop(ctxt);
7004 arg1 = valuePop(ctxt);
7005 if ((arg1 == NULL) || (arg2 == NULL)) {
7006 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007007 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007008 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007009 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007010 XP_ERROR0(XPATH_INVALID_OPERAND);
7011 }
7012
7013 if (arg1 == arg2) {
7014#ifdef DEBUG_EXPR
7015 xmlGenericError(xmlGenericErrorContext,
7016 "Equal: by pointer\n");
7017#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007018 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007019 return(1);
7020 }
7021
7022 /*
7023 *If either argument is a nodeset, it's a 'special case'
7024 */
7025 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7026 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7027 /*
7028 *Hack it to assure arg1 is the nodeset
7029 */
7030 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7031 argtmp = arg2;
7032 arg2 = arg1;
7033 arg1 = argtmp;
7034 }
7035 switch (arg2->type) {
7036 case XPATH_UNDEFINED:
7037#ifdef DEBUG_EXPR
7038 xmlGenericError(xmlGenericErrorContext,
7039 "Equal: undefined\n");
7040#endif
7041 break;
7042 case XPATH_NODESET:
7043 case XPATH_XSLT_TREE:
7044 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7045 break;
7046 case XPATH_BOOLEAN:
7047 if ((arg1->nodesetval == NULL) ||
7048 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7049 else
7050 ret = 1;
7051 ret = (ret == arg2->boolval);
7052 break;
7053 case XPATH_NUMBER:
7054 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7055 break;
7056 case XPATH_STRING:
7057 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7058 break;
7059 case XPATH_USERS:
7060 case XPATH_POINT:
7061 case XPATH_RANGE:
7062 case XPATH_LOCATIONSET:
7063 TODO
7064 break;
7065 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007066 xmlXPathReleaseObject(ctxt->context, arg1);
7067 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007068 return(ret);
7069 }
7070
7071 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7072}
7073
7074/**
7075 * xmlXPathNotEqualValues:
7076 * @ctxt: the XPath Parser context
7077 *
7078 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7079 *
7080 * Returns 0 or 1 depending on the results of the test.
7081 */
7082int
7083xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7084 xmlXPathObjectPtr arg1, arg2, argtmp;
7085 int ret = 0;
7086
Daniel Veillard6128c012004-11-08 17:16:15 +00007087 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007088 arg2 = valuePop(ctxt);
7089 arg1 = valuePop(ctxt);
7090 if ((arg1 == NULL) || (arg2 == NULL)) {
7091 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007092 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007093 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007094 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007095 XP_ERROR0(XPATH_INVALID_OPERAND);
7096 }
7097
7098 if (arg1 == arg2) {
7099#ifdef DEBUG_EXPR
7100 xmlGenericError(xmlGenericErrorContext,
7101 "NotEqual: by pointer\n");
7102#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007103 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007104 return(0);
7105 }
7106
7107 /*
7108 *If either argument is a nodeset, it's a 'special case'
7109 */
7110 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7111 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7112 /*
7113 *Hack it to assure arg1 is the nodeset
7114 */
7115 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7116 argtmp = arg2;
7117 arg2 = arg1;
7118 arg1 = argtmp;
7119 }
7120 switch (arg2->type) {
7121 case XPATH_UNDEFINED:
7122#ifdef DEBUG_EXPR
7123 xmlGenericError(xmlGenericErrorContext,
7124 "NotEqual: undefined\n");
7125#endif
7126 break;
7127 case XPATH_NODESET:
7128 case XPATH_XSLT_TREE:
7129 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7130 break;
7131 case XPATH_BOOLEAN:
7132 if ((arg1->nodesetval == NULL) ||
7133 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7134 else
7135 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007136 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007137 break;
7138 case XPATH_NUMBER:
7139 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7140 break;
7141 case XPATH_STRING:
7142 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7143 break;
7144 case XPATH_USERS:
7145 case XPATH_POINT:
7146 case XPATH_RANGE:
7147 case XPATH_LOCATIONSET:
7148 TODO
7149 break;
7150 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007151 xmlXPathReleaseObject(ctxt->context, arg1);
7152 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007153 return(ret);
7154 }
7155
7156 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7157}
Owen Taylor3473f882001-02-23 17:55:21 +00007158
7159/**
7160 * xmlXPathCompareValues:
7161 * @ctxt: the XPath Parser context
7162 * @inf: less than (1) or greater than (0)
7163 * @strict: is the comparison strict
7164 *
7165 * Implement the compare operation on XPath objects:
7166 * @arg1 < @arg2 (1, 1, ...
7167 * @arg1 <= @arg2 (1, 0, ...
7168 * @arg1 > @arg2 (0, 1, ...
7169 * @arg1 >= @arg2 (0, 0, ...
7170 *
7171 * When neither object to be compared is a node-set and the operator is
7172 * <=, <, >=, >, then the objects are compared by converted both objects
7173 * to numbers and comparing the numbers according to IEEE 754. The <
7174 * comparison will be true if and only if the first number is less than the
7175 * second number. The <= comparison will be true if and only if the first
7176 * number is less than or equal to the second number. The > comparison
7177 * will be true if and only if the first number is greater than the second
7178 * number. The >= comparison will be true if and only if the first number
7179 * is greater than or equal to the second number.
7180 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007181 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007182 */
7183int
7184xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007185 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007186 xmlXPathObjectPtr arg1, arg2;
7187
Daniel Veillard6128c012004-11-08 17:16:15 +00007188 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007189 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007190 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007191 if ((arg1 == NULL) || (arg2 == NULL)) {
7192 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007193 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007194 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007195 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007196 XP_ERROR0(XPATH_INVALID_OPERAND);
7197 }
7198
William M. Brack0c022ad2002-07-12 00:56:01 +00007199 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7200 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007201 /*
7202 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7203 * are not freed from within this routine; they will be freed from the
7204 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7205 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007206 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7207 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007208 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007209 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007210 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007211 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7212 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007213 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007214 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7215 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007216 }
7217 }
7218 return(ret);
7219 }
7220
7221 if (arg1->type != XPATH_NUMBER) {
7222 valuePush(ctxt, arg1);
7223 xmlXPathNumberFunction(ctxt, 1);
7224 arg1 = valuePop(ctxt);
7225 }
7226 if (arg1->type != XPATH_NUMBER) {
7227 xmlXPathFreeObject(arg1);
7228 xmlXPathFreeObject(arg2);
7229 XP_ERROR0(XPATH_INVALID_OPERAND);
7230 }
7231 if (arg2->type != XPATH_NUMBER) {
7232 valuePush(ctxt, arg2);
7233 xmlXPathNumberFunction(ctxt, 1);
7234 arg2 = valuePop(ctxt);
7235 }
7236 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007237 xmlXPathReleaseObject(ctxt->context, arg1);
7238 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007239 XP_ERROR0(XPATH_INVALID_OPERAND);
7240 }
7241 /*
7242 * Add tests for infinity and nan
7243 * => feedback on 3.4 for Inf and NaN
7244 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007245 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007246 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007247 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007248 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007249 arg1i=xmlXPathIsInf(arg1->floatval);
7250 arg2i=xmlXPathIsInf(arg2->floatval);
7251 if (inf && strict) {
7252 if ((arg1i == -1 && arg2i != -1) ||
7253 (arg2i == 1 && arg1i != 1)) {
7254 ret = 1;
7255 } else if (arg1i == 0 && arg2i == 0) {
7256 ret = (arg1->floatval < arg2->floatval);
7257 } else {
7258 ret = 0;
7259 }
7260 }
7261 else if (inf && !strict) {
7262 if (arg1i == -1 || arg2i == 1) {
7263 ret = 1;
7264 } else if (arg1i == 0 && arg2i == 0) {
7265 ret = (arg1->floatval <= arg2->floatval);
7266 } else {
7267 ret = 0;
7268 }
7269 }
7270 else if (!inf && strict) {
7271 if ((arg1i == 1 && arg2i != 1) ||
7272 (arg2i == -1 && arg1i != -1)) {
7273 ret = 1;
7274 } else if (arg1i == 0 && arg2i == 0) {
7275 ret = (arg1->floatval > arg2->floatval);
7276 } else {
7277 ret = 0;
7278 }
7279 }
7280 else if (!inf && !strict) {
7281 if (arg1i == 1 || arg2i == -1) {
7282 ret = 1;
7283 } else if (arg1i == 0 && arg2i == 0) {
7284 ret = (arg1->floatval >= arg2->floatval);
7285 } else {
7286 ret = 0;
7287 }
7288 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007289 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007290 xmlXPathReleaseObject(ctxt->context, arg1);
7291 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007292 return(ret);
7293}
7294
7295/**
7296 * xmlXPathValueFlipSign:
7297 * @ctxt: the XPath Parser context
7298 *
7299 * Implement the unary - operation on an XPath object
7300 * The numeric operators convert their operands to numbers as if
7301 * by calling the number function.
7302 */
7303void
7304xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007305 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007306 CAST_TO_NUMBER;
7307 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007308 if (xmlXPathIsNaN(ctxt->value->floatval))
7309 ctxt->value->floatval=xmlXPathNAN;
7310 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7311 ctxt->value->floatval=xmlXPathNINF;
7312 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7313 ctxt->value->floatval=xmlXPathPINF;
7314 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007315 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7316 ctxt->value->floatval = xmlXPathNZERO;
7317 else
7318 ctxt->value->floatval = 0;
7319 }
7320 else
7321 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007322}
7323
7324/**
7325 * xmlXPathAddValues:
7326 * @ctxt: the XPath Parser context
7327 *
7328 * Implement the add operation on XPath objects:
7329 * The numeric operators convert their operands to numbers as if
7330 * by calling the number function.
7331 */
7332void
7333xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7334 xmlXPathObjectPtr arg;
7335 double val;
7336
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007337 arg = valuePop(ctxt);
7338 if (arg == NULL)
7339 XP_ERROR(XPATH_INVALID_OPERAND);
7340 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007341 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007342 CAST_TO_NUMBER;
7343 CHECK_TYPE(XPATH_NUMBER);
7344 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007345}
7346
7347/**
7348 * xmlXPathSubValues:
7349 * @ctxt: the XPath Parser context
7350 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007351 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007352 * The numeric operators convert their operands to numbers as if
7353 * by calling the number function.
7354 */
7355void
7356xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7357 xmlXPathObjectPtr arg;
7358 double val;
7359
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007360 arg = valuePop(ctxt);
7361 if (arg == NULL)
7362 XP_ERROR(XPATH_INVALID_OPERAND);
7363 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007364 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007365 CAST_TO_NUMBER;
7366 CHECK_TYPE(XPATH_NUMBER);
7367 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007368}
7369
7370/**
7371 * xmlXPathMultValues:
7372 * @ctxt: the XPath Parser context
7373 *
7374 * Implement the multiply operation on XPath objects:
7375 * The numeric operators convert their operands to numbers as if
7376 * by calling the number function.
7377 */
7378void
7379xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7380 xmlXPathObjectPtr arg;
7381 double val;
7382
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007383 arg = valuePop(ctxt);
7384 if (arg == NULL)
7385 XP_ERROR(XPATH_INVALID_OPERAND);
7386 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007387 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007388 CAST_TO_NUMBER;
7389 CHECK_TYPE(XPATH_NUMBER);
7390 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007391}
7392
7393/**
7394 * xmlXPathDivValues:
7395 * @ctxt: the XPath Parser context
7396 *
7397 * Implement the div operation on XPath objects @arg1 / @arg2:
7398 * The numeric operators convert their operands to numbers as if
7399 * by calling the number function.
7400 */
7401void
7402xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7403 xmlXPathObjectPtr arg;
7404 double val;
7405
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007406 arg = valuePop(ctxt);
7407 if (arg == NULL)
7408 XP_ERROR(XPATH_INVALID_OPERAND);
7409 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007410 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007411 CAST_TO_NUMBER;
7412 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007413 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7414 ctxt->value->floatval = xmlXPathNAN;
7415 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007416 if (ctxt->value->floatval == 0)
7417 ctxt->value->floatval = xmlXPathNAN;
7418 else if (ctxt->value->floatval > 0)
7419 ctxt->value->floatval = xmlXPathNINF;
7420 else if (ctxt->value->floatval < 0)
7421 ctxt->value->floatval = xmlXPathPINF;
7422 }
7423 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007424 if (ctxt->value->floatval == 0)
7425 ctxt->value->floatval = xmlXPathNAN;
7426 else if (ctxt->value->floatval > 0)
7427 ctxt->value->floatval = xmlXPathPINF;
7428 else if (ctxt->value->floatval < 0)
7429 ctxt->value->floatval = xmlXPathNINF;
7430 } else
7431 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007432}
7433
7434/**
7435 * xmlXPathModValues:
7436 * @ctxt: the XPath Parser context
7437 *
7438 * Implement the mod operation on XPath objects: @arg1 / @arg2
7439 * The numeric operators convert their operands to numbers as if
7440 * by calling the number function.
7441 */
7442void
7443xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7444 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007445 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007446
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007447 arg = valuePop(ctxt);
7448 if (arg == NULL)
7449 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007450 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007451 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007452 CAST_TO_NUMBER;
7453 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007454 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007455 if (arg2 == 0)
7456 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007457 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007458 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007459 }
Owen Taylor3473f882001-02-23 17:55:21 +00007460}
7461
7462/************************************************************************
7463 * *
7464 * The traversal functions *
7465 * *
7466 ************************************************************************/
7467
Owen Taylor3473f882001-02-23 17:55:21 +00007468/*
7469 * A traversal function enumerates nodes along an axis.
7470 * Initially it must be called with NULL, and it indicates
7471 * termination on the axis by returning NULL.
7472 */
7473typedef xmlNodePtr (*xmlXPathTraversalFunction)
7474 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7475
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007476/*
7477 * xmlXPathTraversalFunctionExt:
7478 * A traversal function enumerates nodes along an axis.
7479 * Initially it must be called with NULL, and it indicates
7480 * termination on the axis by returning NULL.
7481 * The context node of the traversal is specified via @contextNode.
7482 */
7483typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7484 (xmlNodePtr cur, xmlNodePtr contextNode);
7485
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007486/*
7487 * xmlXPathNodeSetMergeFunction:
7488 * Used for merging node sets in xmlXPathCollectAndTest().
7489 */
7490typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7491 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7492
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007493
Owen Taylor3473f882001-02-23 17:55:21 +00007494/**
7495 * xmlXPathNextSelf:
7496 * @ctxt: the XPath Parser context
7497 * @cur: the current node in the traversal
7498 *
7499 * Traversal function for the "self" direction
7500 * The self axis contains just the context node itself
7501 *
7502 * Returns the next element following that axis
7503 */
7504xmlNodePtr
7505xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007506 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007507 if (cur == NULL)
7508 return(ctxt->context->node);
7509 return(NULL);
7510}
7511
7512/**
7513 * xmlXPathNextChild:
7514 * @ctxt: the XPath Parser context
7515 * @cur: the current node in the traversal
7516 *
7517 * Traversal function for the "child" direction
7518 * The child axis contains the children of the context node in document order.
7519 *
7520 * Returns the next element following that axis
7521 */
7522xmlNodePtr
7523xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007524 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007525 if (cur == NULL) {
7526 if (ctxt->context->node == NULL) return(NULL);
7527 switch (ctxt->context->node->type) {
7528 case XML_ELEMENT_NODE:
7529 case XML_TEXT_NODE:
7530 case XML_CDATA_SECTION_NODE:
7531 case XML_ENTITY_REF_NODE:
7532 case XML_ENTITY_NODE:
7533 case XML_PI_NODE:
7534 case XML_COMMENT_NODE:
7535 case XML_NOTATION_NODE:
7536 case XML_DTD_NODE:
7537 return(ctxt->context->node->children);
7538 case XML_DOCUMENT_NODE:
7539 case XML_DOCUMENT_TYPE_NODE:
7540 case XML_DOCUMENT_FRAG_NODE:
7541 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007542#ifdef LIBXML_DOCB_ENABLED
7543 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007544#endif
7545 return(((xmlDocPtr) ctxt->context->node)->children);
7546 case XML_ELEMENT_DECL:
7547 case XML_ATTRIBUTE_DECL:
7548 case XML_ENTITY_DECL:
7549 case XML_ATTRIBUTE_NODE:
7550 case XML_NAMESPACE_DECL:
7551 case XML_XINCLUDE_START:
7552 case XML_XINCLUDE_END:
7553 return(NULL);
7554 }
7555 return(NULL);
7556 }
7557 if ((cur->type == XML_DOCUMENT_NODE) ||
7558 (cur->type == XML_HTML_DOCUMENT_NODE))
7559 return(NULL);
7560 return(cur->next);
7561}
7562
7563/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007564 * xmlXPathNextChildElement:
7565 * @ctxt: the XPath Parser context
7566 * @cur: the current node in the traversal
7567 *
7568 * Traversal function for the "child" direction and nodes of type element.
7569 * The child axis contains the children of the context node in document order.
7570 *
7571 * Returns the next element following that axis
7572 */
7573static xmlNodePtr
7574xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7575 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7576 if (cur == NULL) {
7577 cur = ctxt->context->node;
7578 if (cur == NULL) return(NULL);
7579 /*
7580 * Get the first element child.
7581 */
7582 switch (cur->type) {
7583 case XML_ELEMENT_NODE:
7584 case XML_DOCUMENT_FRAG_NODE:
7585 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7586 case XML_ENTITY_NODE:
7587 cur = cur->children;
7588 if (cur != NULL) {
7589 if (cur->type == XML_ELEMENT_NODE)
7590 return(cur);
7591 do {
7592 cur = cur->next;
7593 } while ((cur != NULL) &&
7594 (cur->type != XML_ELEMENT_NODE));
7595 return(cur);
7596 }
7597 return(NULL);
7598 case XML_DOCUMENT_NODE:
7599 case XML_HTML_DOCUMENT_NODE:
7600#ifdef LIBXML_DOCB_ENABLED
7601 case XML_DOCB_DOCUMENT_NODE:
7602#endif
7603 return(xmlDocGetRootElement((xmlDocPtr) cur));
7604 default:
7605 return(NULL);
7606 }
7607 return(NULL);
7608 }
7609 /*
7610 * Get the next sibling element node.
7611 */
7612 switch (cur->type) {
7613 case XML_ELEMENT_NODE:
7614 case XML_TEXT_NODE:
7615 case XML_ENTITY_REF_NODE:
7616 case XML_ENTITY_NODE:
7617 case XML_CDATA_SECTION_NODE:
7618 case XML_PI_NODE:
7619 case XML_COMMENT_NODE:
7620 case XML_XINCLUDE_END:
7621 break;
7622 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7623 default:
7624 return(NULL);
7625 }
7626 if (cur->next != NULL) {
7627 if (cur->next->type == XML_ELEMENT_NODE)
7628 return(cur->next);
7629 cur = cur->next;
7630 do {
7631 cur = cur->next;
7632 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7633 return(cur);
7634 }
7635 return(NULL);
7636}
7637
7638/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007639 * xmlXPathNextDescendantOrSelfElemParent:
7640 * @ctxt: the XPath Parser context
7641 * @cur: the current node in the traversal
7642 *
7643 * Traversal function for the "descendant-or-self" axis.
7644 * Additionally it returns only nodes which can be parents of
7645 * element nodes.
7646 *
7647 *
7648 * Returns the next element following that axis
7649 */
7650static xmlNodePtr
7651xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7652 xmlNodePtr contextNode)
7653{
7654 if (cur == NULL) {
7655 if (contextNode == NULL)
7656 return(NULL);
7657 switch (contextNode->type) {
7658 case XML_ELEMENT_NODE:
7659 case XML_XINCLUDE_START:
7660 case XML_DOCUMENT_FRAG_NODE:
7661 case XML_DOCUMENT_NODE:
7662#ifdef LIBXML_DOCB_ENABLED
7663 case XML_DOCB_DOCUMENT_NODE:
7664#endif
7665 case XML_HTML_DOCUMENT_NODE:
7666 return(contextNode);
7667 default:
7668 return(NULL);
7669 }
7670 return(NULL);
7671 } else {
7672 xmlNodePtr start = cur;
7673
7674 while (cur != NULL) {
7675 switch (cur->type) {
7676 case XML_ELEMENT_NODE:
7677 /* TODO: OK to have XInclude here? */
7678 case XML_XINCLUDE_START:
7679 case XML_DOCUMENT_FRAG_NODE:
7680 if (cur != start)
7681 return(cur);
7682 if (cur->children != NULL) {
7683 cur = cur->children;
7684 continue;
7685 }
7686 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007687 /* Not sure if we need those here. */
7688 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007689#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007690 case XML_DOCB_DOCUMENT_NODE:
7691#endif
7692 case XML_HTML_DOCUMENT_NODE:
7693 if (cur != start)
7694 return(cur);
7695 return(xmlDocGetRootElement((xmlDocPtr) cur));
7696 default:
7697 break;
7698 }
7699
7700next_sibling:
7701 if ((cur == NULL) || (cur == contextNode))
7702 return(NULL);
7703 if (cur->next != NULL) {
7704 cur = cur->next;
7705 } else {
7706 cur = cur->parent;
7707 goto next_sibling;
7708 }
7709 }
7710 }
7711 return(NULL);
7712}
7713
7714/**
Owen Taylor3473f882001-02-23 17:55:21 +00007715 * xmlXPathNextDescendant:
7716 * @ctxt: the XPath Parser context
7717 * @cur: the current node in the traversal
7718 *
7719 * Traversal function for the "descendant" direction
7720 * the descendant axis contains the descendants of the context node in document
7721 * order; a descendant is a child or a child of a child and so on.
7722 *
7723 * Returns the next element following that axis
7724 */
7725xmlNodePtr
7726xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007727 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007728 if (cur == NULL) {
7729 if (ctxt->context->node == NULL)
7730 return(NULL);
7731 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7732 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7733 return(NULL);
7734
7735 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7736 return(ctxt->context->doc->children);
7737 return(ctxt->context->node->children);
7738 }
7739
Daniel Veillard567e1b42001-08-01 15:53:47 +00007740 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007741 /*
7742 * Do not descend on entities declarations
7743 */
7744 if (cur->children->type != XML_ENTITY_DECL) {
7745 cur = cur->children;
7746 /*
7747 * Skip DTDs
7748 */
7749 if (cur->type != XML_DTD_NODE)
7750 return(cur);
7751 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007752 }
7753
7754 if (cur == ctxt->context->node) return(NULL);
7755
Daniel Veillard68e9e742002-11-16 15:35:11 +00007756 while (cur->next != NULL) {
7757 cur = cur->next;
7758 if ((cur->type != XML_ENTITY_DECL) &&
7759 (cur->type != XML_DTD_NODE))
7760 return(cur);
7761 }
Owen Taylor3473f882001-02-23 17:55:21 +00007762
7763 do {
7764 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007765 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007766 if (cur == ctxt->context->node) return(NULL);
7767 if (cur->next != NULL) {
7768 cur = cur->next;
7769 return(cur);
7770 }
7771 } while (cur != NULL);
7772 return(cur);
7773}
7774
7775/**
7776 * xmlXPathNextDescendantOrSelf:
7777 * @ctxt: the XPath Parser context
7778 * @cur: the current node in the traversal
7779 *
7780 * Traversal function for the "descendant-or-self" direction
7781 * the descendant-or-self axis contains the context node and the descendants
7782 * of the context node in document order; thus the context node is the first
7783 * node on the axis, and the first child of the context node is the second node
7784 * on the axis
7785 *
7786 * Returns the next element following that axis
7787 */
7788xmlNodePtr
7789xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007790 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007791 if (cur == NULL) {
7792 if (ctxt->context->node == NULL)
7793 return(NULL);
7794 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7795 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7796 return(NULL);
7797 return(ctxt->context->node);
7798 }
7799
7800 return(xmlXPathNextDescendant(ctxt, cur));
7801}
7802
7803/**
7804 * xmlXPathNextParent:
7805 * @ctxt: the XPath Parser context
7806 * @cur: the current node in the traversal
7807 *
7808 * Traversal function for the "parent" direction
7809 * The parent axis contains the parent of the context node, if there is one.
7810 *
7811 * Returns the next element following that axis
7812 */
7813xmlNodePtr
7814xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007815 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007816 /*
7817 * the parent of an attribute or namespace node is the element
7818 * to which the attribute or namespace node is attached
7819 * Namespace handling !!!
7820 */
7821 if (cur == NULL) {
7822 if (ctxt->context->node == NULL) return(NULL);
7823 switch (ctxt->context->node->type) {
7824 case XML_ELEMENT_NODE:
7825 case XML_TEXT_NODE:
7826 case XML_CDATA_SECTION_NODE:
7827 case XML_ENTITY_REF_NODE:
7828 case XML_ENTITY_NODE:
7829 case XML_PI_NODE:
7830 case XML_COMMENT_NODE:
7831 case XML_NOTATION_NODE:
7832 case XML_DTD_NODE:
7833 case XML_ELEMENT_DECL:
7834 case XML_ATTRIBUTE_DECL:
7835 case XML_XINCLUDE_START:
7836 case XML_XINCLUDE_END:
7837 case XML_ENTITY_DECL:
7838 if (ctxt->context->node->parent == NULL)
7839 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007840 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007841 ((ctxt->context->node->parent->name[0] == ' ') ||
7842 (xmlStrEqual(ctxt->context->node->parent->name,
7843 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007844 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007845 return(ctxt->context->node->parent);
7846 case XML_ATTRIBUTE_NODE: {
7847 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7848
7849 return(att->parent);
7850 }
7851 case XML_DOCUMENT_NODE:
7852 case XML_DOCUMENT_TYPE_NODE:
7853 case XML_DOCUMENT_FRAG_NODE:
7854 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007855#ifdef LIBXML_DOCB_ENABLED
7856 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007857#endif
7858 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007859 case XML_NAMESPACE_DECL: {
7860 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7861
7862 if ((ns->next != NULL) &&
7863 (ns->next->type != XML_NAMESPACE_DECL))
7864 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007865 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007866 }
Owen Taylor3473f882001-02-23 17:55:21 +00007867 }
7868 }
7869 return(NULL);
7870}
7871
7872/**
7873 * xmlXPathNextAncestor:
7874 * @ctxt: the XPath Parser context
7875 * @cur: the current node in the traversal
7876 *
7877 * Traversal function for the "ancestor" direction
7878 * the ancestor axis contains the ancestors of the context node; the ancestors
7879 * of the context node consist of the parent of context node and the parent's
7880 * parent and so on; the nodes are ordered in reverse document order; thus the
7881 * parent is the first node on the axis, and the parent's parent is the second
7882 * node on the axis
7883 *
7884 * Returns the next element following that axis
7885 */
7886xmlNodePtr
7887xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007888 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007889 /*
7890 * the parent of an attribute or namespace node is the element
7891 * to which the attribute or namespace node is attached
7892 * !!!!!!!!!!!!!
7893 */
7894 if (cur == NULL) {
7895 if (ctxt->context->node == NULL) return(NULL);
7896 switch (ctxt->context->node->type) {
7897 case XML_ELEMENT_NODE:
7898 case XML_TEXT_NODE:
7899 case XML_CDATA_SECTION_NODE:
7900 case XML_ENTITY_REF_NODE:
7901 case XML_ENTITY_NODE:
7902 case XML_PI_NODE:
7903 case XML_COMMENT_NODE:
7904 case XML_DTD_NODE:
7905 case XML_ELEMENT_DECL:
7906 case XML_ATTRIBUTE_DECL:
7907 case XML_ENTITY_DECL:
7908 case XML_NOTATION_NODE:
7909 case XML_XINCLUDE_START:
7910 case XML_XINCLUDE_END:
7911 if (ctxt->context->node->parent == NULL)
7912 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007913 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007914 ((ctxt->context->node->parent->name[0] == ' ') ||
7915 (xmlStrEqual(ctxt->context->node->parent->name,
7916 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007917 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007918 return(ctxt->context->node->parent);
7919 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007920 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007921
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007922 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007923 }
7924 case XML_DOCUMENT_NODE:
7925 case XML_DOCUMENT_TYPE_NODE:
7926 case XML_DOCUMENT_FRAG_NODE:
7927 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007928#ifdef LIBXML_DOCB_ENABLED
7929 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007930#endif
7931 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007932 case XML_NAMESPACE_DECL: {
7933 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7934
7935 if ((ns->next != NULL) &&
7936 (ns->next->type != XML_NAMESPACE_DECL))
7937 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007938 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007939 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007940 }
Owen Taylor3473f882001-02-23 17:55:21 +00007941 }
7942 return(NULL);
7943 }
7944 if (cur == ctxt->context->doc->children)
7945 return((xmlNodePtr) ctxt->context->doc);
7946 if (cur == (xmlNodePtr) ctxt->context->doc)
7947 return(NULL);
7948 switch (cur->type) {
7949 case XML_ELEMENT_NODE:
7950 case XML_TEXT_NODE:
7951 case XML_CDATA_SECTION_NODE:
7952 case XML_ENTITY_REF_NODE:
7953 case XML_ENTITY_NODE:
7954 case XML_PI_NODE:
7955 case XML_COMMENT_NODE:
7956 case XML_NOTATION_NODE:
7957 case XML_DTD_NODE:
7958 case XML_ELEMENT_DECL:
7959 case XML_ATTRIBUTE_DECL:
7960 case XML_ENTITY_DECL:
7961 case XML_XINCLUDE_START:
7962 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007963 if (cur->parent == NULL)
7964 return(NULL);
7965 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007966 ((cur->parent->name[0] == ' ') ||
7967 (xmlStrEqual(cur->parent->name,
7968 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007969 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007970 return(cur->parent);
7971 case XML_ATTRIBUTE_NODE: {
7972 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7973
7974 return(att->parent);
7975 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007976 case XML_NAMESPACE_DECL: {
7977 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7978
7979 if ((ns->next != NULL) &&
7980 (ns->next->type != XML_NAMESPACE_DECL))
7981 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007982 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007983 return(NULL);
7984 }
Owen Taylor3473f882001-02-23 17:55:21 +00007985 case XML_DOCUMENT_NODE:
7986 case XML_DOCUMENT_TYPE_NODE:
7987 case XML_DOCUMENT_FRAG_NODE:
7988 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007989#ifdef LIBXML_DOCB_ENABLED
7990 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007991#endif
7992 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007993 }
7994 return(NULL);
7995}
7996
7997/**
7998 * xmlXPathNextAncestorOrSelf:
7999 * @ctxt: the XPath Parser context
8000 * @cur: the current node in the traversal
8001 *
8002 * Traversal function for the "ancestor-or-self" direction
8003 * he ancestor-or-self axis contains the context node and ancestors of
8004 * the context node in reverse document order; thus the context node is
8005 * the first node on the axis, and the context node's parent the second;
8006 * parent here is defined the same as with the parent axis.
8007 *
8008 * Returns the next element following that axis
8009 */
8010xmlNodePtr
8011xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008012 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008013 if (cur == NULL)
8014 return(ctxt->context->node);
8015 return(xmlXPathNextAncestor(ctxt, cur));
8016}
8017
8018/**
8019 * xmlXPathNextFollowingSibling:
8020 * @ctxt: the XPath Parser context
8021 * @cur: the current node in the traversal
8022 *
8023 * Traversal function for the "following-sibling" direction
8024 * The following-sibling axis contains the following siblings of the context
8025 * node in document order.
8026 *
8027 * Returns the next element following that axis
8028 */
8029xmlNodePtr
8030xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008031 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008032 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8033 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8034 return(NULL);
8035 if (cur == (xmlNodePtr) ctxt->context->doc)
8036 return(NULL);
8037 if (cur == NULL)
8038 return(ctxt->context->node->next);
8039 return(cur->next);
8040}
8041
8042/**
8043 * xmlXPathNextPrecedingSibling:
8044 * @ctxt: the XPath Parser context
8045 * @cur: the current node in the traversal
8046 *
8047 * Traversal function for the "preceding-sibling" direction
8048 * The preceding-sibling axis contains the preceding siblings of the context
8049 * node in reverse document order; the first preceding sibling is first on the
8050 * axis; the sibling preceding that node is the second on the axis and so on.
8051 *
8052 * Returns the next element following that axis
8053 */
8054xmlNodePtr
8055xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008056 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008057 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8058 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8059 return(NULL);
8060 if (cur == (xmlNodePtr) ctxt->context->doc)
8061 return(NULL);
8062 if (cur == NULL)
8063 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008064 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8065 cur = cur->prev;
8066 if (cur == NULL)
8067 return(ctxt->context->node->prev);
8068 }
Owen Taylor3473f882001-02-23 17:55:21 +00008069 return(cur->prev);
8070}
8071
8072/**
8073 * xmlXPathNextFollowing:
8074 * @ctxt: the XPath Parser context
8075 * @cur: the current node in the traversal
8076 *
8077 * Traversal function for the "following" direction
8078 * The following axis contains all nodes in the same document as the context
8079 * node that are after the context node in document order, excluding any
8080 * descendants and excluding attribute nodes and namespace nodes; the nodes
8081 * are ordered in document order
8082 *
8083 * Returns the next element following that axis
8084 */
8085xmlNodePtr
8086xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008087 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008088 if (cur != NULL && cur->children != NULL)
8089 return cur->children ;
8090 if (cur == NULL) cur = ctxt->context->node;
8091 if (cur == NULL) return(NULL) ; /* ERROR */
8092 if (cur->next != NULL) return(cur->next) ;
8093 do {
8094 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008095 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008096 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8097 if (cur->next != NULL) return(cur->next);
8098 } while (cur != NULL);
8099 return(cur);
8100}
8101
8102/*
8103 * xmlXPathIsAncestor:
8104 * @ancestor: the ancestor node
8105 * @node: the current node
8106 *
8107 * Check that @ancestor is a @node's ancestor
8108 *
8109 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8110 */
8111static int
8112xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8113 if ((ancestor == NULL) || (node == NULL)) return(0);
8114 /* nodes need to be in the same document */
8115 if (ancestor->doc != node->doc) return(0);
8116 /* avoid searching if ancestor or node is the root node */
8117 if (ancestor == (xmlNodePtr) node->doc) return(1);
8118 if (node == (xmlNodePtr) ancestor->doc) return(0);
8119 while (node->parent != NULL) {
8120 if (node->parent == ancestor)
8121 return(1);
8122 node = node->parent;
8123 }
8124 return(0);
8125}
8126
8127/**
8128 * xmlXPathNextPreceding:
8129 * @ctxt: the XPath Parser context
8130 * @cur: the current node in the traversal
8131 *
8132 * Traversal function for the "preceding" direction
8133 * the preceding axis contains all nodes in the same document as the context
8134 * node that are before the context node in document order, excluding any
8135 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8136 * ordered in reverse document order
8137 *
8138 * Returns the next element following that axis
8139 */
8140xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008141xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8142{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008143 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008144 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008145 cur = ctxt->context->node;
8146 if (cur == NULL)
8147 return (NULL);
8148 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8149 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008150 do {
8151 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008152 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8153 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008154 }
8155
8156 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008157 if (cur == NULL)
8158 return (NULL);
8159 if (cur == ctxt->context->doc->children)
8160 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008161 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008162 return (cur);
8163}
8164
8165/**
8166 * xmlXPathNextPrecedingInternal:
8167 * @ctxt: the XPath Parser context
8168 * @cur: the current node in the traversal
8169 *
8170 * Traversal function for the "preceding" direction
8171 * the preceding axis contains all nodes in the same document as the context
8172 * node that are before the context node in document order, excluding any
8173 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8174 * ordered in reverse document order
8175 * This is a faster implementation but internal only since it requires a
8176 * state kept in the parser context: ctxt->ancestor.
8177 *
8178 * Returns the next element following that axis
8179 */
8180static xmlNodePtr
8181xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8182 xmlNodePtr cur)
8183{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008184 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008185 if (cur == NULL) {
8186 cur = ctxt->context->node;
8187 if (cur == NULL)
8188 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008189 if (cur->type == XML_NAMESPACE_DECL)
8190 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008191 ctxt->ancestor = cur->parent;
8192 }
8193 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8194 cur = cur->prev;
8195 while (cur->prev == NULL) {
8196 cur = cur->parent;
8197 if (cur == NULL)
8198 return (NULL);
8199 if (cur == ctxt->context->doc->children)
8200 return (NULL);
8201 if (cur != ctxt->ancestor)
8202 return (cur);
8203 ctxt->ancestor = cur->parent;
8204 }
8205 cur = cur->prev;
8206 while (cur->last != NULL)
8207 cur = cur->last;
8208 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008209}
8210
8211/**
8212 * xmlXPathNextNamespace:
8213 * @ctxt: the XPath Parser context
8214 * @cur: the current attribute in the traversal
8215 *
8216 * Traversal function for the "namespace" direction
8217 * the namespace axis contains the namespace nodes of the context node;
8218 * the order of nodes on this axis is implementation-defined; the axis will
8219 * be empty unless the context node is an element
8220 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008221 * We keep the XML namespace node at the end of the list.
8222 *
Owen Taylor3473f882001-02-23 17:55:21 +00008223 * Returns the next element following that axis
8224 */
8225xmlNodePtr
8226xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008227 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008228 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008229 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008230 if (ctxt->context->tmpNsList != NULL)
8231 xmlFree(ctxt->context->tmpNsList);
8232 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008233 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008234 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008235 if (ctxt->context->tmpNsList != NULL) {
8236 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8237 ctxt->context->tmpNsNr++;
8238 }
8239 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008240 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008241 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008242 if (ctxt->context->tmpNsNr > 0) {
8243 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8244 } else {
8245 if (ctxt->context->tmpNsList != NULL)
8246 xmlFree(ctxt->context->tmpNsList);
8247 ctxt->context->tmpNsList = NULL;
8248 return(NULL);
8249 }
Owen Taylor3473f882001-02-23 17:55:21 +00008250}
8251
8252/**
8253 * xmlXPathNextAttribute:
8254 * @ctxt: the XPath Parser context
8255 * @cur: the current attribute in the traversal
8256 *
8257 * Traversal function for the "attribute" direction
8258 * TODO: support DTD inherited default attributes
8259 *
8260 * Returns the next element following that axis
8261 */
8262xmlNodePtr
8263xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008264 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008265 if (ctxt->context->node == NULL)
8266 return(NULL);
8267 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8268 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008269 if (cur == NULL) {
8270 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8271 return(NULL);
8272 return((xmlNodePtr)ctxt->context->node->properties);
8273 }
8274 return((xmlNodePtr)cur->next);
8275}
8276
8277/************************************************************************
8278 * *
8279 * NodeTest Functions *
8280 * *
8281 ************************************************************************/
8282
Owen Taylor3473f882001-02-23 17:55:21 +00008283#define IS_FUNCTION 200
8284
Owen Taylor3473f882001-02-23 17:55:21 +00008285
8286/************************************************************************
8287 * *
8288 * Implicit tree core function library *
8289 * *
8290 ************************************************************************/
8291
8292/**
8293 * xmlXPathRoot:
8294 * @ctxt: the XPath Parser context
8295 *
8296 * Initialize the context to the root of the document
8297 */
8298void
8299xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008300 if ((ctxt == NULL) || (ctxt->context == NULL))
8301 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008302 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008303 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8304 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008305}
8306
8307/************************************************************************
8308 * *
8309 * The explicit core function library *
8310 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8311 * *
8312 ************************************************************************/
8313
8314
8315/**
8316 * xmlXPathLastFunction:
8317 * @ctxt: the XPath Parser context
8318 * @nargs: the number of arguments
8319 *
8320 * Implement the last() XPath function
8321 * number last()
8322 * The last function returns the number of nodes in the context node list.
8323 */
8324void
8325xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8326 CHECK_ARITY(0);
8327 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008328 valuePush(ctxt,
8329 xmlXPathCacheNewFloat(ctxt->context,
8330 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008331#ifdef DEBUG_EXPR
8332 xmlGenericError(xmlGenericErrorContext,
8333 "last() : %d\n", ctxt->context->contextSize);
8334#endif
8335 } else {
8336 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8337 }
8338}
8339
8340/**
8341 * xmlXPathPositionFunction:
8342 * @ctxt: the XPath Parser context
8343 * @nargs: the number of arguments
8344 *
8345 * Implement the position() XPath function
8346 * number position()
8347 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008348 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008349 * will be equal to last().
8350 */
8351void
8352xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8353 CHECK_ARITY(0);
8354 if (ctxt->context->proximityPosition >= 0) {
8355 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008356 xmlXPathCacheNewFloat(ctxt->context,
8357 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008358#ifdef DEBUG_EXPR
8359 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8360 ctxt->context->proximityPosition);
8361#endif
8362 } else {
8363 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8364 }
8365}
8366
8367/**
8368 * xmlXPathCountFunction:
8369 * @ctxt: the XPath Parser context
8370 * @nargs: the number of arguments
8371 *
8372 * Implement the count() XPath function
8373 * number count(node-set)
8374 */
8375void
8376xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8377 xmlXPathObjectPtr cur;
8378
8379 CHECK_ARITY(1);
8380 if ((ctxt->value == NULL) ||
8381 ((ctxt->value->type != XPATH_NODESET) &&
8382 (ctxt->value->type != XPATH_XSLT_TREE)))
8383 XP_ERROR(XPATH_INVALID_TYPE);
8384 cur = valuePop(ctxt);
8385
Daniel Veillard911f49a2001-04-07 15:39:35 +00008386 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008387 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008388 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008389 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8390 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008391 } else {
8392 if ((cur->nodesetval->nodeNr != 1) ||
8393 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008394 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008395 } else {
8396 xmlNodePtr tmp;
8397 int i = 0;
8398
8399 tmp = cur->nodesetval->nodeTab[0];
8400 if (tmp != NULL) {
8401 tmp = tmp->children;
8402 while (tmp != NULL) {
8403 tmp = tmp->next;
8404 i++;
8405 }
8406 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008407 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008408 }
8409 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008410 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008411}
8412
8413/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008414 * xmlXPathGetElementsByIds:
8415 * @doc: the document
8416 * @ids: a whitespace separated list of IDs
8417 *
8418 * Selects elements by their unique ID.
8419 *
8420 * Returns a node-set of selected elements.
8421 */
8422static xmlNodeSetPtr
8423xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8424 xmlNodeSetPtr ret;
8425 const xmlChar *cur = ids;
8426 xmlChar *ID;
8427 xmlAttrPtr attr;
8428 xmlNodePtr elem = NULL;
8429
Daniel Veillard7a985a12003-07-06 17:57:42 +00008430 if (ids == NULL) return(NULL);
8431
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008432 ret = xmlXPathNodeSetCreate(NULL);
8433
William M. Brack76e95df2003-10-18 16:20:14 +00008434 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008435 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008436 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008437 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008438
8439 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008440 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008441 /*
8442 * We used to check the fact that the value passed
8443 * was an NCName, but this generated much troubles for
8444 * me and Aleksey Sanin, people blatantly violated that
8445 * constaint, like Visa3D spec.
8446 * if (xmlValidateNCName(ID, 1) == 0)
8447 */
8448 attr = xmlGetID(doc, ID);
8449 if (attr != NULL) {
8450 if (attr->type == XML_ATTRIBUTE_NODE)
8451 elem = attr->parent;
8452 else if (attr->type == XML_ELEMENT_NODE)
8453 elem = (xmlNodePtr) attr;
8454 else
8455 elem = NULL;
8456 if (elem != NULL)
8457 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008458 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008459 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008460 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008461
William M. Brack76e95df2003-10-18 16:20:14 +00008462 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008463 ids = cur;
8464 }
8465 return(ret);
8466}
8467
8468/**
Owen Taylor3473f882001-02-23 17:55:21 +00008469 * xmlXPathIdFunction:
8470 * @ctxt: the XPath Parser context
8471 * @nargs: the number of arguments
8472 *
8473 * Implement the id() XPath function
8474 * node-set id(object)
8475 * The id function selects elements by their unique ID
8476 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8477 * then the result is the union of the result of applying id to the
8478 * string value of each of the nodes in the argument node-set. When the
8479 * argument to id is of any other type, the argument is converted to a
8480 * string as if by a call to the string function; the string is split
8481 * into a whitespace-separated list of tokens (whitespace is any sequence
8482 * of characters matching the production S); the result is a node-set
8483 * containing the elements in the same document as the context node that
8484 * have a unique ID equal to any of the tokens in the list.
8485 */
8486void
8487xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008488 xmlChar *tokens;
8489 xmlNodeSetPtr ret;
8490 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008491
8492 CHECK_ARITY(1);
8493 obj = valuePop(ctxt);
8494 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008495 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008496 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008497 int i;
8498
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008499 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008500
Daniel Veillard911f49a2001-04-07 15:39:35 +00008501 if (obj->nodesetval != NULL) {
8502 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008503 tokens =
8504 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8505 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8506 ret = xmlXPathNodeSetMerge(ret, ns);
8507 xmlXPathFreeNodeSet(ns);
8508 if (tokens != NULL)
8509 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008510 }
Owen Taylor3473f882001-02-23 17:55:21 +00008511 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008512 xmlXPathReleaseObject(ctxt->context, obj);
8513 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008514 return;
8515 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008516 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008517 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008518 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8519 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008520 return;
8521}
8522
8523/**
8524 * xmlXPathLocalNameFunction:
8525 * @ctxt: the XPath Parser context
8526 * @nargs: the number of arguments
8527 *
8528 * Implement the local-name() XPath function
8529 * string local-name(node-set?)
8530 * The local-name function returns a string containing the local part
8531 * of the name of the node in the argument node-set that is first in
8532 * document order. If the node-set is empty or the first node has no
8533 * name, an empty string is returned. If the argument is omitted it
8534 * defaults to the context node.
8535 */
8536void
8537xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538 xmlXPathObjectPtr cur;
8539
Daniel Veillarda82b1822004-11-08 16:24:57 +00008540 if (ctxt == NULL) return;
8541
Owen Taylor3473f882001-02-23 17:55:21 +00008542 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008543 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8544 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008545 nargs = 1;
8546 }
8547
8548 CHECK_ARITY(1);
8549 if ((ctxt->value == NULL) ||
8550 ((ctxt->value->type != XPATH_NODESET) &&
8551 (ctxt->value->type != XPATH_XSLT_TREE)))
8552 XP_ERROR(XPATH_INVALID_TYPE);
8553 cur = valuePop(ctxt);
8554
Daniel Veillard911f49a2001-04-07 15:39:35 +00008555 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008556 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008557 } else {
8558 int i = 0; /* Should be first in document order !!!!! */
8559 switch (cur->nodesetval->nodeTab[i]->type) {
8560 case XML_ELEMENT_NODE:
8561 case XML_ATTRIBUTE_NODE:
8562 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008563 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008564 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008565 else
8566 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008567 xmlXPathCacheNewString(ctxt->context,
8568 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008569 break;
8570 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008571 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008572 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8573 break;
8574 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008575 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008576 }
8577 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008578 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008579}
8580
8581/**
8582 * xmlXPathNamespaceURIFunction:
8583 * @ctxt: the XPath Parser context
8584 * @nargs: the number of arguments
8585 *
8586 * Implement the namespace-uri() XPath function
8587 * string namespace-uri(node-set?)
8588 * The namespace-uri function returns a string containing the
8589 * namespace URI of the expanded name of the node in the argument
8590 * node-set that is first in document order. If the node-set is empty,
8591 * the first node has no name, or the expanded name has no namespace
8592 * URI, an empty string is returned. If the argument is omitted it
8593 * defaults to the context node.
8594 */
8595void
8596xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8597 xmlXPathObjectPtr cur;
8598
Daniel Veillarda82b1822004-11-08 16:24:57 +00008599 if (ctxt == NULL) return;
8600
Owen Taylor3473f882001-02-23 17:55:21 +00008601 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008602 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8603 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008604 nargs = 1;
8605 }
8606 CHECK_ARITY(1);
8607 if ((ctxt->value == NULL) ||
8608 ((ctxt->value->type != XPATH_NODESET) &&
8609 (ctxt->value->type != XPATH_XSLT_TREE)))
8610 XP_ERROR(XPATH_INVALID_TYPE);
8611 cur = valuePop(ctxt);
8612
Daniel Veillard911f49a2001-04-07 15:39:35 +00008613 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008614 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008615 } else {
8616 int i = 0; /* Should be first in document order !!!!! */
8617 switch (cur->nodesetval->nodeTab[i]->type) {
8618 case XML_ELEMENT_NODE:
8619 case XML_ATTRIBUTE_NODE:
8620 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008621 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008622 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008623 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008624 cur->nodesetval->nodeTab[i]->ns->href));
8625 break;
8626 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008627 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008628 }
8629 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008630 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008631}
8632
8633/**
8634 * xmlXPathNameFunction:
8635 * @ctxt: the XPath Parser context
8636 * @nargs: the number of arguments
8637 *
8638 * Implement the name() XPath function
8639 * string name(node-set?)
8640 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008641 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008642 * order. The QName must represent the name with respect to the namespace
8643 * declarations in effect on the node whose name is being represented.
8644 * Typically, this will be the form in which the name occurred in the XML
8645 * source. This need not be the case if there are namespace declarations
8646 * in effect on the node that associate multiple prefixes with the same
8647 * namespace. However, an implementation may include information about
8648 * the original prefix in its representation of nodes; in this case, an
8649 * implementation can ensure that the returned string is always the same
8650 * as the QName used in the XML source. If the argument it omitted it
8651 * defaults to the context node.
8652 * Libxml keep the original prefix so the "real qualified name" used is
8653 * returned.
8654 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008655static void
Daniel Veillard04383752001-07-08 14:27:15 +00008656xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8657{
Owen Taylor3473f882001-02-23 17:55:21 +00008658 xmlXPathObjectPtr cur;
8659
8660 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008661 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8662 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008663 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008664 }
8665
8666 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008667 if ((ctxt->value == NULL) ||
8668 ((ctxt->value->type != XPATH_NODESET) &&
8669 (ctxt->value->type != XPATH_XSLT_TREE)))
8670 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008671 cur = valuePop(ctxt);
8672
Daniel Veillard911f49a2001-04-07 15:39:35 +00008673 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008674 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008675 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008676 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008677
Daniel Veillard04383752001-07-08 14:27:15 +00008678 switch (cur->nodesetval->nodeTab[i]->type) {
8679 case XML_ELEMENT_NODE:
8680 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008681 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008682 valuePush(ctxt,
8683 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008684 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8685 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008686 valuePush(ctxt,
8687 xmlXPathCacheNewString(ctxt->context,
8688 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008689 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008690 xmlChar *fullname;
8691
8692 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8693 cur->nodesetval->nodeTab[i]->ns->prefix,
8694 NULL, 0);
8695 if (fullname == cur->nodesetval->nodeTab[i]->name)
8696 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8697 if (fullname == NULL) {
8698 XP_ERROR(XPATH_MEMORY_ERROR);
8699 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008700 valuePush(ctxt, xmlXPathCacheWrapString(
8701 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008702 }
8703 break;
8704 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008705 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8706 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008707 xmlXPathLocalNameFunction(ctxt, 1);
8708 }
Owen Taylor3473f882001-02-23 17:55:21 +00008709 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008710 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008711}
8712
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008713
8714/**
Owen Taylor3473f882001-02-23 17:55:21 +00008715 * xmlXPathStringFunction:
8716 * @ctxt: the XPath Parser context
8717 * @nargs: the number of arguments
8718 *
8719 * Implement the string() XPath function
8720 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008721 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008722 * - A node-set is converted to a string by returning the value of
8723 * the node in the node-set that is first in document order.
8724 * If the node-set is empty, an empty string is returned.
8725 * - A number is converted to a string as follows
8726 * + NaN is converted to the string NaN
8727 * + positive zero is converted to the string 0
8728 * + negative zero is converted to the string 0
8729 * + positive infinity is converted to the string Infinity
8730 * + negative infinity is converted to the string -Infinity
8731 * + if the number is an integer, the number is represented in
8732 * decimal form as a Number with no decimal point and no leading
8733 * zeros, preceded by a minus sign (-) if the number is negative
8734 * + otherwise, the number is represented in decimal form as a
8735 * Number including a decimal point with at least one digit
8736 * before the decimal point and at least one digit after the
8737 * decimal point, preceded by a minus sign (-) if the number
8738 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008739 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008740 * before the decimal point; beyond the one required digit
8741 * after the decimal point there must be as many, but only as
8742 * many, more digits as are needed to uniquely distinguish the
8743 * number from all other IEEE 754 numeric values.
8744 * - The boolean false value is converted to the string false.
8745 * The boolean true value is converted to the string true.
8746 *
8747 * If the argument is omitted, it defaults to a node-set with the
8748 * context node as its only member.
8749 */
8750void
8751xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8752 xmlXPathObjectPtr cur;
8753
Daniel Veillarda82b1822004-11-08 16:24:57 +00008754 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008755 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008756 valuePush(ctxt,
8757 xmlXPathCacheWrapString(ctxt->context,
8758 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008759 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008760 }
8761
8762 CHECK_ARITY(1);
8763 cur = valuePop(ctxt);
8764 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008765 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008766}
8767
8768/**
8769 * xmlXPathStringLengthFunction:
8770 * @ctxt: the XPath Parser context
8771 * @nargs: the number of arguments
8772 *
8773 * Implement the string-length() XPath function
8774 * number string-length(string?)
8775 * The string-length returns the number of characters in the string
8776 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8777 * the context node converted to a string, in other words the value
8778 * of the context node.
8779 */
8780void
8781xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8782 xmlXPathObjectPtr cur;
8783
8784 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008785 if ((ctxt == NULL) || (ctxt->context == NULL))
8786 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008787 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008788 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008789 } else {
8790 xmlChar *content;
8791
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008792 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008793 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8794 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008795 xmlFree(content);
8796 }
8797 return;
8798 }
8799 CHECK_ARITY(1);
8800 CAST_TO_STRING;
8801 CHECK_TYPE(XPATH_STRING);
8802 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008803 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8804 xmlUTF8Strlen(cur->stringval)));
8805 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008806}
8807
8808/**
8809 * xmlXPathConcatFunction:
8810 * @ctxt: the XPath Parser context
8811 * @nargs: the number of arguments
8812 *
8813 * Implement the concat() XPath function
8814 * string concat(string, string, string*)
8815 * The concat function returns the concatenation of its arguments.
8816 */
8817void
8818xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8819 xmlXPathObjectPtr cur, newobj;
8820 xmlChar *tmp;
8821
Daniel Veillarda82b1822004-11-08 16:24:57 +00008822 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008823 if (nargs < 2) {
8824 CHECK_ARITY(2);
8825 }
8826
8827 CAST_TO_STRING;
8828 cur = valuePop(ctxt);
8829 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008830 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008831 return;
8832 }
8833 nargs--;
8834
8835 while (nargs > 0) {
8836 CAST_TO_STRING;
8837 newobj = valuePop(ctxt);
8838 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008839 xmlXPathReleaseObject(ctxt->context, newobj);
8840 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008841 XP_ERROR(XPATH_INVALID_TYPE);
8842 }
8843 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8844 newobj->stringval = cur->stringval;
8845 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008846 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008847 nargs--;
8848 }
8849 valuePush(ctxt, cur);
8850}
8851
8852/**
8853 * xmlXPathContainsFunction:
8854 * @ctxt: the XPath Parser context
8855 * @nargs: the number of arguments
8856 *
8857 * Implement the contains() XPath function
8858 * boolean contains(string, string)
8859 * The contains function returns true if the first argument string
8860 * contains the second argument string, and otherwise returns false.
8861 */
8862void
8863xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8864 xmlXPathObjectPtr hay, needle;
8865
8866 CHECK_ARITY(2);
8867 CAST_TO_STRING;
8868 CHECK_TYPE(XPATH_STRING);
8869 needle = valuePop(ctxt);
8870 CAST_TO_STRING;
8871 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008872
Owen Taylor3473f882001-02-23 17:55:21 +00008873 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008874 xmlXPathReleaseObject(ctxt->context, hay);
8875 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008876 XP_ERROR(XPATH_INVALID_TYPE);
8877 }
8878 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008879 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008880 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008881 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8882 xmlXPathReleaseObject(ctxt->context, hay);
8883 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008884}
8885
8886/**
8887 * xmlXPathStartsWithFunction:
8888 * @ctxt: the XPath Parser context
8889 * @nargs: the number of arguments
8890 *
8891 * Implement the starts-with() XPath function
8892 * boolean starts-with(string, string)
8893 * The starts-with function returns true if the first argument string
8894 * starts with the second argument string, and otherwise returns false.
8895 */
8896void
8897xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8898 xmlXPathObjectPtr hay, needle;
8899 int n;
8900
8901 CHECK_ARITY(2);
8902 CAST_TO_STRING;
8903 CHECK_TYPE(XPATH_STRING);
8904 needle = valuePop(ctxt);
8905 CAST_TO_STRING;
8906 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008907
Owen Taylor3473f882001-02-23 17:55:21 +00008908 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008909 xmlXPathReleaseObject(ctxt->context, hay);
8910 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008911 XP_ERROR(XPATH_INVALID_TYPE);
8912 }
8913 n = xmlStrlen(needle->stringval);
8914 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008915 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008916 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008917 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8918 xmlXPathReleaseObject(ctxt->context, hay);
8919 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008920}
8921
8922/**
8923 * xmlXPathSubstringFunction:
8924 * @ctxt: the XPath Parser context
8925 * @nargs: the number of arguments
8926 *
8927 * Implement the substring() XPath function
8928 * string substring(string, number, number?)
8929 * The substring function returns the substring of the first argument
8930 * starting at the position specified in the second argument with
8931 * length specified in the third argument. For example,
8932 * substring("12345",2,3) returns "234". If the third argument is not
8933 * specified, it returns the substring starting at the position specified
8934 * in the second argument and continuing to the end of the string. For
8935 * example, substring("12345",2) returns "2345". More precisely, each
8936 * character in the string (see [3.6 Strings]) is considered to have a
8937 * numeric position: the position of the first character is 1, the position
8938 * of the second character is 2 and so on. The returned substring contains
8939 * those characters for which the position of the character is greater than
8940 * or equal to the second argument and, if the third argument is specified,
8941 * less than the sum of the second and third arguments; the comparisons
8942 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8943 * - substring("12345", 1.5, 2.6) returns "234"
8944 * - substring("12345", 0, 3) returns "12"
8945 * - substring("12345", 0 div 0, 3) returns ""
8946 * - substring("12345", 1, 0 div 0) returns ""
8947 * - substring("12345", -42, 1 div 0) returns "12345"
8948 * - substring("12345", -1 div 0, 1 div 0) returns ""
8949 */
8950void
8951xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8952 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008953 double le=0, in;
8954 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008955 xmlChar *ret;
8956
Owen Taylor3473f882001-02-23 17:55:21 +00008957 if (nargs < 2) {
8958 CHECK_ARITY(2);
8959 }
8960 if (nargs > 3) {
8961 CHECK_ARITY(3);
8962 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008963 /*
8964 * take care of possible last (position) argument
8965 */
Owen Taylor3473f882001-02-23 17:55:21 +00008966 if (nargs == 3) {
8967 CAST_TO_NUMBER;
8968 CHECK_TYPE(XPATH_NUMBER);
8969 len = valuePop(ctxt);
8970 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008971 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008972 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008973
Owen Taylor3473f882001-02-23 17:55:21 +00008974 CAST_TO_NUMBER;
8975 CHECK_TYPE(XPATH_NUMBER);
8976 start = valuePop(ctxt);
8977 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008978 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008979 CAST_TO_STRING;
8980 CHECK_TYPE(XPATH_STRING);
8981 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008982 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008983
Daniel Veillard97ac1312001-05-30 19:14:17 +00008984 /*
8985 * If last pos not present, calculate last position
8986 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008987 if (nargs != 3) {
8988 le = (double)m;
8989 if (in < 1.0)
8990 in = 1.0;
8991 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008992
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008993 /* Need to check for the special cases where either
8994 * the index is NaN, the length is NaN, or both
8995 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008996 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008997 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008998 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008999 * To meet the requirements of the spec, the arguments
9000 * must be converted to integer format before
9001 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009002 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009003 * First we go to integer form, rounding up
9004 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009005 */
9006 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009007 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009008
Daniel Veillard9e412302002-06-10 15:59:44 +00009009 if (xmlXPathIsInf(le) == 1) {
9010 l = m;
9011 if (i < 1)
9012 i = 1;
9013 }
9014 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9015 l = 0;
9016 else {
9017 l = (int) le;
9018 if (((double)l)+0.5 <= le) l++;
9019 }
9020
9021 /* Now we normalize inidices */
9022 i -= 1;
9023 l += i;
9024 if (i < 0)
9025 i = 0;
9026 if (l > m)
9027 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009028
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009029 /* number of chars to copy */
9030 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009031
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009032 ret = xmlUTF8Strsub(str->stringval, i, l);
9033 }
9034 else {
9035 ret = NULL;
9036 }
Owen Taylor3473f882001-02-23 17:55:21 +00009037 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009038 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009039 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009040 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009041 xmlFree(ret);
9042 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009043 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009044}
9045
9046/**
9047 * xmlXPathSubstringBeforeFunction:
9048 * @ctxt: the XPath Parser context
9049 * @nargs: the number of arguments
9050 *
9051 * Implement the substring-before() XPath function
9052 * string substring-before(string, string)
9053 * The substring-before function returns the substring of the first
9054 * argument string that precedes the first occurrence of the second
9055 * argument string in the first argument string, or the empty string
9056 * if the first argument string does not contain the second argument
9057 * string. For example, substring-before("1999/04/01","/") returns 1999.
9058 */
9059void
9060xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9061 xmlXPathObjectPtr str;
9062 xmlXPathObjectPtr find;
9063 xmlBufferPtr target;
9064 const xmlChar *point;
9065 int offset;
9066
9067 CHECK_ARITY(2);
9068 CAST_TO_STRING;
9069 find = valuePop(ctxt);
9070 CAST_TO_STRING;
9071 str = valuePop(ctxt);
9072
9073 target = xmlBufferCreate();
9074 if (target) {
9075 point = xmlStrstr(str->stringval, find->stringval);
9076 if (point) {
9077 offset = (int)(point - str->stringval);
9078 xmlBufferAdd(target, str->stringval, offset);
9079 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009080 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9081 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009082 xmlBufferFree(target);
9083 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009084 xmlXPathReleaseObject(ctxt->context, str);
9085 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009086}
9087
9088/**
9089 * xmlXPathSubstringAfterFunction:
9090 * @ctxt: the XPath Parser context
9091 * @nargs: the number of arguments
9092 *
9093 * Implement the substring-after() XPath function
9094 * string substring-after(string, string)
9095 * The substring-after function returns the substring of the first
9096 * argument string that follows the first occurrence of the second
9097 * argument string in the first argument string, or the empty stringi
9098 * if the first argument string does not contain the second argument
9099 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9100 * and substring-after("1999/04/01","19") returns 99/04/01.
9101 */
9102void
9103xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9104 xmlXPathObjectPtr str;
9105 xmlXPathObjectPtr find;
9106 xmlBufferPtr target;
9107 const xmlChar *point;
9108 int offset;
9109
9110 CHECK_ARITY(2);
9111 CAST_TO_STRING;
9112 find = valuePop(ctxt);
9113 CAST_TO_STRING;
9114 str = valuePop(ctxt);
9115
9116 target = xmlBufferCreate();
9117 if (target) {
9118 point = xmlStrstr(str->stringval, find->stringval);
9119 if (point) {
9120 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9121 xmlBufferAdd(target, &str->stringval[offset],
9122 xmlStrlen(str->stringval) - offset);
9123 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009124 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9125 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009126 xmlBufferFree(target);
9127 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009128 xmlXPathReleaseObject(ctxt->context, str);
9129 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009130}
9131
9132/**
9133 * xmlXPathNormalizeFunction:
9134 * @ctxt: the XPath Parser context
9135 * @nargs: the number of arguments
9136 *
9137 * Implement the normalize-space() XPath function
9138 * string normalize-space(string?)
9139 * The normalize-space function returns the argument string with white
9140 * space normalized by stripping leading and trailing whitespace
9141 * and replacing sequences of whitespace characters by a single
9142 * space. Whitespace characters are the same allowed by the S production
9143 * in XML. If the argument is omitted, it defaults to the context
9144 * node converted to a string, in other words the value of the context node.
9145 */
9146void
9147xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9148 xmlXPathObjectPtr obj = NULL;
9149 xmlChar *source = NULL;
9150 xmlBufferPtr target;
9151 xmlChar blank;
9152
Daniel Veillarda82b1822004-11-08 16:24:57 +00009153 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009154 if (nargs == 0) {
9155 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009156 valuePush(ctxt,
9157 xmlXPathCacheWrapString(ctxt->context,
9158 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009159 nargs = 1;
9160 }
9161
9162 CHECK_ARITY(1);
9163 CAST_TO_STRING;
9164 CHECK_TYPE(XPATH_STRING);
9165 obj = valuePop(ctxt);
9166 source = obj->stringval;
9167
9168 target = xmlBufferCreate();
9169 if (target && source) {
9170
9171 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009172 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009173 source++;
9174
9175 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9176 blank = 0;
9177 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009178 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009179 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009180 } else {
9181 if (blank) {
9182 xmlBufferAdd(target, &blank, 1);
9183 blank = 0;
9184 }
9185 xmlBufferAdd(target, source, 1);
9186 }
9187 source++;
9188 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009189 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9190 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009191 xmlBufferFree(target);
9192 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009193 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009194}
9195
9196/**
9197 * xmlXPathTranslateFunction:
9198 * @ctxt: the XPath Parser context
9199 * @nargs: the number of arguments
9200 *
9201 * Implement the translate() XPath function
9202 * string translate(string, string, string)
9203 * The translate function returns the first argument string with
9204 * occurrences of characters in the second argument string replaced
9205 * by the character at the corresponding position in the third argument
9206 * string. For example, translate("bar","abc","ABC") returns the string
9207 * BAr. If there is a character in the second argument string with no
9208 * character at a corresponding position in the third argument string
9209 * (because the second argument string is longer than the third argument
9210 * string), then occurrences of that character in the first argument
9211 * string are removed. For example, translate("--aaa--","abc-","ABC")
9212 * returns "AAA". If a character occurs more than once in second
9213 * argument string, then the first occurrence determines the replacement
9214 * character. If the third argument string is longer than the second
9215 * argument string, then excess characters are ignored.
9216 */
9217void
9218xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009219 xmlXPathObjectPtr str;
9220 xmlXPathObjectPtr from;
9221 xmlXPathObjectPtr to;
9222 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009223 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009224 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009225 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009226 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009227
Daniel Veillarde043ee12001-04-16 14:08:07 +00009228 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009229
Daniel Veillarde043ee12001-04-16 14:08:07 +00009230 CAST_TO_STRING;
9231 to = valuePop(ctxt);
9232 CAST_TO_STRING;
9233 from = valuePop(ctxt);
9234 CAST_TO_STRING;
9235 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009236
Daniel Veillarde043ee12001-04-16 14:08:07 +00009237 target = xmlBufferCreate();
9238 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009239 max = xmlUTF8Strlen(to->stringval);
9240 for (cptr = str->stringval; (ch=*cptr); ) {
9241 offset = xmlUTF8Strloc(from->stringval, cptr);
9242 if (offset >= 0) {
9243 if (offset < max) {
9244 point = xmlUTF8Strpos(to->stringval, offset);
9245 if (point)
9246 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9247 }
9248 } else
9249 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9250
9251 /* Step to next character in input */
9252 cptr++;
9253 if ( ch & 0x80 ) {
9254 /* if not simple ascii, verify proper format */
9255 if ( (ch & 0xc0) != 0xc0 ) {
9256 xmlGenericError(xmlGenericErrorContext,
9257 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9258 break;
9259 }
9260 /* then skip over remaining bytes for this char */
9261 while ( (ch <<= 1) & 0x80 )
9262 if ( (*cptr++ & 0xc0) != 0x80 ) {
9263 xmlGenericError(xmlGenericErrorContext,
9264 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9265 break;
9266 }
9267 if (ch & 0x80) /* must have had error encountered */
9268 break;
9269 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009270 }
Owen Taylor3473f882001-02-23 17:55:21 +00009271 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009272 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9273 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009274 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009275 xmlXPathReleaseObject(ctxt->context, str);
9276 xmlXPathReleaseObject(ctxt->context, from);
9277 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009278}
9279
9280/**
9281 * xmlXPathBooleanFunction:
9282 * @ctxt: the XPath Parser context
9283 * @nargs: the number of arguments
9284 *
9285 * Implement the boolean() XPath function
9286 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009287 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009288 * - a number is true if and only if it is neither positive or
9289 * negative zero nor NaN
9290 * - a node-set is true if and only if it is non-empty
9291 * - a string is true if and only if its length is non-zero
9292 */
9293void
9294xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9295 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009296
9297 CHECK_ARITY(1);
9298 cur = valuePop(ctxt);
9299 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009300 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009301 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009302}
9303
9304/**
9305 * xmlXPathNotFunction:
9306 * @ctxt: the XPath Parser context
9307 * @nargs: the number of arguments
9308 *
9309 * Implement the not() XPath function
9310 * boolean not(boolean)
9311 * The not function returns true if its argument is false,
9312 * and false otherwise.
9313 */
9314void
9315xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9316 CHECK_ARITY(1);
9317 CAST_TO_BOOLEAN;
9318 CHECK_TYPE(XPATH_BOOLEAN);
9319 ctxt->value->boolval = ! ctxt->value->boolval;
9320}
9321
9322/**
9323 * xmlXPathTrueFunction:
9324 * @ctxt: the XPath Parser context
9325 * @nargs: the number of arguments
9326 *
9327 * Implement the true() XPath function
9328 * boolean true()
9329 */
9330void
9331xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9332 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009333 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009334}
9335
9336/**
9337 * xmlXPathFalseFunction:
9338 * @ctxt: the XPath Parser context
9339 * @nargs: the number of arguments
9340 *
9341 * Implement the false() XPath function
9342 * boolean false()
9343 */
9344void
9345xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9346 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009347 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009348}
9349
9350/**
9351 * xmlXPathLangFunction:
9352 * @ctxt: the XPath Parser context
9353 * @nargs: the number of arguments
9354 *
9355 * Implement the lang() XPath function
9356 * boolean lang(string)
9357 * The lang function returns true or false depending on whether the
9358 * language of the context node as specified by xml:lang attributes
9359 * is the same as or is a sublanguage of the language specified by
9360 * the argument string. The language of the context node is determined
9361 * by the value of the xml:lang attribute on the context node, or, if
9362 * the context node has no xml:lang attribute, by the value of the
9363 * xml:lang attribute on the nearest ancestor of the context node that
9364 * has an xml:lang attribute. If there is no such attribute, then lang
9365 * returns false. If there is such an attribute, then lang returns
9366 * true if the attribute value is equal to the argument ignoring case,
9367 * or if there is some suffix starting with - such that the attribute
9368 * value is equal to the argument ignoring that suffix of the attribute
9369 * value and ignoring case.
9370 */
9371void
9372xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009373 xmlXPathObjectPtr val = NULL;
9374 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009375 const xmlChar *lang;
9376 int ret = 0;
9377 int i;
9378
9379 CHECK_ARITY(1);
9380 CAST_TO_STRING;
9381 CHECK_TYPE(XPATH_STRING);
9382 val = valuePop(ctxt);
9383 lang = val->stringval;
9384 theLang = xmlNodeGetLang(ctxt->context->node);
9385 if ((theLang != NULL) && (lang != NULL)) {
9386 for (i = 0;lang[i] != 0;i++)
9387 if (toupper(lang[i]) != toupper(theLang[i]))
9388 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009389 if ((theLang[i] == 0) || (theLang[i] == '-'))
9390 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009391 }
9392not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009393 if (theLang != NULL)
9394 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009395
9396 xmlXPathReleaseObject(ctxt->context, val);
9397 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009398}
9399
9400/**
9401 * xmlXPathNumberFunction:
9402 * @ctxt: the XPath Parser context
9403 * @nargs: the number of arguments
9404 *
9405 * Implement the number() XPath function
9406 * number number(object?)
9407 */
9408void
9409xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9410 xmlXPathObjectPtr cur;
9411 double res;
9412
Daniel Veillarda82b1822004-11-08 16:24:57 +00009413 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009414 if (nargs == 0) {
9415 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009416 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009417 } else {
9418 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9419
9420 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009421 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009422 xmlFree(content);
9423 }
9424 return;
9425 }
9426
9427 CHECK_ARITY(1);
9428 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009429 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009430}
9431
9432/**
9433 * xmlXPathSumFunction:
9434 * @ctxt: the XPath Parser context
9435 * @nargs: the number of arguments
9436 *
9437 * Implement the sum() XPath function
9438 * number sum(node-set)
9439 * The sum function returns the sum of the values of the nodes in
9440 * the argument node-set.
9441 */
9442void
9443xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9444 xmlXPathObjectPtr cur;
9445 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009446 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009447
9448 CHECK_ARITY(1);
9449 if ((ctxt->value == NULL) ||
9450 ((ctxt->value->type != XPATH_NODESET) &&
9451 (ctxt->value->type != XPATH_XSLT_TREE)))
9452 XP_ERROR(XPATH_INVALID_TYPE);
9453 cur = valuePop(ctxt);
9454
William M. Brack08171912003-12-29 02:52:11 +00009455 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009456 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9457 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009458 }
9459 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009460 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9461 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009462}
9463
William M. Brack3d426662005-04-19 14:40:28 +00009464/*
9465 * To assure working code on multiple platforms, we want to only depend
9466 * upon the characteristic truncation of converting a floating point value
9467 * to an integer. Unfortunately, because of the different storage sizes
9468 * of our internal floating point value (double) and integer (int), we
9469 * can't directly convert (see bug 301162). This macro is a messy
9470 * 'workaround'
9471 */
9472#define XTRUNC(f, v) \
9473 f = fmod((v), INT_MAX); \
9474 f = (v) - (f) + (double)((int)(f));
9475
Owen Taylor3473f882001-02-23 17:55:21 +00009476/**
9477 * xmlXPathFloorFunction:
9478 * @ctxt: the XPath Parser context
9479 * @nargs: the number of arguments
9480 *
9481 * Implement the floor() XPath function
9482 * number floor(number)
9483 * The floor function returns the largest (closest to positive infinity)
9484 * number that is not greater than the argument and that is an integer.
9485 */
9486void
9487xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009488 double f;
9489
Owen Taylor3473f882001-02-23 17:55:21 +00009490 CHECK_ARITY(1);
9491 CAST_TO_NUMBER;
9492 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009493
William M. Brack3d426662005-04-19 14:40:28 +00009494 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009495 if (f != ctxt->value->floatval) {
9496 if (ctxt->value->floatval > 0)
9497 ctxt->value->floatval = f;
9498 else
9499 ctxt->value->floatval = f - 1;
9500 }
Owen Taylor3473f882001-02-23 17:55:21 +00009501}
9502
9503/**
9504 * xmlXPathCeilingFunction:
9505 * @ctxt: the XPath Parser context
9506 * @nargs: the number of arguments
9507 *
9508 * Implement the ceiling() XPath function
9509 * number ceiling(number)
9510 * The ceiling function returns the smallest (closest to negative infinity)
9511 * number that is not less than the argument and that is an integer.
9512 */
9513void
9514xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9515 double f;
9516
9517 CHECK_ARITY(1);
9518 CAST_TO_NUMBER;
9519 CHECK_TYPE(XPATH_NUMBER);
9520
9521#if 0
9522 ctxt->value->floatval = ceil(ctxt->value->floatval);
9523#else
William M. Brack3d426662005-04-19 14:40:28 +00009524 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009525 if (f != ctxt->value->floatval) {
9526 if (ctxt->value->floatval > 0)
9527 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009528 else {
9529 if (ctxt->value->floatval < 0 && f == 0)
9530 ctxt->value->floatval = xmlXPathNZERO;
9531 else
9532 ctxt->value->floatval = f;
9533 }
9534
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009535 }
Owen Taylor3473f882001-02-23 17:55:21 +00009536#endif
9537}
9538
9539/**
9540 * xmlXPathRoundFunction:
9541 * @ctxt: the XPath Parser context
9542 * @nargs: the number of arguments
9543 *
9544 * Implement the round() XPath function
9545 * number round(number)
9546 * The round function returns the number that is closest to the
9547 * argument and that is an integer. If there are two such numbers,
9548 * then the one that is even is returned.
9549 */
9550void
9551xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9552 double f;
9553
9554 CHECK_ARITY(1);
9555 CAST_TO_NUMBER;
9556 CHECK_TYPE(XPATH_NUMBER);
9557
Daniel Veillardcda96922001-08-21 10:56:31 +00009558 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9559 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9560 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009561 (ctxt->value->floatval == 0.0))
9562 return;
9563
William M. Brack3d426662005-04-19 14:40:28 +00009564 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009565 if (ctxt->value->floatval < 0) {
9566 if (ctxt->value->floatval < f - 0.5)
9567 ctxt->value->floatval = f - 1;
9568 else
9569 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009570 if (ctxt->value->floatval == 0)
9571 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009572 } else {
9573 if (ctxt->value->floatval < f + 0.5)
9574 ctxt->value->floatval = f;
9575 else
9576 ctxt->value->floatval = f + 1;
9577 }
Owen Taylor3473f882001-02-23 17:55:21 +00009578}
9579
9580/************************************************************************
9581 * *
9582 * The Parser *
9583 * *
9584 ************************************************************************/
9585
9586/*
William M. Brack08171912003-12-29 02:52:11 +00009587 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009588 * implementation.
9589 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009590static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009591static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009592static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009593static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009594static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9595 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009596
9597/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009598 * xmlXPathCurrentChar:
9599 * @ctxt: the XPath parser context
9600 * @cur: pointer to the beginning of the char
9601 * @len: pointer to the length of the char read
9602 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009603 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009604 * bytes in the input buffer.
9605 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009606 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009607 */
9608
9609static int
9610xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9611 unsigned char c;
9612 unsigned int val;
9613 const xmlChar *cur;
9614
9615 if (ctxt == NULL)
9616 return(0);
9617 cur = ctxt->cur;
9618
9619 /*
9620 * We are supposed to handle UTF8, check it's valid
9621 * From rfc2044: encoding of the Unicode values on UTF-8:
9622 *
9623 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9624 * 0000 0000-0000 007F 0xxxxxxx
9625 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9626 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9627 *
9628 * Check for the 0x110000 limit too
9629 */
9630 c = *cur;
9631 if (c & 0x80) {
9632 if ((cur[1] & 0xc0) != 0x80)
9633 goto encoding_error;
9634 if ((c & 0xe0) == 0xe0) {
9635
9636 if ((cur[2] & 0xc0) != 0x80)
9637 goto encoding_error;
9638 if ((c & 0xf0) == 0xf0) {
9639 if (((c & 0xf8) != 0xf0) ||
9640 ((cur[3] & 0xc0) != 0x80))
9641 goto encoding_error;
9642 /* 4-byte code */
9643 *len = 4;
9644 val = (cur[0] & 0x7) << 18;
9645 val |= (cur[1] & 0x3f) << 12;
9646 val |= (cur[2] & 0x3f) << 6;
9647 val |= cur[3] & 0x3f;
9648 } else {
9649 /* 3-byte code */
9650 *len = 3;
9651 val = (cur[0] & 0xf) << 12;
9652 val |= (cur[1] & 0x3f) << 6;
9653 val |= cur[2] & 0x3f;
9654 }
9655 } else {
9656 /* 2-byte code */
9657 *len = 2;
9658 val = (cur[0] & 0x1f) << 6;
9659 val |= cur[1] & 0x3f;
9660 }
9661 if (!IS_CHAR(val)) {
9662 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9663 }
9664 return(val);
9665 } else {
9666 /* 1-byte code */
9667 *len = 1;
9668 return((int) *cur);
9669 }
9670encoding_error:
9671 /*
William M. Brack08171912003-12-29 02:52:11 +00009672 * If we detect an UTF8 error that probably means that the
9673 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009674 * declaration header. Report the error and switch the encoding
9675 * to ISO-Latin-1 (if you don't like this policy, just declare the
9676 * encoding !)
9677 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009678 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009679 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009680}
9681
9682/**
Owen Taylor3473f882001-02-23 17:55:21 +00009683 * xmlXPathParseNCName:
9684 * @ctxt: the XPath Parser context
9685 *
9686 * parse an XML namespace non qualified name.
9687 *
9688 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9689 *
9690 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9691 * CombiningChar | Extender
9692 *
9693 * Returns the namespace name or NULL
9694 */
9695
9696xmlChar *
9697xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009698 const xmlChar *in;
9699 xmlChar *ret;
9700 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009701
Daniel Veillarda82b1822004-11-08 16:24:57 +00009702 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009703 /*
9704 * Accelerator for simple ASCII names
9705 */
9706 in = ctxt->cur;
9707 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9708 ((*in >= 0x41) && (*in <= 0x5A)) ||
9709 (*in == '_')) {
9710 in++;
9711 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9712 ((*in >= 0x41) && (*in <= 0x5A)) ||
9713 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009714 (*in == '_') || (*in == '.') ||
9715 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009716 in++;
9717 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9718 (*in == '[') || (*in == ']') || (*in == ':') ||
9719 (*in == '@') || (*in == '*')) {
9720 count = in - ctxt->cur;
9721 if (count == 0)
9722 return(NULL);
9723 ret = xmlStrndup(ctxt->cur, count);
9724 ctxt->cur = in;
9725 return(ret);
9726 }
9727 }
9728 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009729}
9730
Daniel Veillard2156a562001-04-28 12:24:34 +00009731
Owen Taylor3473f882001-02-23 17:55:21 +00009732/**
9733 * xmlXPathParseQName:
9734 * @ctxt: the XPath Parser context
9735 * @prefix: a xmlChar **
9736 *
9737 * parse an XML qualified name
9738 *
9739 * [NS 5] QName ::= (Prefix ':')? LocalPart
9740 *
9741 * [NS 6] Prefix ::= NCName
9742 *
9743 * [NS 7] LocalPart ::= NCName
9744 *
9745 * Returns the function returns the local part, and prefix is updated
9746 * to get the Prefix if any.
9747 */
9748
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009749static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009750xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9751 xmlChar *ret = NULL;
9752
9753 *prefix = NULL;
9754 ret = xmlXPathParseNCName(ctxt);
9755 if (CUR == ':') {
9756 *prefix = ret;
9757 NEXT;
9758 ret = xmlXPathParseNCName(ctxt);
9759 }
9760 return(ret);
9761}
9762
9763/**
9764 * xmlXPathParseName:
9765 * @ctxt: the XPath Parser context
9766 *
9767 * parse an XML name
9768 *
9769 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9770 * CombiningChar | Extender
9771 *
9772 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9773 *
9774 * Returns the namespace name or NULL
9775 */
9776
9777xmlChar *
9778xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009779 const xmlChar *in;
9780 xmlChar *ret;
9781 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009782
Daniel Veillarda82b1822004-11-08 16:24:57 +00009783 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009784 /*
9785 * Accelerator for simple ASCII names
9786 */
9787 in = ctxt->cur;
9788 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9789 ((*in >= 0x41) && (*in <= 0x5A)) ||
9790 (*in == '_') || (*in == ':')) {
9791 in++;
9792 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9793 ((*in >= 0x41) && (*in <= 0x5A)) ||
9794 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009795 (*in == '_') || (*in == '-') ||
9796 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009797 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009798 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009799 count = in - ctxt->cur;
9800 ret = xmlStrndup(ctxt->cur, count);
9801 ctxt->cur = in;
9802 return(ret);
9803 }
9804 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009805 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009806}
9807
Daniel Veillard61d80a22001-04-27 17:13:01 +00009808static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009809xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009810 xmlChar buf[XML_MAX_NAMELEN + 5];
9811 int len = 0, l;
9812 int c;
9813
9814 /*
9815 * Handler for more complex cases
9816 */
9817 c = CUR_CHAR(l);
9818 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009819 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9820 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009821 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009822 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009823 return(NULL);
9824 }
9825
9826 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9827 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9828 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009829 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009830 (IS_COMBINING(c)) ||
9831 (IS_EXTENDER(c)))) {
9832 COPY_BUF(l,buf,len,c);
9833 NEXTL(l);
9834 c = CUR_CHAR(l);
9835 if (len >= XML_MAX_NAMELEN) {
9836 /*
9837 * Okay someone managed to make a huge name, so he's ready to pay
9838 * for the processing speed.
9839 */
9840 xmlChar *buffer;
9841 int max = len * 2;
9842
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009843 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009844 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009845 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009846 }
9847 memcpy(buffer, buf, len);
9848 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9849 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009850 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009851 (IS_COMBINING(c)) ||
9852 (IS_EXTENDER(c))) {
9853 if (len + 10 > max) {
9854 max *= 2;
9855 buffer = (xmlChar *) xmlRealloc(buffer,
9856 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009857 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009858 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009859 }
9860 }
9861 COPY_BUF(l,buffer,len,c);
9862 NEXTL(l);
9863 c = CUR_CHAR(l);
9864 }
9865 buffer[len] = 0;
9866 return(buffer);
9867 }
9868 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009869 if (len == 0)
9870 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009871 return(xmlStrndup(buf, len));
9872}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009873
9874#define MAX_FRAC 20
9875
William M. Brack372a4452004-02-17 13:09:23 +00009876/*
9877 * These are used as divisors for the fractional part of a number.
9878 * Since the table includes 1.0 (representing '0' fractional digits),
9879 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9880 */
9881static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009882 1.0, 10.0, 100.0, 1000.0, 10000.0,
9883 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9884 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9885 100000000000000.0,
9886 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009887 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009888};
9889
Owen Taylor3473f882001-02-23 17:55:21 +00009890/**
9891 * xmlXPathStringEvalNumber:
9892 * @str: A string to scan
9893 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009894 * [30a] Float ::= Number ('e' Digits?)?
9895 *
Owen Taylor3473f882001-02-23 17:55:21 +00009896 * [30] Number ::= Digits ('.' Digits?)?
9897 * | '.' Digits
9898 * [31] Digits ::= [0-9]+
9899 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009900 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009901 * In complement of the Number expression, this function also handles
9902 * negative values : '-' Number.
9903 *
9904 * Returns the double value.
9905 */
9906double
9907xmlXPathStringEvalNumber(const xmlChar *str) {
9908 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009909 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009910 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009911 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009912 int exponent = 0;
9913 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009914#ifdef __GNUC__
9915 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009916 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009917#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009918 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009919 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009920 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9921 return(xmlXPathNAN);
9922 }
9923 if (*cur == '-') {
9924 isneg = 1;
9925 cur++;
9926 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009927
9928#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009929 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009930 * tmp/temp is a workaround against a gcc compiler bug
9931 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009932 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009933 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009934 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009935 ret = ret * 10;
9936 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009937 ok = 1;
9938 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009939 temp = (double) tmp;
9940 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009941 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009942#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009943 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009944 while ((*cur >= '0') && (*cur <= '9')) {
9945 ret = ret * 10 + (*cur - '0');
9946 ok = 1;
9947 cur++;
9948 }
9949#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009950
Owen Taylor3473f882001-02-23 17:55:21 +00009951 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009952 int v, frac = 0;
9953 double fraction = 0;
9954
Owen Taylor3473f882001-02-23 17:55:21 +00009955 cur++;
9956 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9957 return(xmlXPathNAN);
9958 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009959 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9960 v = (*cur - '0');
9961 fraction = fraction * 10 + v;
9962 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009963 cur++;
9964 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009965 fraction /= my_pow10[frac];
9966 ret = ret + fraction;
9967 while ((*cur >= '0') && (*cur <= '9'))
9968 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009969 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009970 if ((*cur == 'e') || (*cur == 'E')) {
9971 cur++;
9972 if (*cur == '-') {
9973 is_exponent_negative = 1;
9974 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009975 } else if (*cur == '+') {
9976 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009977 }
9978 while ((*cur >= '0') && (*cur <= '9')) {
9979 exponent = exponent * 10 + (*cur - '0');
9980 cur++;
9981 }
9982 }
William M. Brack76e95df2003-10-18 16:20:14 +00009983 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009984 if (*cur != 0) return(xmlXPathNAN);
9985 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009986 if (is_exponent_negative) exponent = -exponent;
9987 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009988 return(ret);
9989}
9990
9991/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009992 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009993 * @ctxt: the XPath Parser context
9994 *
9995 * [30] Number ::= Digits ('.' Digits?)?
9996 * | '.' Digits
9997 * [31] Digits ::= [0-9]+
9998 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009999 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010000 *
10001 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010002static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010003xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10004{
Owen Taylor3473f882001-02-23 17:55:21 +000010005 double ret = 0.0;
10006 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +000010007 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010008 int exponent = 0;
10009 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010010#ifdef __GNUC__
10011 unsigned long tmp = 0;
10012 double temp;
10013#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010014
10015 CHECK_ERROR;
10016 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10017 XP_ERROR(XPATH_NUMBER_ERROR);
10018 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010019#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010020 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010021 * tmp/temp is a workaround against a gcc compiler bug
10022 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010023 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010024 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010025 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010026 ret = ret * 10;
10027 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010028 ok = 1;
10029 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010030 temp = (double) tmp;
10031 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010032 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010033#else
10034 ret = 0;
10035 while ((CUR >= '0') && (CUR <= '9')) {
10036 ret = ret * 10 + (CUR - '0');
10037 ok = 1;
10038 NEXT;
10039 }
10040#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010041 if (CUR == '.') {
10042 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010043 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10044 XP_ERROR(XPATH_NUMBER_ERROR);
10045 }
10046 while ((CUR >= '0') && (CUR <= '9')) {
10047 mult /= 10;
10048 ret = ret + (CUR - '0') * mult;
10049 NEXT;
10050 }
Owen Taylor3473f882001-02-23 17:55:21 +000010051 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010052 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010053 NEXT;
10054 if (CUR == '-') {
10055 is_exponent_negative = 1;
10056 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010057 } else if (CUR == '+') {
10058 NEXT;
10059 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010060 while ((CUR >= '0') && (CUR <= '9')) {
10061 exponent = exponent * 10 + (CUR - '0');
10062 NEXT;
10063 }
10064 if (is_exponent_negative)
10065 exponent = -exponent;
10066 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010067 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010068 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010069 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010070}
10071
10072/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010073 * xmlXPathParseLiteral:
10074 * @ctxt: the XPath Parser context
10075 *
10076 * Parse a Literal
10077 *
10078 * [29] Literal ::= '"' [^"]* '"'
10079 * | "'" [^']* "'"
10080 *
10081 * Returns the value found or NULL in case of error
10082 */
10083static xmlChar *
10084xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10085 const xmlChar *q;
10086 xmlChar *ret = NULL;
10087
10088 if (CUR == '"') {
10089 NEXT;
10090 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010091 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010092 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010093 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010094 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010095 } else {
10096 ret = xmlStrndup(q, CUR_PTR - q);
10097 NEXT;
10098 }
10099 } else if (CUR == '\'') {
10100 NEXT;
10101 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010102 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010103 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010104 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010105 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010106 } else {
10107 ret = xmlStrndup(q, CUR_PTR - q);
10108 NEXT;
10109 }
10110 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010111 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010112 }
10113 return(ret);
10114}
10115
10116/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010117 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010118 * @ctxt: the XPath Parser context
10119 *
10120 * Parse a Literal and push it on the stack.
10121 *
10122 * [29] Literal ::= '"' [^"]* '"'
10123 * | "'" [^']* "'"
10124 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010125 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010126 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010127static void
10128xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010129 const xmlChar *q;
10130 xmlChar *ret = NULL;
10131
10132 if (CUR == '"') {
10133 NEXT;
10134 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010135 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010136 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010137 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010138 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10139 } else {
10140 ret = xmlStrndup(q, CUR_PTR - q);
10141 NEXT;
10142 }
10143 } else if (CUR == '\'') {
10144 NEXT;
10145 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010146 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010147 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010148 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010149 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10150 } else {
10151 ret = xmlStrndup(q, CUR_PTR - q);
10152 NEXT;
10153 }
10154 } else {
10155 XP_ERROR(XPATH_START_LITERAL_ERROR);
10156 }
10157 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010158 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010159 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010160 xmlFree(ret);
10161}
10162
10163/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010164 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010165 * @ctxt: the XPath Parser context
10166 *
10167 * Parse a VariableReference, evaluate it and push it on the stack.
10168 *
10169 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010170 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010171 * of any of the types that are possible for the value of an expression,
10172 * and may also be of additional types not specified here.
10173 *
10174 * Early evaluation is possible since:
10175 * The variable bindings [...] used to evaluate a subexpression are
10176 * always the same as those used to evaluate the containing expression.
10177 *
10178 * [36] VariableReference ::= '$' QName
10179 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010180static void
10181xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010182 xmlChar *name;
10183 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010184
10185 SKIP_BLANKS;
10186 if (CUR != '$') {
10187 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10188 }
10189 NEXT;
10190 name = xmlXPathParseQName(ctxt, &prefix);
10191 if (name == NULL) {
10192 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10193 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010194 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010195 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10196 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010197 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010198 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10199 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10200 }
Owen Taylor3473f882001-02-23 17:55:21 +000010201}
10202
10203/**
10204 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010205 * @name: a name string
10206 *
10207 * Is the name given a NodeType one.
10208 *
10209 * [38] NodeType ::= 'comment'
10210 * | 'text'
10211 * | 'processing-instruction'
10212 * | 'node'
10213 *
10214 * Returns 1 if true 0 otherwise
10215 */
10216int
10217xmlXPathIsNodeType(const xmlChar *name) {
10218 if (name == NULL)
10219 return(0);
10220
Daniel Veillard1971ee22002-01-31 20:29:19 +000010221 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010222 return(1);
10223 if (xmlStrEqual(name, BAD_CAST "text"))
10224 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010225 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010226 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010227 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010228 return(1);
10229 return(0);
10230}
10231
10232/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010233 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010234 * @ctxt: the XPath Parser context
10235 *
10236 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10237 * [17] Argument ::= Expr
10238 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010239 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010240 * pushed on the stack
10241 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010242static void
10243xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010244 xmlChar *name;
10245 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010246 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010247 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010248
10249 name = xmlXPathParseQName(ctxt, &prefix);
10250 if (name == NULL) {
10251 XP_ERROR(XPATH_EXPR_ERROR);
10252 }
10253 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010254#ifdef DEBUG_EXPR
10255 if (prefix == NULL)
10256 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10257 name);
10258 else
10259 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10260 prefix, name);
10261#endif
10262
Owen Taylor3473f882001-02-23 17:55:21 +000010263 if (CUR != '(') {
10264 XP_ERROR(XPATH_EXPR_ERROR);
10265 }
10266 NEXT;
10267 SKIP_BLANKS;
10268
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010269 /*
10270 * Optimization for count(): we don't need the node-set to be sorted.
10271 */
10272 if ((prefix == NULL) && (name[0] == 'c') &&
10273 xmlStrEqual(name, BAD_CAST "count"))
10274 {
10275 sort = 0;
10276 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010277 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010278 if (CUR != ')') {
10279 while (CUR != 0) {
10280 int op1 = ctxt->comp->last;
10281 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010282 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010283 CHECK_ERROR;
10284 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10285 nbargs++;
10286 if (CUR == ')') break;
10287 if (CUR != ',') {
10288 XP_ERROR(XPATH_EXPR_ERROR);
10289 }
10290 NEXT;
10291 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010292 }
Owen Taylor3473f882001-02-23 17:55:21 +000010293 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010294 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10295 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010296 NEXT;
10297 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010298}
10299
10300/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010301 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010302 * @ctxt: the XPath Parser context
10303 *
10304 * [15] PrimaryExpr ::= VariableReference
10305 * | '(' Expr ')'
10306 * | Literal
10307 * | Number
10308 * | FunctionCall
10309 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010310 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010311 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010312static void
10313xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010314 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010315 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010316 else if (CUR == '(') {
10317 NEXT;
10318 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010319 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010320 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010321 if (CUR != ')') {
10322 XP_ERROR(XPATH_EXPR_ERROR);
10323 }
10324 NEXT;
10325 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010326 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010327 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010328 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010329 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010330 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010331 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010332 }
10333 SKIP_BLANKS;
10334}
10335
10336/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010337 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010338 * @ctxt: the XPath Parser context
10339 *
10340 * [20] FilterExpr ::= PrimaryExpr
10341 * | FilterExpr Predicate
10342 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010343 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010344 * Square brackets are used to filter expressions in the same way that
10345 * they are used in location paths. It is an error if the expression to
10346 * be filtered does not evaluate to a node-set. The context node list
10347 * used for evaluating the expression in square brackets is the node-set
10348 * to be filtered listed in document order.
10349 */
10350
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010351static void
10352xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10353 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010354 CHECK_ERROR;
10355 SKIP_BLANKS;
10356
10357 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010358 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010359 SKIP_BLANKS;
10360 }
10361
10362
10363}
10364
10365/**
10366 * xmlXPathScanName:
10367 * @ctxt: the XPath Parser context
10368 *
10369 * Trickery: parse an XML name but without consuming the input flow
10370 * Needed to avoid insanity in the parser state.
10371 *
10372 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10373 * CombiningChar | Extender
10374 *
10375 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10376 *
10377 * [6] Names ::= Name (S Name)*
10378 *
10379 * Returns the Name parsed or NULL
10380 */
10381
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010382static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010383xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010384 int len = 0, l;
10385 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010386 const xmlChar *cur;
10387 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010388
Daniel Veillard03226812004-11-01 14:55:21 +000010389 cur = ctxt->cur;
10390
10391 c = CUR_CHAR(l);
10392 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10393 (!IS_LETTER(c) && (c != '_') &&
10394 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010395 return(NULL);
10396 }
10397
Daniel Veillard03226812004-11-01 14:55:21 +000010398 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10399 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10400 (c == '.') || (c == '-') ||
10401 (c == '_') || (c == ':') ||
10402 (IS_COMBINING(c)) ||
10403 (IS_EXTENDER(c)))) {
10404 len += l;
10405 NEXTL(l);
10406 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010407 }
Daniel Veillard03226812004-11-01 14:55:21 +000010408 ret = xmlStrndup(cur, ctxt->cur - cur);
10409 ctxt->cur = cur;
10410 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010411}
10412
10413/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010414 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010415 * @ctxt: the XPath Parser context
10416 *
10417 * [19] PathExpr ::= LocationPath
10418 * | FilterExpr
10419 * | FilterExpr '/' RelativeLocationPath
10420 * | FilterExpr '//' RelativeLocationPath
10421 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010422 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010423 * The / operator and // operators combine an arbitrary expression
10424 * and a relative location path. It is an error if the expression
10425 * does not evaluate to a node-set.
10426 * The / operator does composition in the same way as when / is
10427 * used in a location path. As in location paths, // is short for
10428 * /descendant-or-self::node()/.
10429 */
10430
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010431static void
10432xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010433 int lc = 1; /* Should we branch to LocationPath ? */
10434 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10435
10436 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010437 if ((CUR == '$') || (CUR == '(') ||
10438 (IS_ASCII_DIGIT(CUR)) ||
10439 (CUR == '\'') || (CUR == '"') ||
10440 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010441 lc = 0;
10442 } else if (CUR == '*') {
10443 /* relative or absolute location path */
10444 lc = 1;
10445 } else if (CUR == '/') {
10446 /* relative or absolute location path */
10447 lc = 1;
10448 } else if (CUR == '@') {
10449 /* relative abbreviated attribute location path */
10450 lc = 1;
10451 } else if (CUR == '.') {
10452 /* relative abbreviated attribute location path */
10453 lc = 1;
10454 } else {
10455 /*
10456 * Problem is finding if we have a name here whether it's:
10457 * - a nodetype
10458 * - a function call in which case it's followed by '('
10459 * - an axis in which case it's followed by ':'
10460 * - a element name
10461 * We do an a priori analysis here rather than having to
10462 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010463 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010464 * read/write/debug.
10465 */
10466 SKIP_BLANKS;
10467 name = xmlXPathScanName(ctxt);
10468 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10469#ifdef DEBUG_STEP
10470 xmlGenericError(xmlGenericErrorContext,
10471 "PathExpr: Axis\n");
10472#endif
10473 lc = 1;
10474 xmlFree(name);
10475 } else if (name != NULL) {
10476 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010477
10478
10479 while (NXT(len) != 0) {
10480 if (NXT(len) == '/') {
10481 /* element name */
10482#ifdef DEBUG_STEP
10483 xmlGenericError(xmlGenericErrorContext,
10484 "PathExpr: AbbrRelLocation\n");
10485#endif
10486 lc = 1;
10487 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010488 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010489 /* ignore blanks */
10490 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010491 } else if (NXT(len) == ':') {
10492#ifdef DEBUG_STEP
10493 xmlGenericError(xmlGenericErrorContext,
10494 "PathExpr: AbbrRelLocation\n");
10495#endif
10496 lc = 1;
10497 break;
10498 } else if ((NXT(len) == '(')) {
10499 /* Note Type or Function */
10500 if (xmlXPathIsNodeType(name)) {
10501#ifdef DEBUG_STEP
10502 xmlGenericError(xmlGenericErrorContext,
10503 "PathExpr: Type search\n");
10504#endif
10505 lc = 1;
10506 } else {
10507#ifdef DEBUG_STEP
10508 xmlGenericError(xmlGenericErrorContext,
10509 "PathExpr: function call\n");
10510#endif
10511 lc = 0;
10512 }
10513 break;
10514 } else if ((NXT(len) == '[')) {
10515 /* element name */
10516#ifdef DEBUG_STEP
10517 xmlGenericError(xmlGenericErrorContext,
10518 "PathExpr: AbbrRelLocation\n");
10519#endif
10520 lc = 1;
10521 break;
10522 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10523 (NXT(len) == '=')) {
10524 lc = 1;
10525 break;
10526 } else {
10527 lc = 1;
10528 break;
10529 }
10530 len++;
10531 }
10532 if (NXT(len) == 0) {
10533#ifdef DEBUG_STEP
10534 xmlGenericError(xmlGenericErrorContext,
10535 "PathExpr: AbbrRelLocation\n");
10536#endif
10537 /* element name */
10538 lc = 1;
10539 }
10540 xmlFree(name);
10541 } else {
William M. Brack08171912003-12-29 02:52:11 +000010542 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010543 XP_ERROR(XPATH_EXPR_ERROR);
10544 }
10545 }
10546
10547 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010548 if (CUR == '/') {
10549 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10550 } else {
10551 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010552 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010553 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010554 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010555 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010556 CHECK_ERROR;
10557 if ((CUR == '/') && (NXT(1) == '/')) {
10558 SKIP(2);
10559 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010560
10561 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10562 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10563 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10564
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010565 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010566 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010567 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010568 }
10569 }
10570 SKIP_BLANKS;
10571}
10572
10573/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010574 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010575 * @ctxt: the XPath Parser context
10576 *
10577 * [18] UnionExpr ::= PathExpr
10578 * | UnionExpr '|' PathExpr
10579 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010580 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010581 */
10582
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010583static void
10584xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10585 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010586 CHECK_ERROR;
10587 SKIP_BLANKS;
10588 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010589 int op1 = ctxt->comp->last;
10590 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010591
10592 NEXT;
10593 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010594 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010595
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010596 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10597
Owen Taylor3473f882001-02-23 17:55:21 +000010598 SKIP_BLANKS;
10599 }
Owen Taylor3473f882001-02-23 17:55:21 +000010600}
10601
10602/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010603 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010604 * @ctxt: the XPath Parser context
10605 *
10606 * [27] UnaryExpr ::= UnionExpr
10607 * | '-' UnaryExpr
10608 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010609 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010610 */
10611
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010612static void
10613xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010614 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010615 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010616
10617 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010618 while (CUR == '-') {
10619 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010620 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010621 NEXT;
10622 SKIP_BLANKS;
10623 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010624
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010625 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010626 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010627 if (found) {
10628 if (minus)
10629 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10630 else
10631 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010632 }
10633}
10634
10635/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010636 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010637 * @ctxt: the XPath Parser context
10638 *
10639 * [26] MultiplicativeExpr ::= UnaryExpr
10640 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10641 * | MultiplicativeExpr 'div' UnaryExpr
10642 * | MultiplicativeExpr 'mod' UnaryExpr
10643 * [34] MultiplyOperator ::= '*'
10644 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010645 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010646 */
10647
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010648static void
10649xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10650 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010651 CHECK_ERROR;
10652 SKIP_BLANKS;
10653 while ((CUR == '*') ||
10654 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10655 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10656 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010657 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010658
10659 if (CUR == '*') {
10660 op = 0;
10661 NEXT;
10662 } else if (CUR == 'd') {
10663 op = 1;
10664 SKIP(3);
10665 } else if (CUR == 'm') {
10666 op = 2;
10667 SKIP(3);
10668 }
10669 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010670 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010671 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010672 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010673 SKIP_BLANKS;
10674 }
10675}
10676
10677/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010678 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010679 * @ctxt: the XPath Parser context
10680 *
10681 * [25] AdditiveExpr ::= MultiplicativeExpr
10682 * | AdditiveExpr '+' MultiplicativeExpr
10683 * | AdditiveExpr '-' MultiplicativeExpr
10684 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010686 */
10687
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010688static void
10689xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010690
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010691 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010692 CHECK_ERROR;
10693 SKIP_BLANKS;
10694 while ((CUR == '+') || (CUR == '-')) {
10695 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010696 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010697
10698 if (CUR == '+') plus = 1;
10699 else plus = 0;
10700 NEXT;
10701 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010702 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010703 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010704 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010705 SKIP_BLANKS;
10706 }
10707}
10708
10709/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010710 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010711 * @ctxt: the XPath Parser context
10712 *
10713 * [24] RelationalExpr ::= AdditiveExpr
10714 * | RelationalExpr '<' AdditiveExpr
10715 * | RelationalExpr '>' AdditiveExpr
10716 * | RelationalExpr '<=' AdditiveExpr
10717 * | RelationalExpr '>=' AdditiveExpr
10718 *
10719 * A <= B > C is allowed ? Answer from James, yes with
10720 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10721 * which is basically what got implemented.
10722 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010723 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010724 * on the stack
10725 */
10726
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010727static void
10728xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10729 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010730 CHECK_ERROR;
10731 SKIP_BLANKS;
10732 while ((CUR == '<') ||
10733 (CUR == '>') ||
10734 ((CUR == '<') && (NXT(1) == '=')) ||
10735 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010736 int inf, strict;
10737 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010738
10739 if (CUR == '<') inf = 1;
10740 else inf = 0;
10741 if (NXT(1) == '=') strict = 0;
10742 else strict = 1;
10743 NEXT;
10744 if (!strict) NEXT;
10745 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010746 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010747 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010748 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010749 SKIP_BLANKS;
10750 }
10751}
10752
10753/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010754 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010755 * @ctxt: the XPath Parser context
10756 *
10757 * [23] EqualityExpr ::= RelationalExpr
10758 * | EqualityExpr '=' RelationalExpr
10759 * | EqualityExpr '!=' RelationalExpr
10760 *
10761 * A != B != C is allowed ? Answer from James, yes with
10762 * (RelationalExpr = RelationalExpr) = RelationalExpr
10763 * (RelationalExpr != RelationalExpr) != RelationalExpr
10764 * which is basically what got implemented.
10765 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010766 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010767 *
10768 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010769static void
10770xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10771 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010772 CHECK_ERROR;
10773 SKIP_BLANKS;
10774 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010775 int eq;
10776 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010777
10778 if (CUR == '=') eq = 1;
10779 else eq = 0;
10780 NEXT;
10781 if (!eq) NEXT;
10782 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010783 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010784 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010785 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010786 SKIP_BLANKS;
10787 }
10788}
10789
10790/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010791 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010792 * @ctxt: the XPath Parser context
10793 *
10794 * [22] AndExpr ::= EqualityExpr
10795 * | AndExpr 'and' EqualityExpr
10796 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010798 *
10799 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010800static void
10801xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10802 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010803 CHECK_ERROR;
10804 SKIP_BLANKS;
10805 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010806 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010807 SKIP(3);
10808 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010809 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010810 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010811 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010812 SKIP_BLANKS;
10813 }
10814}
10815
10816/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010817 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010818 * @ctxt: the XPath Parser context
10819 *
10820 * [14] Expr ::= OrExpr
10821 * [21] OrExpr ::= AndExpr
10822 * | OrExpr 'or' AndExpr
10823 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010824 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010825 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010827xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010828 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010829 CHECK_ERROR;
10830 SKIP_BLANKS;
10831 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010832 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010833 SKIP(2);
10834 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010835 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010836 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010837 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10838 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010839 SKIP_BLANKS;
10840 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010841 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010842 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010843 /*
10844 * This is the main place to eliminate sorting for
10845 * operations which don't require a sorted node-set.
10846 * E.g. count().
10847 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010848 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10849 }
Owen Taylor3473f882001-02-23 17:55:21 +000010850}
10851
10852/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010853 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010854 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010855 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010856 *
10857 * [8] Predicate ::= '[' PredicateExpr ']'
10858 * [9] PredicateExpr ::= Expr
10859 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010860 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010861 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010862static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010863xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010864 int op1 = ctxt->comp->last;
10865
10866 SKIP_BLANKS;
10867 if (CUR != '[') {
10868 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10869 }
10870 NEXT;
10871 SKIP_BLANKS;
10872
10873 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010874 /*
10875 * This call to xmlXPathCompileExpr() will deactivate sorting
10876 * of the predicate result.
10877 * TODO: Sorting is still activated for filters, since I'm not
10878 * sure if needed. Normally sorting should not be needed, since
10879 * a filter can only diminish the number of items in a sequence,
10880 * but won't change its order; so if the initial sequence is sorted,
10881 * subsequent sorting is not needed.
10882 */
10883 if (! filter)
10884 xmlXPathCompileExpr(ctxt, 0);
10885 else
10886 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010887 CHECK_ERROR;
10888
10889 if (CUR != ']') {
10890 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10891 }
10892
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010893 if (filter)
10894 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10895 else
10896 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010897
10898 NEXT;
10899 SKIP_BLANKS;
10900}
10901
10902/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010903 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010904 * @ctxt: the XPath Parser context
10905 * @test: pointer to a xmlXPathTestVal
10906 * @type: pointer to a xmlXPathTypeVal
10907 * @prefix: placeholder for a possible name prefix
10908 *
10909 * [7] NodeTest ::= NameTest
10910 * | NodeType '(' ')'
10911 * | 'processing-instruction' '(' Literal ')'
10912 *
10913 * [37] NameTest ::= '*'
10914 * | NCName ':' '*'
10915 * | QName
10916 * [38] NodeType ::= 'comment'
10917 * | 'text'
10918 * | 'processing-instruction'
10919 * | 'node'
10920 *
William M. Brack08171912003-12-29 02:52:11 +000010921 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010922 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010923static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010924xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10925 xmlXPathTypeVal *type, const xmlChar **prefix,
10926 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010927 int blanks;
10928
10929 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10930 STRANGE;
10931 return(NULL);
10932 }
William M. Brack78637da2003-07-31 14:47:38 +000010933 *type = (xmlXPathTypeVal) 0;
10934 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010935 *prefix = NULL;
10936 SKIP_BLANKS;
10937
10938 if ((name == NULL) && (CUR == '*')) {
10939 /*
10940 * All elements
10941 */
10942 NEXT;
10943 *test = NODE_TEST_ALL;
10944 return(NULL);
10945 }
10946
10947 if (name == NULL)
10948 name = xmlXPathParseNCName(ctxt);
10949 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010950 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010951 }
10952
William M. Brack76e95df2003-10-18 16:20:14 +000010953 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010954 SKIP_BLANKS;
10955 if (CUR == '(') {
10956 NEXT;
10957 /*
10958 * NodeType or PI search
10959 */
10960 if (xmlStrEqual(name, BAD_CAST "comment"))
10961 *type = NODE_TYPE_COMMENT;
10962 else if (xmlStrEqual(name, BAD_CAST "node"))
10963 *type = NODE_TYPE_NODE;
10964 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10965 *type = NODE_TYPE_PI;
10966 else if (xmlStrEqual(name, BAD_CAST "text"))
10967 *type = NODE_TYPE_TEXT;
10968 else {
10969 if (name != NULL)
10970 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010971 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010972 }
10973
10974 *test = NODE_TEST_TYPE;
10975
10976 SKIP_BLANKS;
10977 if (*type == NODE_TYPE_PI) {
10978 /*
10979 * Specific case: search a PI by name.
10980 */
Owen Taylor3473f882001-02-23 17:55:21 +000010981 if (name != NULL)
10982 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010983 name = NULL;
10984 if (CUR != ')') {
10985 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010986 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010987 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010988 SKIP_BLANKS;
10989 }
Owen Taylor3473f882001-02-23 17:55:21 +000010990 }
10991 if (CUR != ')') {
10992 if (name != NULL)
10993 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010994 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010995 }
10996 NEXT;
10997 return(name);
10998 }
10999 *test = NODE_TEST_NAME;
11000 if ((!blanks) && (CUR == ':')) {
11001 NEXT;
11002
11003 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011004 * Since currently the parser context don't have a
11005 * namespace list associated:
11006 * The namespace name for this prefix can be computed
11007 * only at evaluation time. The compilation is done
11008 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011009 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011010#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011011 *prefix = xmlXPathNsLookup(ctxt->context, name);
11012 if (name != NULL)
11013 xmlFree(name);
11014 if (*prefix == NULL) {
11015 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11016 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011017#else
11018 *prefix = name;
11019#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011020
11021 if (CUR == '*') {
11022 /*
11023 * All elements
11024 */
11025 NEXT;
11026 *test = NODE_TEST_ALL;
11027 return(NULL);
11028 }
11029
11030 name = xmlXPathParseNCName(ctxt);
11031 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011032 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011033 }
11034 }
11035 return(name);
11036}
11037
11038/**
11039 * xmlXPathIsAxisName:
11040 * @name: a preparsed name token
11041 *
11042 * [6] AxisName ::= 'ancestor'
11043 * | 'ancestor-or-self'
11044 * | 'attribute'
11045 * | 'child'
11046 * | 'descendant'
11047 * | 'descendant-or-self'
11048 * | 'following'
11049 * | 'following-sibling'
11050 * | 'namespace'
11051 * | 'parent'
11052 * | 'preceding'
11053 * | 'preceding-sibling'
11054 * | 'self'
11055 *
11056 * Returns the axis or 0
11057 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011058static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011059xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011060 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011061 switch (name[0]) {
11062 case 'a':
11063 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11064 ret = AXIS_ANCESTOR;
11065 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11066 ret = AXIS_ANCESTOR_OR_SELF;
11067 if (xmlStrEqual(name, BAD_CAST "attribute"))
11068 ret = AXIS_ATTRIBUTE;
11069 break;
11070 case 'c':
11071 if (xmlStrEqual(name, BAD_CAST "child"))
11072 ret = AXIS_CHILD;
11073 break;
11074 case 'd':
11075 if (xmlStrEqual(name, BAD_CAST "descendant"))
11076 ret = AXIS_DESCENDANT;
11077 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11078 ret = AXIS_DESCENDANT_OR_SELF;
11079 break;
11080 case 'f':
11081 if (xmlStrEqual(name, BAD_CAST "following"))
11082 ret = AXIS_FOLLOWING;
11083 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11084 ret = AXIS_FOLLOWING_SIBLING;
11085 break;
11086 case 'n':
11087 if (xmlStrEqual(name, BAD_CAST "namespace"))
11088 ret = AXIS_NAMESPACE;
11089 break;
11090 case 'p':
11091 if (xmlStrEqual(name, BAD_CAST "parent"))
11092 ret = AXIS_PARENT;
11093 if (xmlStrEqual(name, BAD_CAST "preceding"))
11094 ret = AXIS_PRECEDING;
11095 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11096 ret = AXIS_PRECEDING_SIBLING;
11097 break;
11098 case 's':
11099 if (xmlStrEqual(name, BAD_CAST "self"))
11100 ret = AXIS_SELF;
11101 break;
11102 }
11103 return(ret);
11104}
11105
11106/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011107 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011108 * @ctxt: the XPath Parser context
11109 *
11110 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11111 * | AbbreviatedStep
11112 *
11113 * [12] AbbreviatedStep ::= '.' | '..'
11114 *
11115 * [5] AxisSpecifier ::= AxisName '::'
11116 * | AbbreviatedAxisSpecifier
11117 *
11118 * [13] AbbreviatedAxisSpecifier ::= '@'?
11119 *
11120 * Modified for XPtr range support as:
11121 *
11122 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11123 * | AbbreviatedStep
11124 * | 'range-to' '(' Expr ')' Predicate*
11125 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011126 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011127 * A location step of . is short for self::node(). This is
11128 * particularly useful in conjunction with //. For example, the
11129 * location path .//para is short for
11130 * self::node()/descendant-or-self::node()/child::para
11131 * and so will select all para descendant elements of the context
11132 * node.
11133 * Similarly, a location step of .. is short for parent::node().
11134 * For example, ../title is short for parent::node()/child::title
11135 * and so will select the title children of the parent of the context
11136 * node.
11137 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011138static void
11139xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011140#ifdef LIBXML_XPTR_ENABLED
11141 int rangeto = 0;
11142 int op2 = -1;
11143#endif
11144
Owen Taylor3473f882001-02-23 17:55:21 +000011145 SKIP_BLANKS;
11146 if ((CUR == '.') && (NXT(1) == '.')) {
11147 SKIP(2);
11148 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011149 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11150 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011151 } else if (CUR == '.') {
11152 NEXT;
11153 SKIP_BLANKS;
11154 } else {
11155 xmlChar *name = NULL;
11156 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011157 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011158 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011159 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011160 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011161
11162 /*
11163 * The modification needed for XPointer change to the production
11164 */
11165#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011166 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011167 name = xmlXPathParseNCName(ctxt);
11168 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011169 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011170 xmlFree(name);
11171 SKIP_BLANKS;
11172 if (CUR != '(') {
11173 XP_ERROR(XPATH_EXPR_ERROR);
11174 }
11175 NEXT;
11176 SKIP_BLANKS;
11177
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011178 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011179 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011180 CHECK_ERROR;
11181
11182 SKIP_BLANKS;
11183 if (CUR != ')') {
11184 XP_ERROR(XPATH_EXPR_ERROR);
11185 }
11186 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011187 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011188 goto eval_predicates;
11189 }
11190 }
11191#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011192 if (CUR == '*') {
11193 axis = AXIS_CHILD;
11194 } else {
11195 if (name == NULL)
11196 name = xmlXPathParseNCName(ctxt);
11197 if (name != NULL) {
11198 axis = xmlXPathIsAxisName(name);
11199 if (axis != 0) {
11200 SKIP_BLANKS;
11201 if ((CUR == ':') && (NXT(1) == ':')) {
11202 SKIP(2);
11203 xmlFree(name);
11204 name = NULL;
11205 } else {
11206 /* an element name can conflict with an axis one :-\ */
11207 axis = AXIS_CHILD;
11208 }
Owen Taylor3473f882001-02-23 17:55:21 +000011209 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011210 axis = AXIS_CHILD;
11211 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011212 } else if (CUR == '@') {
11213 NEXT;
11214 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011215 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011216 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011217 }
Owen Taylor3473f882001-02-23 17:55:21 +000011218 }
11219
11220 CHECK_ERROR;
11221
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011222 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011223 if (test == 0)
11224 return;
11225
Daniel Veillarded6c5492005-07-23 15:00:22 +000011226 if ((prefix != NULL) && (ctxt->context != NULL) &&
11227 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11228 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11229 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11230 }
11231 }
Owen Taylor3473f882001-02-23 17:55:21 +000011232#ifdef DEBUG_STEP
11233 xmlGenericError(xmlGenericErrorContext,
11234 "Basis : computing new set\n");
11235#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011236
Owen Taylor3473f882001-02-23 17:55:21 +000011237#ifdef DEBUG_STEP
11238 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011239 if (ctxt->value == NULL)
11240 xmlGenericError(xmlGenericErrorContext, "no value\n");
11241 else if (ctxt->value->nodesetval == NULL)
11242 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11243 else
11244 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011245#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011246
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011247#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011248eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011249#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011250 op1 = ctxt->comp->last;
11251 ctxt->comp->last = -1;
11252
Owen Taylor3473f882001-02-23 17:55:21 +000011253 SKIP_BLANKS;
11254 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011255 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011256 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011257
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011258#ifdef LIBXML_XPTR_ENABLED
11259 if (rangeto) {
11260 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11261 } else
11262#endif
11263 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11264 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011265
Owen Taylor3473f882001-02-23 17:55:21 +000011266 }
11267#ifdef DEBUG_STEP
11268 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011269 if (ctxt->value == NULL)
11270 xmlGenericError(xmlGenericErrorContext, "no value\n");
11271 else if (ctxt->value->nodesetval == NULL)
11272 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11273 else
11274 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11275 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011276#endif
11277}
11278
11279/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011280 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011281 * @ctxt: the XPath Parser context
11282 *
11283 * [3] RelativeLocationPath ::= Step
11284 * | RelativeLocationPath '/' Step
11285 * | AbbreviatedRelativeLocationPath
11286 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11287 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011288 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011289 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011290static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011291xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011292(xmlXPathParserContextPtr ctxt) {
11293 SKIP_BLANKS;
11294 if ((CUR == '/') && (NXT(1) == '/')) {
11295 SKIP(2);
11296 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011297 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11298 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011299 } else if (CUR == '/') {
11300 NEXT;
11301 SKIP_BLANKS;
11302 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011303 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011304 SKIP_BLANKS;
11305 while (CUR == '/') {
11306 if ((CUR == '/') && (NXT(1) == '/')) {
11307 SKIP(2);
11308 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011309 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011310 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011311 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011312 } else if (CUR == '/') {
11313 NEXT;
11314 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011315 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011316 }
11317 SKIP_BLANKS;
11318 }
11319}
11320
11321/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011322 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011323 * @ctxt: the XPath Parser context
11324 *
11325 * [1] LocationPath ::= RelativeLocationPath
11326 * | AbsoluteLocationPath
11327 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11328 * | AbbreviatedAbsoluteLocationPath
11329 * [10] AbbreviatedAbsoluteLocationPath ::=
11330 * '//' RelativeLocationPath
11331 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011332 * Compile a location path
11333 *
Owen Taylor3473f882001-02-23 17:55:21 +000011334 * // is short for /descendant-or-self::node()/. For example,
11335 * //para is short for /descendant-or-self::node()/child::para and
11336 * so will select any para element in the document (even a para element
11337 * that is a document element will be selected by //para since the
11338 * document element node is a child of the root node); div//para is
11339 * short for div/descendant-or-self::node()/child::para and so will
11340 * select all para descendants of div children.
11341 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011342static void
11343xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011344 SKIP_BLANKS;
11345 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011346 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011347 } else {
11348 while (CUR == '/') {
11349 if ((CUR == '/') && (NXT(1) == '/')) {
11350 SKIP(2);
11351 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011352 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11353 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011354 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011355 } else if (CUR == '/') {
11356 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011357 SKIP_BLANKS;
11358 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011359 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011360 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011361 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011362 }
11363 }
11364 }
11365}
11366
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011367/************************************************************************
11368 * *
11369 * XPath precompiled expression evaluation *
11370 * *
11371 ************************************************************************/
11372
Daniel Veillardf06307e2001-07-03 10:35:50 +000011373static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011374xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11375
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011376#ifdef DEBUG_STEP
11377static void
11378xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11379 xmlXPathTestVal test,
11380 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011381{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011382 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011383 switch (axis) {
11384 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011385 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011386 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011387 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011388 xmlGenericError(xmlGenericErrorContext,
11389 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011391 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011392 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011394 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011395 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011396 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011397 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011399 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011400 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011401 xmlGenericError(xmlGenericErrorContext,
11402 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011403 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011404 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011405 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011406 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011407 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011408 xmlGenericError(xmlGenericErrorContext,
11409 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011411 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011412 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011413 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011414 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011415 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011416 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011417 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011418 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011419 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011420 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011421 xmlGenericError(xmlGenericErrorContext,
11422 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011423 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011424 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011425 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011426 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011427 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011428 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011429 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011430 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011431 case NODE_TEST_NONE:
11432 xmlGenericError(xmlGenericErrorContext,
11433 " searching for none !!!\n");
11434 break;
11435 case NODE_TEST_TYPE:
11436 xmlGenericError(xmlGenericErrorContext,
11437 " searching for type %d\n", type);
11438 break;
11439 case NODE_TEST_PI:
11440 xmlGenericError(xmlGenericErrorContext,
11441 " searching for PI !!!\n");
11442 break;
11443 case NODE_TEST_ALL:
11444 xmlGenericError(xmlGenericErrorContext,
11445 " searching for *\n");
11446 break;
11447 case NODE_TEST_NS:
11448 xmlGenericError(xmlGenericErrorContext,
11449 " searching for namespace %s\n",
11450 prefix);
11451 break;
11452 case NODE_TEST_NAME:
11453 xmlGenericError(xmlGenericErrorContext,
11454 " searching for name %s\n", name);
11455 if (prefix != NULL)
11456 xmlGenericError(xmlGenericErrorContext,
11457 " with namespace %s\n", prefix);
11458 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011459 }
11460 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011461}
11462#endif /* DEBUG_STEP */
11463
11464static int
11465xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11466 xmlXPathStepOpPtr op,
11467 xmlNodeSetPtr set,
11468 int contextSize,
11469 int hasNsNodes)
11470{
11471 if (op->ch1 != -1) {
11472 xmlXPathCompExprPtr comp = ctxt->comp;
11473 /*
11474 * Process inner predicates first.
11475 */
11476 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11477 /*
11478 * TODO: raise an internal error.
11479 */
11480 }
11481 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11482 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11483 CHECK_ERROR0;
11484 if (contextSize <= 0)
11485 return(0);
11486 }
11487 if (op->ch2 != -1) {
11488 xmlXPathContextPtr xpctxt = ctxt->context;
11489 xmlNodePtr contextNode, oldContextNode;
11490 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011491 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011492 xmlXPathStepOpPtr exprOp;
11493 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11494
11495#ifdef LIBXML_XPTR_ENABLED
11496 /*
11497 * URGENT TODO: Check the following:
11498 * We don't expect location sets if evaluating prediates, right?
11499 * Only filters should expect location sets, right?
11500 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011501#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011502 /*
11503 * SPEC XPath 1.0:
11504 * "For each node in the node-set to be filtered, the
11505 * PredicateExpr is evaluated with that node as the
11506 * context node, with the number of nodes in the
11507 * node-set as the context size, and with the proximity
11508 * position of the node in the node-set with respect to
11509 * the axis as the context position;"
11510 * @oldset is the node-set" to be filtered.
11511 *
11512 * SPEC XPath 1.0:
11513 * "only predicates change the context position and
11514 * context size (see [2.4 Predicates])."
11515 * Example:
11516 * node-set context pos
11517 * nA 1
11518 * nB 2
11519 * nC 3
11520 * After applying predicate [position() > 1] :
11521 * node-set context pos
11522 * nB 1
11523 * nC 2
11524 */
11525 oldContextNode = xpctxt->node;
11526 oldContextDoc = xpctxt->doc;
11527 /*
11528 * Get the expression of this predicate.
11529 */
11530 exprOp = &ctxt->comp->steps[op->ch2];
11531 newContextSize = 0;
11532 for (i = 0; i < set->nodeNr; i++) {
11533 if (set->nodeTab[i] == NULL)
11534 continue;
11535
11536 contextNode = set->nodeTab[i];
11537 xpctxt->node = contextNode;
11538 xpctxt->contextSize = contextSize;
11539 xpctxt->proximityPosition = ++contextPos;
11540
11541 /*
11542 * Also set the xpath document in case things like
11543 * key() are evaluated in the predicate.
11544 */
11545 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11546 (contextNode->doc != NULL))
11547 xpctxt->doc = contextNode->doc;
11548 /*
11549 * Evaluate the predicate expression with 1 context node
11550 * at a time; this node is packaged into a node set; this
11551 * node set is handed over to the evaluation mechanism.
11552 */
11553 if (contextObj == NULL)
11554 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11555 else
11556 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11557 contextNode);
11558
11559 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011560
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011561 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011562
William M. Brack0bcec062007-02-14 02:15:19 +000011563 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11564 xmlXPathNodeSetClear(set, hasNsNodes);
11565 newContextSize = 0;
11566 goto evaluation_exit;
11567 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011568
11569 if (res != 0) {
11570 newContextSize++;
11571 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011572 /*
11573 * Remove the entry from the initial node set.
11574 */
11575 set->nodeTab[i] = NULL;
11576 if (contextNode->type == XML_NAMESPACE_DECL)
11577 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011578 }
11579 if (ctxt->value == contextObj) {
11580 /*
11581 * Don't free the temporary XPath object holding the
11582 * context node, in order to avoid massive recreation
11583 * inside this loop.
11584 */
11585 valuePop(ctxt);
11586 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11587 } else {
11588 /*
11589 * TODO: The object was lost in the evaluation machinery.
11590 * Can this happen? Maybe in internal-error cases.
11591 */
11592 contextObj = NULL;
11593 }
11594 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011595
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011596 if (contextObj != NULL) {
11597 if (ctxt->value == contextObj)
11598 valuePop(ctxt);
11599 xmlXPathReleaseObject(xpctxt, contextObj);
11600 }
William M. Brack0bcec062007-02-14 02:15:19 +000011601evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011602 if (exprRes != NULL)
11603 xmlXPathReleaseObject(ctxt->context, exprRes);
11604 /*
11605 * Reset/invalidate the context.
11606 */
11607 xpctxt->node = oldContextNode;
11608 xpctxt->doc = oldContextDoc;
11609 xpctxt->contextSize = -1;
11610 xpctxt->proximityPosition = -1;
11611 return(newContextSize);
11612 }
11613 return(contextSize);
11614}
11615
11616static int
11617xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11618 xmlXPathStepOpPtr op,
11619 xmlNodeSetPtr set,
11620 int contextSize,
11621 int minPos,
11622 int maxPos,
11623 int hasNsNodes)
11624{
11625 if (op->ch1 != -1) {
11626 xmlXPathCompExprPtr comp = ctxt->comp;
11627 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11628 /*
11629 * TODO: raise an internal error.
11630 */
11631 }
11632 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11633 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11634 CHECK_ERROR0;
11635 if (contextSize <= 0)
11636 return(0);
11637 }
11638 /*
11639 * Check if the node set contains a sufficient number of nodes for
11640 * the requested range.
11641 */
11642 if (contextSize < minPos) {
11643 xmlXPathNodeSetClear(set, hasNsNodes);
11644 return(0);
11645 }
11646 if (op->ch2 == -1) {
11647 /*
11648 * TODO: Can this ever happen?
11649 */
11650 return (contextSize);
11651 } else {
11652 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011653 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011654 xmlXPathStepOpPtr exprOp;
11655 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11656 xmlNodePtr oldContextNode, contextNode = NULL;
11657 xmlXPathContextPtr xpctxt = ctxt->context;
11658
11659#ifdef LIBXML_XPTR_ENABLED
11660 /*
11661 * URGENT TODO: Check the following:
11662 * We don't expect location sets if evaluating prediates, right?
11663 * Only filters should expect location sets, right?
11664 */
11665#endif /* LIBXML_XPTR_ENABLED */
11666
11667 /*
11668 * Save old context.
11669 */
11670 oldContextNode = xpctxt->node;
11671 oldContextDoc = xpctxt->doc;
11672 /*
11673 * Get the expression of this predicate.
11674 */
11675 exprOp = &ctxt->comp->steps[op->ch2];
11676 for (i = 0; i < set->nodeNr; i++) {
11677 if (set->nodeTab[i] == NULL)
11678 continue;
11679
11680 contextNode = set->nodeTab[i];
11681 xpctxt->node = contextNode;
11682 xpctxt->contextSize = contextSize;
11683 xpctxt->proximityPosition = ++contextPos;
11684
11685 /*
11686 * Initialize the new set.
11687 * Also set the xpath document in case things like
11688 * key() evaluation are attempted on the predicate
11689 */
11690 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11691 (contextNode->doc != NULL))
11692 xpctxt->doc = contextNode->doc;
11693 /*
11694 * Evaluate the predicate expression with 1 context node
11695 * at a time; this node is packaged into a node set; this
11696 * node set is handed over to the evaluation mechanism.
11697 */
11698 if (contextObj == NULL)
11699 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11700 else
11701 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11702 contextNode);
11703
11704 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011705 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011706
11707 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011708 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011709
11710 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011711 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011712
11713 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011714 /*
11715 * Fits in the requested range.
11716 */
11717 newContextSize++;
11718 if (minPos == maxPos) {
11719 /*
11720 * Only 1 node was requested.
11721 */
11722 if (contextNode->type == XML_NAMESPACE_DECL) {
11723 /*
11724 * As always: take care of those nasty
11725 * namespace nodes.
11726 */
11727 set->nodeTab[i] = NULL;
11728 }
11729 xmlXPathNodeSetClear(set, hasNsNodes);
11730 set->nodeNr = 1;
11731 set->nodeTab[0] = contextNode;
11732 goto evaluation_exit;
11733 }
11734 if (pos == maxPos) {
11735 /*
11736 * We are done.
11737 */
11738 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11739 goto evaluation_exit;
11740 }
11741 } else {
11742 /*
11743 * Remove the entry from the initial node set.
11744 */
11745 set->nodeTab[i] = NULL;
11746 if (contextNode->type == XML_NAMESPACE_DECL)
11747 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11748 }
11749 if (exprRes != NULL) {
11750 xmlXPathReleaseObject(ctxt->context, exprRes);
11751 exprRes = NULL;
11752 }
11753 if (ctxt->value == contextObj) {
11754 /*
11755 * Don't free the temporary XPath object holding the
11756 * context node, in order to avoid massive recreation
11757 * inside this loop.
11758 */
11759 valuePop(ctxt);
11760 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11761 } else {
11762 /*
11763 * The object was lost in the evaluation machinery.
11764 * Can this happen? Maybe in case of internal-errors.
11765 */
11766 contextObj = NULL;
11767 }
11768 }
11769 goto evaluation_exit;
11770
11771evaluation_error:
11772 xmlXPathNodeSetClear(set, hasNsNodes);
11773 newContextSize = 0;
11774
11775evaluation_exit:
11776 if (contextObj != NULL) {
11777 if (ctxt->value == contextObj)
11778 valuePop(ctxt);
11779 xmlXPathReleaseObject(xpctxt, contextObj);
11780 }
11781 if (exprRes != NULL)
11782 xmlXPathReleaseObject(ctxt->context, exprRes);
11783 /*
11784 * Reset/invalidate the context.
11785 */
11786 xpctxt->node = oldContextNode;
11787 xpctxt->doc = oldContextDoc;
11788 xpctxt->contextSize = -1;
11789 xpctxt->proximityPosition = -1;
11790 return(newContextSize);
11791 }
11792 return(contextSize);
11793}
11794
11795static int
11796xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11797 xmlXPathStepOpPtr op,
11798 int *maxPos)
11799{
11800
11801 xmlXPathStepOpPtr exprOp;
11802
11803 /*
11804 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11805 */
11806
11807 /*
11808 * If not -1, then ch1 will point to:
11809 * 1) For predicates (XPATH_OP_PREDICATE):
11810 * - an inner predicate operator
11811 * 2) For filters (XPATH_OP_FILTER):
11812 * - an inner filter operater OR
11813 * - an expression selecting the node set.
11814 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11815 */
11816 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11817 return(0);
11818
11819 if (op->ch2 != -1) {
11820 exprOp = &ctxt->comp->steps[op->ch2];
11821 } else
11822 return(0);
11823
11824 if ((exprOp != NULL) &&
11825 (exprOp->op == XPATH_OP_VALUE) &&
11826 (exprOp->value4 != NULL) &&
11827 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11828 {
11829 /*
11830 * We have a "[n]" predicate here.
11831 * TODO: Unfortunately this simplistic test here is not
11832 * able to detect a position() predicate in compound
11833 * expressions like "[@attr = 'a" and position() = 1],
11834 * and even not the usage of position() in
11835 * "[position() = 1]"; thus - obviously - a position-range,
11836 * like it "[position() < 5]", is also not detected.
11837 * Maybe we could rewrite the AST to ease the optimization.
11838 */
11839 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11840
11841 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11842 (float) *maxPos)
11843 {
11844 return(1);
11845 }
11846 }
11847 return(0);
11848}
11849
11850static int
11851xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11852 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011853 xmlNodePtr * first, xmlNodePtr * last,
11854 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011855{
11856
11857#define XP_TEST_HIT \
11858 if (hasAxisRange != 0) { \
11859 if (++pos == maxPos) { \
11860 addNode(seq, cur); \
11861 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011862 } else { \
11863 addNode(seq, cur); \
11864 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011865
11866#define XP_TEST_HIT_NS \
11867 if (hasAxisRange != 0) { \
11868 if (++pos == maxPos) { \
11869 hasNsNodes = 1; \
11870 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11871 goto axis_range_end; } \
11872 } else { \
11873 hasNsNodes = 1; \
11874 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011875 xpctxt->node, (xmlNsPtr) cur); \
11876 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011877
11878 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11879 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11880 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11881 const xmlChar *prefix = op->value4;
11882 const xmlChar *name = op->value5;
11883 const xmlChar *URI = NULL;
11884
11885#ifdef DEBUG_STEP
11886 int nbMatches = 0, prevMatches = 0;
11887#endif
11888 int total = 0, hasNsNodes = 0;
11889 /* The popped object holding the context nodes */
11890 xmlXPathObjectPtr obj;
11891 /* The set of context nodes for the node tests */
11892 xmlNodeSetPtr contextSeq;
11893 int contextIdx;
11894 xmlNodePtr contextNode;
11895 /* The context node for a compound traversal */
11896 xmlNodePtr outerContextNode;
11897 /* The final resulting node set wrt to all context nodes */
11898 xmlNodeSetPtr outSeq;
11899 /*
11900 * The temporary resulting node set wrt 1 context node.
11901 * Used to feed predicate evaluation.
11902 */
11903 xmlNodeSetPtr seq;
11904 xmlNodePtr cur;
11905 /* First predicate operator */
11906 xmlXPathStepOpPtr predOp;
11907 int maxPos; /* The requested position() (when a "[n]" predicate) */
11908 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011909 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011910
11911 xmlXPathTraversalFunction next = NULL;
11912 /* compound axis traversal */
11913 xmlXPathTraversalFunctionExt outerNext = NULL;
11914 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11915 xmlXPathNodeSetMergeFunction mergeAndClear;
11916 xmlNodePtr oldContextNode;
11917 xmlXPathContextPtr xpctxt = ctxt->context;
11918
11919
11920 CHECK_TYPE0(XPATH_NODESET);
11921 obj = valuePop(ctxt);
11922 /*
11923 * Setup namespaces.
11924 */
11925 if (prefix != NULL) {
11926 URI = xmlXPathNsLookup(xpctxt, prefix);
11927 if (URI == NULL) {
11928 xmlXPathReleaseObject(xpctxt, obj);
11929 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11930 }
11931 }
11932 /*
11933 * Setup axis.
11934 *
11935 * MAYBE FUTURE TODO: merging optimizations:
11936 * - If the nodes to be traversed wrt to the initial nodes and
11937 * the current axis cannot overlap, then we could avoid searching
11938 * for duplicates during the merge.
11939 * But the question is how/when to evaluate if they cannot overlap.
11940 * Example: if we know that for two initial nodes, the one is
11941 * not in the ancestor-or-self axis of the other, then we could safely
11942 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11943 * the descendant-or-self axis.
11944 */
11945 addNode = xmlXPathNodeSetAdd;
11946 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11947 switch (axis) {
11948 case AXIS_ANCESTOR:
11949 first = NULL;
11950 next = xmlXPathNextAncestor;
11951 break;
11952 case AXIS_ANCESTOR_OR_SELF:
11953 first = NULL;
11954 next = xmlXPathNextAncestorOrSelf;
11955 break;
11956 case AXIS_ATTRIBUTE:
11957 first = NULL;
11958 last = NULL;
11959 next = xmlXPathNextAttribute;
11960 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11961 break;
11962 case AXIS_CHILD:
11963 last = NULL;
11964 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11965 /*
11966 * This iterator will give us only nodes which can
11967 * hold element nodes.
11968 */
11969 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11970 }
11971 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11972 (type == NODE_TYPE_NODE))
11973 {
11974 /*
11975 * Optimization if an element node type is 'element'.
11976 */
11977 next = xmlXPathNextChildElement;
11978 } else
11979 next = xmlXPathNextChild;
11980 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11981 break;
11982 case AXIS_DESCENDANT:
11983 last = NULL;
11984 next = xmlXPathNextDescendant;
11985 break;
11986 case AXIS_DESCENDANT_OR_SELF:
11987 last = NULL;
11988 next = xmlXPathNextDescendantOrSelf;
11989 break;
11990 case AXIS_FOLLOWING:
11991 last = NULL;
11992 next = xmlXPathNextFollowing;
11993 break;
11994 case AXIS_FOLLOWING_SIBLING:
11995 last = NULL;
11996 next = xmlXPathNextFollowingSibling;
11997 break;
11998 case AXIS_NAMESPACE:
11999 first = NULL;
12000 last = NULL;
12001 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12002 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12003 break;
12004 case AXIS_PARENT:
12005 first = NULL;
12006 next = xmlXPathNextParent;
12007 break;
12008 case AXIS_PRECEDING:
12009 first = NULL;
12010 next = xmlXPathNextPrecedingInternal;
12011 break;
12012 case AXIS_PRECEDING_SIBLING:
12013 first = NULL;
12014 next = xmlXPathNextPrecedingSibling;
12015 break;
12016 case AXIS_SELF:
12017 first = NULL;
12018 last = NULL;
12019 next = xmlXPathNextSelf;
12020 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12021 break;
12022 }
12023
12024#ifdef DEBUG_STEP
12025 xmlXPathDebugDumpStepAxis(axis, test,
12026 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12027#endif
12028
12029 if (next == NULL) {
12030 xmlXPathReleaseObject(xpctxt, obj);
12031 return(0);
12032 }
12033 contextSeq = obj->nodesetval;
12034 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12035 xmlXPathReleaseObject(xpctxt, obj);
12036 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12037 return(0);
12038 }
12039 /*
12040 * Predicate optimization ---------------------------------------------
12041 * If this step has a last predicate, which contains a position(),
12042 * then we'll optimize (although not exactly "position()", but only
12043 * the short-hand form, i.e., "[n]".
12044 *
12045 * Example - expression "/foo[parent::bar][1]":
12046 *
12047 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12048 * ROOT -- op->ch1
12049 * PREDICATE -- op->ch2 (predOp)
12050 * PREDICATE -- predOp->ch1 = [parent::bar]
12051 * SORT
12052 * COLLECT 'parent' 'name' 'node' bar
12053 * NODE
12054 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12055 *
12056 */
12057 maxPos = 0;
12058 predOp = NULL;
12059 hasPredicateRange = 0;
12060 hasAxisRange = 0;
12061 if (op->ch2 != -1) {
12062 /*
12063 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12064 */
12065 predOp = &ctxt->comp->steps[op->ch2];
12066 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12067 if (predOp->ch1 != -1) {
12068 /*
12069 * Use the next inner predicate operator.
12070 */
12071 predOp = &ctxt->comp->steps[predOp->ch1];
12072 hasPredicateRange = 1;
12073 } else {
12074 /*
12075 * There's no other predicate than the [n] predicate.
12076 */
12077 predOp = NULL;
12078 hasAxisRange = 1;
12079 }
12080 }
12081 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012082 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012083 /*
12084 * Axis traversal -----------------------------------------------------
12085 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012086 /*
12087 * 2.3 Node Tests
12088 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089 * - For the namespace axis, the principal node type is namespace.
12090 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012091 *
12092 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012093 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012094 * select all element children of the context node
12095 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012096 oldContextNode = xpctxt->node;
12097 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012098 outSeq = NULL;
12099 seq = NULL;
12100 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012101 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012102 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012103
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012104
12105 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12106 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012107 /*
12108 * This is a compound traversal.
12109 */
12110 if (contextNode == NULL) {
12111 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012112 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012113 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 outerContextNode = contextSeq->nodeTab[contextIdx++];
12115 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012116 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012117 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012118 if (contextNode == NULL)
12119 continue;
12120 /*
12121 * Set the context for the main traversal.
12122 */
12123 xpctxt->node = contextNode;
12124 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012125 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012126
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012127 if (seq == NULL) {
12128 seq = xmlXPathNodeSetCreate(NULL);
12129 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012130 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012131 goto error;
12132 }
12133 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012134 /*
12135 * Traverse the axis and test the nodes.
12136 */
12137 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012138 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012139 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012140 do {
12141 cur = next(ctxt, cur);
12142 if (cur == NULL)
12143 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012144
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012145 /*
12146 * QUESTION TODO: What does the "first" and "last" stuff do?
12147 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012148 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012149 if (*first == cur)
12150 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012151 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012152#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012153 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012154#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012155 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012156#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012157 {
12158 break;
12159 }
12160 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012161 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012162 if (*last == cur)
12163 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012164 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012165#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012166 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012167#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012168 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012169#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012170 {
12171 break;
12172 }
12173 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012174
12175 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012176
Daniel Veillardf06307e2001-07-03 10:35:50 +000012177#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012178 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12179#endif
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012180
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012181 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012182 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012183 total = 0;
12184 STRANGE
12185 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012186 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012187 /*
12188 * TODO: Don't we need to use
12189 * xmlXPathNodeSetAddNs() for namespace nodes here?
12190 * Surprisingly, some c14n tests fail, if we do this.
12191 */
12192 if (type == NODE_TYPE_NODE) {
12193 switch (cur->type) {
12194 case XML_DOCUMENT_NODE:
12195 case XML_HTML_DOCUMENT_NODE:
12196#ifdef LIBXML_DOCB_ENABLED
12197 case XML_DOCB_DOCUMENT_NODE:
12198#endif
12199 case XML_ELEMENT_NODE:
12200 case XML_ATTRIBUTE_NODE:
12201 case XML_PI_NODE:
12202 case XML_COMMENT_NODE:
12203 case XML_CDATA_SECTION_NODE:
12204 case XML_TEXT_NODE:
12205 case XML_NAMESPACE_DECL:
12206 XP_TEST_HIT
12207 break;
12208 default:
12209 break;
12210 }
12211 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012212 if (type == XML_NAMESPACE_DECL)
12213 XP_TEST_HIT_NS
12214 else
12215 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012216 } else if ((type == NODE_TYPE_TEXT) &&
12217 (cur->type == XML_CDATA_SECTION_NODE))
12218 {
12219 XP_TEST_HIT
12220 }
12221 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012222 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012223 if ((cur->type == XML_PI_NODE) &&
12224 ((name == NULL) || xmlStrEqual(name, cur->name)))
12225 {
12226 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012227 }
12228 break;
12229 case NODE_TEST_ALL:
12230 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012231 if (cur->type == XML_ATTRIBUTE_NODE)
12232 {
12233 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012234 }
12235 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012236 if (cur->type == XML_NAMESPACE_DECL)
12237 {
12238 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012239 }
12240 } else {
12241 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012242 if (prefix == NULL)
12243 {
12244 XP_TEST_HIT
12245
Daniel Veillardf06307e2001-07-03 10:35:50 +000012246 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012247 (xmlStrEqual(URI, cur->ns->href)))
12248 {
12249 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012250 }
12251 }
12252 }
12253 break;
12254 case NODE_TEST_NS:{
12255 TODO;
12256 break;
12257 }
12258 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012259 if (axis == AXIS_ATTRIBUTE) {
12260 if (cur->type != XML_ATTRIBUTE_NODE)
12261 break;
12262 } else if (axis == AXIS_NAMESPACE) {
12263 if (cur->type != XML_NAMESPACE_DECL)
12264 break;
12265 } else {
12266 if (cur->type != XML_ELEMENT_NODE)
12267 break;
12268 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012269 switch (cur->type) {
12270 case XML_ELEMENT_NODE:
12271 if (xmlStrEqual(name, cur->name)) {
12272 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012273 if (cur->ns == NULL)
12274 {
12275 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012276 }
12277 } else {
12278 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012279 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012280 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012281 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012282 }
12283 }
12284 }
12285 break;
12286 case XML_ATTRIBUTE_NODE:{
12287 xmlAttrPtr attr = (xmlAttrPtr) cur;
12288
12289 if (xmlStrEqual(name, attr->name)) {
12290 if (prefix == NULL) {
12291 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012292 (attr->ns->prefix == NULL))
12293 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012294 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012295 }
12296 } else {
12297 if ((attr->ns != NULL) &&
12298 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012299 attr->ns->href)))
12300 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012301 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012302 }
12303 }
12304 }
12305 break;
12306 }
12307 case XML_NAMESPACE_DECL:
12308 if (cur->type == XML_NAMESPACE_DECL) {
12309 xmlNsPtr ns = (xmlNsPtr) cur;
12310
12311 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012312 && (xmlStrEqual(ns->prefix, name)))
12313 {
12314 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012315 }
12316 }
12317 break;
12318 default:
12319 break;
12320 }
12321 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012322 } /* switch(test) */
12323 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012324
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012325 goto apply_predicates;
12326
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012327axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012328 /*
12329 * We have a "/foo[n]", and position() = n was reached.
12330 * Note that we can have as well "/foo/::parent::foo[1]", so
12331 * a duplicate-aware merge is still needed.
12332 * Merge with the result.
12333 */
12334 if (outSeq == NULL) {
12335 outSeq = seq;
12336 seq = NULL;
12337 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012338 outSeq = mergeAndClear(outSeq, seq, 0);
12339 /*
12340 * Break if only a true/false result was requested.
12341 */
12342 if (toBool)
12343 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012344 continue;
12345
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012346first_hit: /* ---------------------------------------------------------- */
12347 /*
12348 * Break if only a true/false result was requested and
12349 * no predicates existed and a node test succeeded.
12350 */
12351 if (outSeq == NULL) {
12352 outSeq = seq;
12353 seq = NULL;
12354 } else
12355 outSeq = mergeAndClear(outSeq, seq, 0);
12356 break;
12357
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012358#ifdef DEBUG_STEP
12359 if (seq != NULL)
12360 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012361#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012362
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012363apply_predicates: /* --------------------------------------------------- */
12364 /*
12365 * Apply predicates.
12366 */
12367 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12368 /*
12369 * E.g. when we have a "/foo[some expression][n]".
12370 */
12371 /*
12372 * QUESTION TODO: The old predicate evaluation took into
12373 * account location-sets.
12374 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12375 * Do we expect such a set here?
12376 * All what I learned now from the evaluation semantics
12377 * does not indicate that a location-set will be processed
12378 * here, so this looks OK.
12379 */
12380 /*
12381 * Iterate over all predicates, starting with the outermost
12382 * predicate.
12383 * TODO: Problem: we cannot execute the inner predicates first
12384 * since we cannot go back *up* the operator tree!
12385 * Options we have:
12386 * 1) Use of recursive functions (like is it currently done
12387 * via xmlXPathCompOpEval())
12388 * 2) Add a predicate evaluation information stack to the
12389 * context struct
12390 * 3) Change the way the operators are linked; we need a
12391 * "parent" field on xmlXPathStepOp
12392 *
12393 * For the moment, I'll try to solve this with a recursive
12394 * function: xmlXPathCompOpEvalPredicate().
12395 */
12396 size = seq->nodeNr;
12397 if (hasPredicateRange != 0)
12398 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12399 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12400 else
12401 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12402 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012403
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012404 if (ctxt->error != XPATH_EXPRESSION_OK) {
12405 total = 0;
12406 goto error;
12407 }
12408 /*
12409 * Add the filtered set of nodes to the result node set.
12410 */
12411 if (newSize == 0) {
12412 /*
12413 * The predicates filtered all nodes out.
12414 */
12415 xmlXPathNodeSetClear(seq, hasNsNodes);
12416 } else if (seq->nodeNr > 0) {
12417 /*
12418 * Add to result set.
12419 */
12420 if (outSeq == NULL) {
12421 if (size != newSize) {
12422 /*
12423 * We need to merge and clear here, since
12424 * the sequence will contained NULLed entries.
12425 */
12426 outSeq = mergeAndClear(NULL, seq, 1);
12427 } else {
12428 outSeq = seq;
12429 seq = NULL;
12430 }
12431 } else
12432 outSeq = mergeAndClear(outSeq, seq,
12433 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012434 /*
12435 * Break if only a true/false result was requested.
12436 */
12437 if (toBool)
12438 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012439 }
12440 } else if (seq->nodeNr > 0) {
12441 /*
12442 * Add to result set.
12443 */
12444 if (outSeq == NULL) {
12445 outSeq = seq;
12446 seq = NULL;
12447 } else {
12448 outSeq = mergeAndClear(outSeq, seq, 0);
12449 }
12450 }
12451 }
12452
12453error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012454 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012455 /*
12456 * QUESTION TODO: What does this do and why?
12457 * TODO: Do we have to do this also for the "error"
12458 * cleanup further down?
12459 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012460 ctxt->value->boolval = 1;
12461 ctxt->value->user = obj->user;
12462 obj->user = NULL;
12463 obj->boolval = 0;
12464 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012465 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012466
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012467 /*
12468 * Ensure we return at least an emtpy set.
12469 */
12470 if (outSeq == NULL) {
12471 if ((seq != NULL) && (seq->nodeNr == 0))
12472 outSeq = seq;
12473 else
12474 outSeq = xmlXPathNodeSetCreate(NULL);
12475 }
12476 if ((seq != NULL) && (seq != outSeq)) {
12477 xmlXPathFreeNodeSet(seq);
12478 }
12479 /*
12480 * Hand over the result. Better to push the set also in
12481 * case of errors.
12482 */
12483 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12484 /*
12485 * Reset the context node.
12486 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012487 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012488
12489#ifdef DEBUG_STEP
12490 xmlGenericError(xmlGenericErrorContext,
12491 "\nExamined %d nodes, found %d nodes at that step\n",
12492 total, nbMatches);
12493#endif
12494
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012495 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012496}
12497
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012498static int
12499xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12500 xmlXPathStepOpPtr op, xmlNodePtr * first);
12501
Daniel Veillardf06307e2001-07-03 10:35:50 +000012502/**
12503 * xmlXPathCompOpEvalFirst:
12504 * @ctxt: the XPath parser context with the compiled expression
12505 * @op: an XPath compiled operation
12506 * @first: the first elem found so far
12507 *
12508 * Evaluate the Precompiled XPath operation searching only the first
12509 * element in document order
12510 *
12511 * Returns the number of examined objects.
12512 */
12513static int
12514xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12515 xmlXPathStepOpPtr op, xmlNodePtr * first)
12516{
12517 int total = 0, cur;
12518 xmlXPathCompExprPtr comp;
12519 xmlXPathObjectPtr arg1, arg2;
12520
Daniel Veillard556c6682001-10-06 09:59:51 +000012521 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012522 comp = ctxt->comp;
12523 switch (op->op) {
12524 case XPATH_OP_END:
12525 return (0);
12526 case XPATH_OP_UNION:
12527 total =
12528 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12529 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012530 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012531 if ((ctxt->value != NULL)
12532 && (ctxt->value->type == XPATH_NODESET)
12533 && (ctxt->value->nodesetval != NULL)
12534 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12535 /*
12536 * limit tree traversing to first node in the result
12537 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012538 /*
12539 * OPTIMIZE TODO: This implicitely sorts
12540 * the result, even if not needed. E.g. if the argument
12541 * of the count() function, no sorting is needed.
12542 * OPTIMIZE TODO: How do we know if the node-list wasn't
12543 * aready sorted?
12544 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012545 if (ctxt->value->nodesetval->nodeNr > 1)
12546 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012547 *first = ctxt->value->nodesetval->nodeTab[0];
12548 }
12549 cur =
12550 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12551 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012552 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012553 CHECK_TYPE0(XPATH_NODESET);
12554 arg2 = valuePop(ctxt);
12555
12556 CHECK_TYPE0(XPATH_NODESET);
12557 arg1 = valuePop(ctxt);
12558
12559 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12560 arg2->nodesetval);
12561 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012562 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012563 /* optimizer */
12564 if (total > cur)
12565 xmlXPathCompSwap(op);
12566 return (total + cur);
12567 case XPATH_OP_ROOT:
12568 xmlXPathRoot(ctxt);
12569 return (0);
12570 case XPATH_OP_NODE:
12571 if (op->ch1 != -1)
12572 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012573 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012574 if (op->ch2 != -1)
12575 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012576 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012577 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12578 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012579 return (total);
12580 case XPATH_OP_RESET:
12581 if (op->ch1 != -1)
12582 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012583 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012584 if (op->ch2 != -1)
12585 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012586 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012587 ctxt->context->node = NULL;
12588 return (total);
12589 case XPATH_OP_COLLECT:{
12590 if (op->ch1 == -1)
12591 return (total);
12592
12593 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012594 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012595
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012596 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012597 return (total);
12598 }
12599 case XPATH_OP_VALUE:
12600 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012601 xmlXPathCacheObjectCopy(ctxt->context,
12602 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012603 return (0);
12604 case XPATH_OP_SORT:
12605 if (op->ch1 != -1)
12606 total +=
12607 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12608 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012609 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012610 if ((ctxt->value != NULL)
12611 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012612 && (ctxt->value->nodesetval != NULL)
12613 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012614 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12615 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012616#ifdef XP_OPTIMIZED_FILTER_FIRST
12617 case XPATH_OP_FILTER:
12618 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12619 return (total);
12620#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012621 default:
12622 return (xmlXPathCompOpEval(ctxt, op));
12623 }
12624}
12625
12626/**
12627 * xmlXPathCompOpEvalLast:
12628 * @ctxt: the XPath parser context with the compiled expression
12629 * @op: an XPath compiled operation
12630 * @last: the last elem found so far
12631 *
12632 * Evaluate the Precompiled XPath operation searching only the last
12633 * element in document order
12634 *
William M. Brack08171912003-12-29 02:52:11 +000012635 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012636 */
12637static int
12638xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12639 xmlNodePtr * last)
12640{
12641 int total = 0, cur;
12642 xmlXPathCompExprPtr comp;
12643 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012644 xmlNodePtr bak;
12645 xmlDocPtr bakd;
12646 int pp;
12647 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012648
Daniel Veillard556c6682001-10-06 09:59:51 +000012649 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012650 comp = ctxt->comp;
12651 switch (op->op) {
12652 case XPATH_OP_END:
12653 return (0);
12654 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012655 bakd = ctxt->context->doc;
12656 bak = ctxt->context->node;
12657 pp = ctxt->context->proximityPosition;
12658 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012659 total =
12660 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012661 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012662 if ((ctxt->value != NULL)
12663 && (ctxt->value->type == XPATH_NODESET)
12664 && (ctxt->value->nodesetval != NULL)
12665 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12666 /*
12667 * limit tree traversing to first node in the result
12668 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012669 if (ctxt->value->nodesetval->nodeNr > 1)
12670 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012671 *last =
12672 ctxt->value->nodesetval->nodeTab[ctxt->value->
12673 nodesetval->nodeNr -
12674 1];
12675 }
William M. Brackce4fc562004-01-22 02:47:18 +000012676 ctxt->context->doc = bakd;
12677 ctxt->context->node = bak;
12678 ctxt->context->proximityPosition = pp;
12679 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012680 cur =
12681 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012682 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012683 if ((ctxt->value != NULL)
12684 && (ctxt->value->type == XPATH_NODESET)
12685 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012686 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012687 }
12688 CHECK_TYPE0(XPATH_NODESET);
12689 arg2 = valuePop(ctxt);
12690
12691 CHECK_TYPE0(XPATH_NODESET);
12692 arg1 = valuePop(ctxt);
12693
12694 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12695 arg2->nodesetval);
12696 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012697 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012698 /* optimizer */
12699 if (total > cur)
12700 xmlXPathCompSwap(op);
12701 return (total + cur);
12702 case XPATH_OP_ROOT:
12703 xmlXPathRoot(ctxt);
12704 return (0);
12705 case XPATH_OP_NODE:
12706 if (op->ch1 != -1)
12707 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 if (op->ch2 != -1)
12710 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012711 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012712 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12713 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012714 return (total);
12715 case XPATH_OP_RESET:
12716 if (op->ch1 != -1)
12717 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012718 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012719 if (op->ch2 != -1)
12720 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012721 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012722 ctxt->context->node = NULL;
12723 return (total);
12724 case XPATH_OP_COLLECT:{
12725 if (op->ch1 == -1)
12726 return (0);
12727
12728 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012729 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012730
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012731 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012732 return (total);
12733 }
12734 case XPATH_OP_VALUE:
12735 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012736 xmlXPathCacheObjectCopy(ctxt->context,
12737 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012738 return (0);
12739 case XPATH_OP_SORT:
12740 if (op->ch1 != -1)
12741 total +=
12742 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12743 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012744 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012745 if ((ctxt->value != NULL)
12746 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012747 && (ctxt->value->nodesetval != NULL)
12748 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012749 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12750 return (total);
12751 default:
12752 return (xmlXPathCompOpEval(ctxt, op));
12753 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012754}
12755
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012756#ifdef XP_OPTIMIZED_FILTER_FIRST
12757static int
12758xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12759 xmlXPathStepOpPtr op, xmlNodePtr * first)
12760{
12761 int total = 0;
12762 xmlXPathCompExprPtr comp;
12763 xmlXPathObjectPtr res;
12764 xmlXPathObjectPtr obj;
12765 xmlNodeSetPtr oldset;
12766 xmlNodePtr oldnode;
12767 xmlDocPtr oldDoc;
12768 int i;
12769
12770 CHECK_ERROR0;
12771 comp = ctxt->comp;
12772 /*
12773 * Optimization for ()[last()] selection i.e. the last elem
12774 */
12775 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12776 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12777 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12778 int f = comp->steps[op->ch2].ch1;
12779
12780 if ((f != -1) &&
12781 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12782 (comp->steps[f].value5 == NULL) &&
12783 (comp->steps[f].value == 0) &&
12784 (comp->steps[f].value4 != NULL) &&
12785 (xmlStrEqual
12786 (comp->steps[f].value4, BAD_CAST "last"))) {
12787 xmlNodePtr last = NULL;
12788
12789 total +=
12790 xmlXPathCompOpEvalLast(ctxt,
12791 &comp->steps[op->ch1],
12792 &last);
12793 CHECK_ERROR0;
12794 /*
12795 * The nodeset should be in document order,
12796 * Keep only the last value
12797 */
12798 if ((ctxt->value != NULL) &&
12799 (ctxt->value->type == XPATH_NODESET) &&
12800 (ctxt->value->nodesetval != NULL) &&
12801 (ctxt->value->nodesetval->nodeTab != NULL) &&
12802 (ctxt->value->nodesetval->nodeNr > 1)) {
12803 ctxt->value->nodesetval->nodeTab[0] =
12804 ctxt->value->nodesetval->nodeTab[ctxt->
12805 value->
12806 nodesetval->
12807 nodeNr -
12808 1];
12809 ctxt->value->nodesetval->nodeNr = 1;
12810 *first = *(ctxt->value->nodesetval->nodeTab);
12811 }
12812 return (total);
12813 }
12814 }
12815
12816 if (op->ch1 != -1)
12817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12818 CHECK_ERROR0;
12819 if (op->ch2 == -1)
12820 return (total);
12821 if (ctxt->value == NULL)
12822 return (total);
12823
12824#ifdef LIBXML_XPTR_ENABLED
12825 oldnode = ctxt->context->node;
12826 /*
12827 * Hum are we filtering the result of an XPointer expression
12828 */
12829 if (ctxt->value->type == XPATH_LOCATIONSET) {
12830 xmlXPathObjectPtr tmp = NULL;
12831 xmlLocationSetPtr newlocset = NULL;
12832 xmlLocationSetPtr oldlocset;
12833
12834 /*
12835 * Extract the old locset, and then evaluate the result of the
12836 * expression for all the element in the locset. use it to grow
12837 * up a new locset.
12838 */
12839 CHECK_TYPE0(XPATH_LOCATIONSET);
12840 obj = valuePop(ctxt);
12841 oldlocset = obj->user;
12842 ctxt->context->node = NULL;
12843
12844 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12845 ctxt->context->contextSize = 0;
12846 ctxt->context->proximityPosition = 0;
12847 if (op->ch2 != -1)
12848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12849 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012850 if (res != NULL) {
12851 xmlXPathReleaseObject(ctxt->context, res);
12852 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012853 valuePush(ctxt, obj);
12854 CHECK_ERROR0;
12855 return (total);
12856 }
12857 newlocset = xmlXPtrLocationSetCreate(NULL);
12858
12859 for (i = 0; i < oldlocset->locNr; i++) {
12860 /*
12861 * Run the evaluation with a node list made of a
12862 * single item in the nodelocset.
12863 */
12864 ctxt->context->node = oldlocset->locTab[i]->user;
12865 ctxt->context->contextSize = oldlocset->locNr;
12866 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012867 if (tmp == NULL) {
12868 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12869 ctxt->context->node);
12870 } else {
12871 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12872 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012873 }
12874 valuePush(ctxt, tmp);
12875 if (op->ch2 != -1)
12876 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12877 if (ctxt->error != XPATH_EXPRESSION_OK) {
12878 xmlXPathFreeObject(obj);
12879 return(0);
12880 }
12881 /*
12882 * The result of the evaluation need to be tested to
12883 * decided whether the filter succeeded or not
12884 */
12885 res = valuePop(ctxt);
12886 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12887 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012888 xmlXPathCacheObjectCopy(ctxt->context,
12889 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012890 }
12891 /*
12892 * Cleanup
12893 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012894 if (res != NULL) {
12895 xmlXPathReleaseObject(ctxt->context, res);
12896 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012897 if (ctxt->value == tmp) {
12898 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012899 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012900 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012901 * REVISIT TODO: Don't create a temporary nodeset
12902 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012903 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012904 /* OLD: xmlXPathFreeObject(res); */
12905 } else
12906 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012907 ctxt->context->node = NULL;
12908 /*
12909 * Only put the first node in the result, then leave.
12910 */
12911 if (newlocset->locNr > 0) {
12912 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12913 break;
12914 }
12915 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012916 if (tmp != NULL) {
12917 xmlXPathReleaseObject(ctxt->context, tmp);
12918 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012919 /*
12920 * The result is used as the new evaluation locset.
12921 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012922 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012923 ctxt->context->node = NULL;
12924 ctxt->context->contextSize = -1;
12925 ctxt->context->proximityPosition = -1;
12926 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12927 ctxt->context->node = oldnode;
12928 return (total);
12929 }
12930#endif /* LIBXML_XPTR_ENABLED */
12931
12932 /*
12933 * Extract the old set, and then evaluate the result of the
12934 * expression for all the element in the set. use it to grow
12935 * up a new set.
12936 */
12937 CHECK_TYPE0(XPATH_NODESET);
12938 obj = valuePop(ctxt);
12939 oldset = obj->nodesetval;
12940
12941 oldnode = ctxt->context->node;
12942 oldDoc = ctxt->context->doc;
12943 ctxt->context->node = NULL;
12944
12945 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12946 ctxt->context->contextSize = 0;
12947 ctxt->context->proximityPosition = 0;
12948 /* QUESTION TODO: Why was this code commented out?
12949 if (op->ch2 != -1)
12950 total +=
12951 xmlXPathCompOpEval(ctxt,
12952 &comp->steps[op->ch2]);
12953 CHECK_ERROR0;
12954 res = valuePop(ctxt);
12955 if (res != NULL)
12956 xmlXPathFreeObject(res);
12957 */
12958 valuePush(ctxt, obj);
12959 ctxt->context->node = oldnode;
12960 CHECK_ERROR0;
12961 } else {
12962 xmlNodeSetPtr newset;
12963 xmlXPathObjectPtr tmp = NULL;
12964 /*
12965 * Initialize the new set.
12966 * Also set the xpath document in case things like
12967 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012968 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012969 newset = xmlXPathNodeSetCreate(NULL);
12970
12971 for (i = 0; i < oldset->nodeNr; i++) {
12972 /*
12973 * Run the evaluation with a node list made of
12974 * a single item in the nodeset.
12975 */
12976 ctxt->context->node = oldset->nodeTab[i];
12977 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12978 (oldset->nodeTab[i]->doc != NULL))
12979 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012980 if (tmp == NULL) {
12981 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12982 ctxt->context->node);
12983 } else {
12984 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12985 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012986 }
12987 valuePush(ctxt, tmp);
12988 ctxt->context->contextSize = oldset->nodeNr;
12989 ctxt->context->proximityPosition = i + 1;
12990 if (op->ch2 != -1)
12991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12992 if (ctxt->error != XPATH_EXPRESSION_OK) {
12993 xmlXPathFreeNodeSet(newset);
12994 xmlXPathFreeObject(obj);
12995 return(0);
12996 }
12997 /*
12998 * The result of the evaluation needs to be tested to
12999 * decide whether the filter succeeded or not
13000 */
13001 res = valuePop(ctxt);
13002 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13003 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13004 }
13005 /*
13006 * Cleanup
13007 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013008 if (res != NULL) {
13009 xmlXPathReleaseObject(ctxt->context, res);
13010 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013011 if (ctxt->value == tmp) {
13012 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013013 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013014 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013015 * in order to avoid massive recreation inside this
13016 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013017 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013018 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013019 } else
13020 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013021 ctxt->context->node = NULL;
13022 /*
13023 * Only put the first node in the result, then leave.
13024 */
13025 if (newset->nodeNr > 0) {
13026 *first = *(newset->nodeTab);
13027 break;
13028 }
13029 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013030 if (tmp != NULL) {
13031 xmlXPathReleaseObject(ctxt->context, tmp);
13032 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013033 /*
13034 * The result is used as the new evaluation set.
13035 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013036 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013037 ctxt->context->node = NULL;
13038 ctxt->context->contextSize = -1;
13039 ctxt->context->proximityPosition = -1;
13040 /* may want to move this past the '}' later */
13041 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013042 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013043 }
13044 ctxt->context->node = oldnode;
13045 return(total);
13046}
13047#endif /* XP_OPTIMIZED_FILTER_FIRST */
13048
Owen Taylor3473f882001-02-23 17:55:21 +000013049/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013050 * xmlXPathCompOpEval:
13051 * @ctxt: the XPath parser context with the compiled expression
13052 * @op: an XPath compiled operation
13053 *
13054 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013055 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013056 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013057static int
13058xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13059{
13060 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013061 int equal, ret;
13062 xmlXPathCompExprPtr comp;
13063 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013064 xmlNodePtr bak;
13065 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013066 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013067 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013068
Daniel Veillard556c6682001-10-06 09:59:51 +000013069 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013070 comp = ctxt->comp;
13071 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013072 case XPATH_OP_END:
13073 return (0);
13074 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013075 bakd = ctxt->context->doc;
13076 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013077 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013078 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013079 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013080 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013081 xmlXPathBooleanFunction(ctxt, 1);
13082 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13083 return (total);
13084 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013085 ctxt->context->doc = bakd;
13086 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013087 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013088 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013090 if (ctxt->error) {
13091 xmlXPathFreeObject(arg2);
13092 return(0);
13093 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013094 xmlXPathBooleanFunction(ctxt, 1);
13095 arg1 = valuePop(ctxt);
13096 arg1->boolval &= arg2->boolval;
13097 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013098 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013099 return (total);
13100 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013101 bakd = ctxt->context->doc;
13102 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013103 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013104 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013105 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013106 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013107 xmlXPathBooleanFunction(ctxt, 1);
13108 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13109 return (total);
13110 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013111 ctxt->context->doc = bakd;
13112 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013113 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013114 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013116 if (ctxt->error) {
13117 xmlXPathFreeObject(arg2);
13118 return(0);
13119 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013120 xmlXPathBooleanFunction(ctxt, 1);
13121 arg1 = valuePop(ctxt);
13122 arg1->boolval |= arg2->boolval;
13123 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013124 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013125 return (total);
13126 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013127 bakd = ctxt->context->doc;
13128 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013129 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013130 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013132 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013133 ctxt->context->doc = bakd;
13134 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013135 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013136 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013137 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013138 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013139 if (op->value)
13140 equal = xmlXPathEqualValues(ctxt);
13141 else
13142 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013143 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013144 return (total);
13145 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013146 bakd = ctxt->context->doc;
13147 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013148 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013149 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013150 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013151 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013152 ctxt->context->doc = bakd;
13153 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013154 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013155 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013156 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013157 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013158 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013159 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013160 return (total);
13161 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013162 bakd = ctxt->context->doc;
13163 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013164 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013165 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013166 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013167 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013168 if (op->ch2 != -1) {
13169 ctxt->context->doc = bakd;
13170 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013171 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013172 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013174 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013175 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013176 if (op->value == 0)
13177 xmlXPathSubValues(ctxt);
13178 else if (op->value == 1)
13179 xmlXPathAddValues(ctxt);
13180 else if (op->value == 2)
13181 xmlXPathValueFlipSign(ctxt);
13182 else if (op->value == 3) {
13183 CAST_TO_NUMBER;
13184 CHECK_TYPE0(XPATH_NUMBER);
13185 }
13186 return (total);
13187 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013188 bakd = ctxt->context->doc;
13189 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013190 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013191 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013192 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013193 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013194 ctxt->context->doc = bakd;
13195 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013196 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013197 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013198 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013199 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013200 if (op->value == 0)
13201 xmlXPathMultValues(ctxt);
13202 else if (op->value == 1)
13203 xmlXPathDivValues(ctxt);
13204 else if (op->value == 2)
13205 xmlXPathModValues(ctxt);
13206 return (total);
13207 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013208 bakd = ctxt->context->doc;
13209 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013210 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013211 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013212 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013213 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013214 ctxt->context->doc = bakd;
13215 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013216 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013217 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013219 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013220 CHECK_TYPE0(XPATH_NODESET);
13221 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013222
Daniel Veillardf06307e2001-07-03 10:35:50 +000013223 CHECK_TYPE0(XPATH_NODESET);
13224 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013225
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013226 if ((arg1->nodesetval == NULL) ||
13227 ((arg2->nodesetval != NULL) &&
13228 (arg2->nodesetval->nodeNr != 0)))
13229 {
13230 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13231 arg2->nodesetval);
13232 }
13233
Daniel Veillardf06307e2001-07-03 10:35:50 +000013234 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013235 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 return (total);
13237 case XPATH_OP_ROOT:
13238 xmlXPathRoot(ctxt);
13239 return (total);
13240 case XPATH_OP_NODE:
13241 if (op->ch1 != -1)
13242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013243 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013244 if (op->ch2 != -1)
13245 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013246 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013247 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13248 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013249 return (total);
13250 case XPATH_OP_RESET:
13251 if (op->ch1 != -1)
13252 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013253 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013254 if (op->ch2 != -1)
13255 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013256 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013257 ctxt->context->node = NULL;
13258 return (total);
13259 case XPATH_OP_COLLECT:{
13260 if (op->ch1 == -1)
13261 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013262
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013264 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013265
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013266 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013267 return (total);
13268 }
13269 case XPATH_OP_VALUE:
13270 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013271 xmlXPathCacheObjectCopy(ctxt->context,
13272 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013273 return (total);
13274 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013275 xmlXPathObjectPtr val;
13276
Daniel Veillardf06307e2001-07-03 10:35:50 +000013277 if (op->ch1 != -1)
13278 total +=
13279 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013280 if (op->value5 == NULL) {
13281 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13282 if (val == NULL) {
13283 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13284 return(0);
13285 }
13286 valuePush(ctxt, val);
13287 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013288 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013289
Daniel Veillardf06307e2001-07-03 10:35:50 +000013290 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13291 if (URI == NULL) {
13292 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013293 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013294 op->value4, op->value5);
13295 return (total);
13296 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013297 val = xmlXPathVariableLookupNS(ctxt->context,
13298 op->value4, URI);
13299 if (val == NULL) {
13300 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13301 return(0);
13302 }
13303 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013304 }
13305 return (total);
13306 }
13307 case XPATH_OP_FUNCTION:{
13308 xmlXPathFunction func;
13309 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013310 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013311
13312 if (op->ch1 != -1)
13313 total +=
13314 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013315 if (ctxt->valueNr < op->value) {
13316 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013317 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013318 ctxt->error = XPATH_INVALID_OPERAND;
13319 return (total);
13320 }
13321 for (i = 0; i < op->value; i++)
13322 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13323 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013324 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013325 ctxt->error = XPATH_INVALID_OPERAND;
13326 return (total);
13327 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013328 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013329 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013330 else {
13331 const xmlChar *URI = NULL;
13332
13333 if (op->value5 == NULL)
13334 func =
13335 xmlXPathFunctionLookup(ctxt->context,
13336 op->value4);
13337 else {
13338 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13339 if (URI == NULL) {
13340 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013341 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013342 op->value4, op->value5);
13343 return (total);
13344 }
13345 func = xmlXPathFunctionLookupNS(ctxt->context,
13346 op->value4, URI);
13347 }
13348 if (func == NULL) {
13349 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013350 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 op->value4);
13352 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013353 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013354 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 op->cacheURI = (void *) URI;
13356 }
13357 oldFunc = ctxt->context->function;
13358 oldFuncURI = ctxt->context->functionURI;
13359 ctxt->context->function = op->value4;
13360 ctxt->context->functionURI = op->cacheURI;
13361 func(ctxt, op->value);
13362 ctxt->context->function = oldFunc;
13363 ctxt->context->functionURI = oldFuncURI;
13364 return (total);
13365 }
13366 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013367 bakd = ctxt->context->doc;
13368 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013369 pp = ctxt->context->proximityPosition;
13370 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013371 if (op->ch1 != -1)
13372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013373 ctxt->context->contextSize = cs;
13374 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013375 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013376 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013377 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013378 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013379 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013380 ctxt->context->doc = bakd;
13381 ctxt->context->node = bak;
13382 CHECK_ERROR0;
13383 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013384 return (total);
13385 case XPATH_OP_PREDICATE:
13386 case XPATH_OP_FILTER:{
13387 xmlXPathObjectPtr res;
13388 xmlXPathObjectPtr obj, tmp;
13389 xmlNodeSetPtr newset = NULL;
13390 xmlNodeSetPtr oldset;
13391 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013392 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013393 int i;
13394
13395 /*
13396 * Optimization for ()[1] selection i.e. the first elem
13397 */
13398 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013399#ifdef XP_OPTIMIZED_FILTER_FIRST
13400 /*
13401 * FILTER TODO: Can we assume that the inner processing
13402 * will result in an ordered list if we have an
13403 * XPATH_OP_FILTER?
13404 * What about an additional field or flag on
13405 * xmlXPathObject like @sorted ? This way we wouln'd need
13406 * to assume anything, so it would be more robust and
13407 * easier to optimize.
13408 */
13409 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13410 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13411#else
13412 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13413#endif
13414 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013415 xmlXPathObjectPtr val;
13416
13417 val = comp->steps[op->ch2].value4;
13418 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13419 (val->floatval == 1.0)) {
13420 xmlNodePtr first = NULL;
13421
13422 total +=
13423 xmlXPathCompOpEvalFirst(ctxt,
13424 &comp->steps[op->ch1],
13425 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013426 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013427 /*
13428 * The nodeset should be in document order,
13429 * Keep only the first value
13430 */
13431 if ((ctxt->value != NULL) &&
13432 (ctxt->value->type == XPATH_NODESET) &&
13433 (ctxt->value->nodesetval != NULL) &&
13434 (ctxt->value->nodesetval->nodeNr > 1))
13435 ctxt->value->nodesetval->nodeNr = 1;
13436 return (total);
13437 }
13438 }
13439 /*
13440 * Optimization for ()[last()] selection i.e. the last elem
13441 */
13442 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13443 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13444 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13445 int f = comp->steps[op->ch2].ch1;
13446
13447 if ((f != -1) &&
13448 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13449 (comp->steps[f].value5 == NULL) &&
13450 (comp->steps[f].value == 0) &&
13451 (comp->steps[f].value4 != NULL) &&
13452 (xmlStrEqual
13453 (comp->steps[f].value4, BAD_CAST "last"))) {
13454 xmlNodePtr last = NULL;
13455
13456 total +=
13457 xmlXPathCompOpEvalLast(ctxt,
13458 &comp->steps[op->ch1],
13459 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013460 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013461 /*
13462 * The nodeset should be in document order,
13463 * Keep only the last value
13464 */
13465 if ((ctxt->value != NULL) &&
13466 (ctxt->value->type == XPATH_NODESET) &&
13467 (ctxt->value->nodesetval != NULL) &&
13468 (ctxt->value->nodesetval->nodeTab != NULL) &&
13469 (ctxt->value->nodesetval->nodeNr > 1)) {
13470 ctxt->value->nodesetval->nodeTab[0] =
13471 ctxt->value->nodesetval->nodeTab[ctxt->
13472 value->
13473 nodesetval->
13474 nodeNr -
13475 1];
13476 ctxt->value->nodesetval->nodeNr = 1;
13477 }
13478 return (total);
13479 }
13480 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013481 /*
13482 * Process inner predicates first.
13483 * Example "index[parent::book][1]":
13484 * ...
13485 * PREDICATE <-- we are here "[1]"
13486 * PREDICATE <-- process "[parent::book]" first
13487 * SORT
13488 * COLLECT 'parent' 'name' 'node' book
13489 * NODE
13490 * ELEM Object is a number : 1
13491 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013492 if (op->ch1 != -1)
13493 total +=
13494 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013496 if (op->ch2 == -1)
13497 return (total);
13498 if (ctxt->value == NULL)
13499 return (total);
13500
13501 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013502
13503#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013504 /*
13505 * Hum are we filtering the result of an XPointer expression
13506 */
13507 if (ctxt->value->type == XPATH_LOCATIONSET) {
13508 xmlLocationSetPtr newlocset = NULL;
13509 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013510
Daniel Veillardf06307e2001-07-03 10:35:50 +000013511 /*
13512 * Extract the old locset, and then evaluate the result of the
13513 * expression for all the element in the locset. use it to grow
13514 * up a new locset.
13515 */
13516 CHECK_TYPE0(XPATH_LOCATIONSET);
13517 obj = valuePop(ctxt);
13518 oldlocset = obj->user;
13519 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013520
Daniel Veillardf06307e2001-07-03 10:35:50 +000013521 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13522 ctxt->context->contextSize = 0;
13523 ctxt->context->proximityPosition = 0;
13524 if (op->ch2 != -1)
13525 total +=
13526 xmlXPathCompOpEval(ctxt,
13527 &comp->steps[op->ch2]);
13528 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013529 if (res != NULL) {
13530 xmlXPathReleaseObject(ctxt->context, res);
13531 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013532 valuePush(ctxt, obj);
13533 CHECK_ERROR0;
13534 return (total);
13535 }
13536 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013537
Daniel Veillardf06307e2001-07-03 10:35:50 +000013538 for (i = 0; i < oldlocset->locNr; i++) {
13539 /*
13540 * Run the evaluation with a node list made of a
13541 * single item in the nodelocset.
13542 */
13543 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013544 ctxt->context->contextSize = oldlocset->locNr;
13545 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013546 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13547 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013548 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013549
Daniel Veillardf06307e2001-07-03 10:35:50 +000013550 if (op->ch2 != -1)
13551 total +=
13552 xmlXPathCompOpEval(ctxt,
13553 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013554 if (ctxt->error != XPATH_EXPRESSION_OK) {
13555 xmlXPathFreeObject(obj);
13556 return(0);
13557 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013558
Daniel Veillardf06307e2001-07-03 10:35:50 +000013559 /*
13560 * The result of the evaluation need to be tested to
13561 * decided whether the filter succeeded or not
13562 */
13563 res = valuePop(ctxt);
13564 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13565 xmlXPtrLocationSetAdd(newlocset,
13566 xmlXPathObjectCopy
13567 (oldlocset->locTab[i]));
13568 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013569
Daniel Veillardf06307e2001-07-03 10:35:50 +000013570 /*
13571 * Cleanup
13572 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013573 if (res != NULL) {
13574 xmlXPathReleaseObject(ctxt->context, res);
13575 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013576 if (ctxt->value == tmp) {
13577 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013578 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013579 }
13580
13581 ctxt->context->node = NULL;
13582 }
13583
13584 /*
13585 * The result is used as the new evaluation locset.
13586 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013587 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013588 ctxt->context->node = NULL;
13589 ctxt->context->contextSize = -1;
13590 ctxt->context->proximityPosition = -1;
13591 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13592 ctxt->context->node = oldnode;
13593 return (total);
13594 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013595#endif /* LIBXML_XPTR_ENABLED */
13596
Daniel Veillardf06307e2001-07-03 10:35:50 +000013597 /*
13598 * Extract the old set, and then evaluate the result of the
13599 * expression for all the element in the set. use it to grow
13600 * up a new set.
13601 */
13602 CHECK_TYPE0(XPATH_NODESET);
13603 obj = valuePop(ctxt);
13604 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013605
Daniel Veillardf06307e2001-07-03 10:35:50 +000013606 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013607 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013608 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013609
Daniel Veillardf06307e2001-07-03 10:35:50 +000013610 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13611 ctxt->context->contextSize = 0;
13612 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013613/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013614 if (op->ch2 != -1)
13615 total +=
13616 xmlXPathCompOpEval(ctxt,
13617 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013618 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013619 res = valuePop(ctxt);
13620 if (res != NULL)
13621 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013622*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013623 valuePush(ctxt, obj);
13624 ctxt->context->node = oldnode;
13625 CHECK_ERROR0;
13626 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013627 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013628 /*
13629 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013630 * Also set the xpath document in case things like
13631 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013632 */
13633 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013634 /*
13635 * SPEC XPath 1.0:
13636 * "For each node in the node-set to be filtered, the
13637 * PredicateExpr is evaluated with that node as the
13638 * context node, with the number of nodes in the
13639 * node-set as the context size, and with the proximity
13640 * position of the node in the node-set with respect to
13641 * the axis as the context position;"
13642 * @oldset is the node-set" to be filtered.
13643 *
13644 * SPEC XPath 1.0:
13645 * "only predicates change the context position and
13646 * context size (see [2.4 Predicates])."
13647 * Example:
13648 * node-set context pos
13649 * nA 1
13650 * nB 2
13651 * nC 3
13652 * After applying predicate [position() > 1] :
13653 * node-set context pos
13654 * nB 1
13655 * nC 2
13656 *
13657 * removed the first node in the node-set, then
13658 * the context position of the
13659 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013660 for (i = 0; i < oldset->nodeNr; i++) {
13661 /*
13662 * Run the evaluation with a node list made of
13663 * a single item in the nodeset.
13664 */
13665 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013666 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13667 (oldset->nodeTab[i]->doc != NULL))
13668 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013669 if (tmp == NULL) {
13670 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13671 ctxt->context->node);
13672 } else {
13673 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13674 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013675 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013676 valuePush(ctxt, tmp);
13677 ctxt->context->contextSize = oldset->nodeNr;
13678 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013679 /*
13680 * Evaluate the predicate against the context node.
13681 * Can/should we optimize position() predicates
13682 * here (e.g. "[1]")?
13683 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013684 if (op->ch2 != -1)
13685 total +=
13686 xmlXPathCompOpEval(ctxt,
13687 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013688 if (ctxt->error != XPATH_EXPRESSION_OK) {
13689 xmlXPathFreeNodeSet(newset);
13690 xmlXPathFreeObject(obj);
13691 return(0);
13692 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013693
Daniel Veillardf06307e2001-07-03 10:35:50 +000013694 /*
William M. Brack08171912003-12-29 02:52:11 +000013695 * The result of the evaluation needs to be tested to
13696 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013697 */
13698 /*
13699 * OPTIMIZE TODO: Can we use
13700 * xmlXPathNodeSetAdd*Unique()* instead?
13701 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013702 res = valuePop(ctxt);
13703 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13704 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13705 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013706
Daniel Veillardf06307e2001-07-03 10:35:50 +000013707 /*
13708 * Cleanup
13709 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013710 if (res != NULL) {
13711 xmlXPathReleaseObject(ctxt->context, res);
13712 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013713 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013714 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013715 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013716 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013717 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013718 * in order to avoid massive recreation inside this
13719 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013720 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013721 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013722 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013723 ctxt->context->node = NULL;
13724 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013725 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013726 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013727 /*
13728 * The result is used as the new evaluation set.
13729 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013730 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013731 ctxt->context->node = NULL;
13732 ctxt->context->contextSize = -1;
13733 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013734 /* may want to move this past the '}' later */
13735 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013736 valuePush(ctxt,
13737 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013738 }
13739 ctxt->context->node = oldnode;
13740 return (total);
13741 }
13742 case XPATH_OP_SORT:
13743 if (op->ch1 != -1)
13744 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013745 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013746 if ((ctxt->value != NULL) &&
13747 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013748 (ctxt->value->nodesetval != NULL) &&
13749 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013750 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013751 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013752 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013753 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013754#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013755 case XPATH_OP_RANGETO:{
13756 xmlXPathObjectPtr range;
13757 xmlXPathObjectPtr res, obj;
13758 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013759 xmlLocationSetPtr newlocset = NULL;
13760 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013761 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013762 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013763
Daniel Veillardf06307e2001-07-03 10:35:50 +000013764 if (op->ch1 != -1)
13765 total +=
13766 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13767 if (op->ch2 == -1)
13768 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013769
William M. Brack08171912003-12-29 02:52:11 +000013770 if (ctxt->value->type == XPATH_LOCATIONSET) {
13771 /*
13772 * Extract the old locset, and then evaluate the result of the
13773 * expression for all the element in the locset. use it to grow
13774 * up a new locset.
13775 */
13776 CHECK_TYPE0(XPATH_LOCATIONSET);
13777 obj = valuePop(ctxt);
13778 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013779
William M. Brack08171912003-12-29 02:52:11 +000013780 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013781 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013782 ctxt->context->contextSize = 0;
13783 ctxt->context->proximityPosition = 0;
13784 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13785 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013786 if (res != NULL) {
13787 xmlXPathReleaseObject(ctxt->context, res);
13788 }
William M. Brack08171912003-12-29 02:52:11 +000013789 valuePush(ctxt, obj);
13790 CHECK_ERROR0;
13791 return (total);
13792 }
13793 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013794
William M. Brack08171912003-12-29 02:52:11 +000013795 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013796 /*
William M. Brack08171912003-12-29 02:52:11 +000013797 * Run the evaluation with a node list made of a
13798 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013799 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013800 ctxt->context->node = oldlocset->locTab[i]->user;
13801 ctxt->context->contextSize = oldlocset->locNr;
13802 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013803 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13804 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013805 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013806
Daniel Veillardf06307e2001-07-03 10:35:50 +000013807 if (op->ch2 != -1)
13808 total +=
13809 xmlXPathCompOpEval(ctxt,
13810 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013811 if (ctxt->error != XPATH_EXPRESSION_OK) {
13812 xmlXPathFreeObject(obj);
13813 return(0);
13814 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013815
Daniel Veillardf06307e2001-07-03 10:35:50 +000013816 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013817 if (res->type == XPATH_LOCATIONSET) {
13818 xmlLocationSetPtr rloc =
13819 (xmlLocationSetPtr)res->user;
13820 for (j=0; j<rloc->locNr; j++) {
13821 range = xmlXPtrNewRange(
13822 oldlocset->locTab[i]->user,
13823 oldlocset->locTab[i]->index,
13824 rloc->locTab[j]->user2,
13825 rloc->locTab[j]->index2);
13826 if (range != NULL) {
13827 xmlXPtrLocationSetAdd(newlocset, range);
13828 }
13829 }
13830 } else {
13831 range = xmlXPtrNewRangeNodeObject(
13832 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13833 if (range != NULL) {
13834 xmlXPtrLocationSetAdd(newlocset,range);
13835 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013836 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013837
Daniel Veillardf06307e2001-07-03 10:35:50 +000013838 /*
13839 * Cleanup
13840 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013841 if (res != NULL) {
13842 xmlXPathReleaseObject(ctxt->context, res);
13843 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013844 if (ctxt->value == tmp) {
13845 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013846 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013847 }
13848
13849 ctxt->context->node = NULL;
13850 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013851 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013852 CHECK_TYPE0(XPATH_NODESET);
13853 obj = valuePop(ctxt);
13854 oldset = obj->nodesetval;
13855 ctxt->context->node = NULL;
13856
13857 newlocset = xmlXPtrLocationSetCreate(NULL);
13858
13859 if (oldset != NULL) {
13860 for (i = 0; i < oldset->nodeNr; i++) {
13861 /*
13862 * Run the evaluation with a node list made of a single item
13863 * in the nodeset.
13864 */
13865 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013866 /*
13867 * OPTIMIZE TODO: Avoid recreation for every iteration.
13868 */
13869 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13870 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013871 valuePush(ctxt, tmp);
13872
13873 if (op->ch2 != -1)
13874 total +=
13875 xmlXPathCompOpEval(ctxt,
13876 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013877 if (ctxt->error != XPATH_EXPRESSION_OK) {
13878 xmlXPathFreeObject(obj);
13879 return(0);
13880 }
William M. Brack08171912003-12-29 02:52:11 +000013881
William M. Brack08171912003-12-29 02:52:11 +000013882 res = valuePop(ctxt);
13883 range =
13884 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13885 res);
13886 if (range != NULL) {
13887 xmlXPtrLocationSetAdd(newlocset, range);
13888 }
13889
13890 /*
13891 * Cleanup
13892 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013893 if (res != NULL) {
13894 xmlXPathReleaseObject(ctxt->context, res);
13895 }
William M. Brack08171912003-12-29 02:52:11 +000013896 if (ctxt->value == tmp) {
13897 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013898 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013899 }
13900
13901 ctxt->context->node = NULL;
13902 }
13903 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013904 }
13905
13906 /*
13907 * The result is used as the new evaluation set.
13908 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013909 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013910 ctxt->context->node = NULL;
13911 ctxt->context->contextSize = -1;
13912 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013913 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013914 return (total);
13915 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013916#endif /* LIBXML_XPTR_ENABLED */
13917 }
13918 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013919 "XPath: unknown precompiled operation %d\n", op->op);
13920 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013921}
13922
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013923/**
13924 * xmlXPathCompOpEvalToBoolean:
13925 * @ctxt: the XPath parser context
13926 *
13927 * Evaluates if the expression evaluates to true.
13928 *
13929 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13930 */
13931static int
13932xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013933 xmlXPathStepOpPtr op,
13934 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013935{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013936 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013937
13938start:
13939 /* comp = ctxt->comp; */
13940 switch (op->op) {
13941 case XPATH_OP_END:
13942 return (0);
13943 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013944 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013945 if (isPredicate)
13946 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13947 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013948 case XPATH_OP_SORT:
13949 /*
13950 * We don't need sorting for boolean results. Skip this one.
13951 */
13952 if (op->ch1 != -1) {
13953 op = &ctxt->comp->steps[op->ch1];
13954 goto start;
13955 }
13956 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013957 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013958 if (op->ch1 == -1)
13959 return(0);
13960
13961 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13962 if (ctxt->error != XPATH_EXPRESSION_OK)
13963 return(-1);
13964
13965 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13966 if (ctxt->error != XPATH_EXPRESSION_OK)
13967 return(-1);
13968
13969 resObj = valuePop(ctxt);
13970 if (resObj == NULL)
13971 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013972 break;
13973 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013974 /*
13975 * Fallback to call xmlXPathCompOpEval().
13976 */
13977 xmlXPathCompOpEval(ctxt, op);
13978 if (ctxt->error != XPATH_EXPRESSION_OK)
13979 return(-1);
13980
13981 resObj = valuePop(ctxt);
13982 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013983 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013984 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013985 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013986
13987 if (resObj) {
13988 int res;
13989
13990 if (resObj->type == XPATH_BOOLEAN) {
13991 res = resObj->boolval;
13992 } else if (isPredicate) {
13993 /*
13994 * For predicates a result of type "number" is handled
13995 * differently:
13996 * SPEC XPath 1.0:
13997 * "If the result is a number, the result will be converted
13998 * to true if the number is equal to the context position
13999 * and will be converted to false otherwise;"
14000 */
14001 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14002 } else {
14003 res = xmlXPathCastToBoolean(resObj);
14004 }
14005 xmlXPathReleaseObject(ctxt->context, resObj);
14006 return(res);
14007 }
14008
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014009 return(0);
14010}
14011
Daniel Veillard56de87e2005-02-16 00:22:29 +000014012#ifdef XPATH_STREAMING
14013/**
14014 * xmlXPathRunStreamEval:
14015 * @ctxt: the XPath parser context with the compiled expression
14016 *
14017 * Evaluate the Precompiled Streamable XPath expression in the given context.
14018 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014019static int
14020xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14021 xmlXPathObjectPtr *resultSeq, int toBool)
14022{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014023 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014024 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014025 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014026 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014027 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014028 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014029
14030 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014031
14032 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014033 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014034 max_depth = xmlPatternMaxDepth(comp);
14035 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014036 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014037 if (max_depth == -2)
14038 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014039 min_depth = xmlPatternMinDepth(comp);
14040 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014041 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014042 from_root = xmlPatternFromRoot(comp);
14043 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014044 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014045#if 0
14046 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14047#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014048
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014049 if (! toBool) {
14050 if (resultSeq == NULL)
14051 return(-1);
14052 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14053 if (*resultSeq == NULL)
14054 return(-1);
14055 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014056
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014057 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014058 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014059 */
14060 if (min_depth == 0) {
14061 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014062 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014063 if (toBool)
14064 return(1);
14065 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14066 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014067 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014068 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014069 if (toBool)
14070 return(1);
14071 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014072 }
14073 }
14074 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014075 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014076 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014077
Daniel Veillard56de87e2005-02-16 00:22:29 +000014078 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014079 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014080 } else if (ctxt->node != NULL) {
14081 switch (ctxt->node->type) {
14082 case XML_ELEMENT_NODE:
14083 case XML_DOCUMENT_NODE:
14084 case XML_DOCUMENT_FRAG_NODE:
14085 case XML_HTML_DOCUMENT_NODE:
14086#ifdef LIBXML_DOCB_ENABLED
14087 case XML_DOCB_DOCUMENT_NODE:
14088#endif
14089 cur = ctxt->node;
14090 break;
14091 case XML_ATTRIBUTE_NODE:
14092 case XML_TEXT_NODE:
14093 case XML_CDATA_SECTION_NODE:
14094 case XML_ENTITY_REF_NODE:
14095 case XML_ENTITY_NODE:
14096 case XML_PI_NODE:
14097 case XML_COMMENT_NODE:
14098 case XML_NOTATION_NODE:
14099 case XML_DTD_NODE:
14100 case XML_DOCUMENT_TYPE_NODE:
14101 case XML_ELEMENT_DECL:
14102 case XML_ATTRIBUTE_DECL:
14103 case XML_ENTITY_DECL:
14104 case XML_NAMESPACE_DECL:
14105 case XML_XINCLUDE_START:
14106 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014107 break;
14108 }
14109 limit = cur;
14110 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014111 if (cur == NULL) {
14112 return(0);
14113 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014114
14115 patstream = xmlPatternGetStreamCtxt(comp);
14116 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014117 /*
14118 * QUESTION TODO: Is this an error?
14119 */
14120 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014121 }
14122
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014123 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014124
Daniel Veillard56de87e2005-02-16 00:22:29 +000014125 if (from_root) {
14126 ret = xmlStreamPush(patstream, NULL, NULL);
14127 if (ret < 0) {
14128 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014129 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014130 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014131 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014132 }
14133 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014134 depth = 0;
14135 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014136next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014137 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014138 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014139
14140 switch (cur->type) {
14141 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014142 case XML_TEXT_NODE:
14143 case XML_CDATA_SECTION_NODE:
14144 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014145 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014146 if (cur->type == XML_ELEMENT_NODE) {
14147 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014148 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014149 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014150 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14151 else
14152 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014153
14154 if (ret < 0) {
14155 /* NOP. */
14156 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014157 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014158 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014159 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014160 }
14161 if ((cur->children == NULL) || (depth >= max_depth)) {
14162 ret = xmlStreamPop(patstream);
14163 while (cur->next != NULL) {
14164 cur = cur->next;
14165 if ((cur->type != XML_ENTITY_DECL) &&
14166 (cur->type != XML_DTD_NODE))
14167 goto next_node;
14168 }
14169 }
14170 default:
14171 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014172 }
14173
Daniel Veillard56de87e2005-02-16 00:22:29 +000014174scan_children:
14175 if ((cur->children != NULL) && (depth < max_depth)) {
14176 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014177 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014178 */
14179 if (cur->children->type != XML_ENTITY_DECL) {
14180 cur = cur->children;
14181 depth++;
14182 /*
14183 * Skip DTDs
14184 */
14185 if (cur->type != XML_DTD_NODE)
14186 continue;
14187 }
14188 }
14189
14190 if (cur == limit)
14191 break;
14192
14193 while (cur->next != NULL) {
14194 cur = cur->next;
14195 if ((cur->type != XML_ENTITY_DECL) &&
14196 (cur->type != XML_DTD_NODE))
14197 goto next_node;
14198 }
14199
14200 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014201 cur = cur->parent;
14202 depth--;
14203 if ((cur == NULL) || (cur == limit))
14204 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014205 if (cur->type == XML_ELEMENT_NODE) {
14206 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014207 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014208 ((cur->type == XML_TEXT_NODE) ||
14209 (cur->type == XML_CDATA_SECTION_NODE) ||
14210 (cur->type == XML_COMMENT_NODE) ||
14211 (cur->type == XML_PI_NODE)))
14212 {
14213 ret = xmlStreamPop(patstream);
14214 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014215 if (cur->next != NULL) {
14216 cur = cur->next;
14217 break;
14218 }
14219 } while (cur != NULL);
14220
14221 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014222
Daniel Veillard56de87e2005-02-16 00:22:29 +000014223done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014224
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014225#if 0
14226 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014227 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014228#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014229
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014230 if (patstream)
14231 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014232 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014233
14234return_1:
14235 if (patstream)
14236 xmlFreeStreamCtxt(patstream);
14237 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014238}
14239#endif /* XPATH_STREAMING */
14240
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014241/**
14242 * xmlXPathRunEval:
14243 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014244 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014245 *
14246 * Evaluate the Precompiled XPath expression in the given context.
14247 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014248static int
14249xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14250{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014251 xmlXPathCompExprPtr comp;
14252
14253 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014254 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014255
14256 if (ctxt->valueTab == NULL) {
14257 /* Allocate the value stack */
14258 ctxt->valueTab = (xmlXPathObjectPtr *)
14259 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14260 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014261 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014262 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014263 }
14264 ctxt->valueNr = 0;
14265 ctxt->valueMax = 10;
14266 ctxt->value = NULL;
14267 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014268#ifdef XPATH_STREAMING
14269 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014270 int res;
14271
14272 if (toBool) {
14273 /*
14274 * Evaluation to boolean result.
14275 */
14276 res = xmlXPathRunStreamEval(ctxt->context,
14277 ctxt->comp->stream, NULL, 1);
14278 if (res != -1)
14279 return(res);
14280 } else {
14281 xmlXPathObjectPtr resObj = NULL;
14282
14283 /*
14284 * Evaluation to a sequence.
14285 */
14286 res = xmlXPathRunStreamEval(ctxt->context,
14287 ctxt->comp->stream, &resObj, 0);
14288
14289 if ((res != -1) && (resObj != NULL)) {
14290 valuePush(ctxt, resObj);
14291 return(0);
14292 }
14293 if (resObj != NULL)
14294 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014295 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014296 /*
14297 * QUESTION TODO: This falls back to normal XPath evaluation
14298 * if res == -1. Is this intended?
14299 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014300 }
14301#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014302 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014303 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014304 xmlGenericError(xmlGenericErrorContext,
14305 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014306 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014307 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014308 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014309 return(xmlXPathCompOpEvalToBoolean(ctxt,
14310 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014311 else
14312 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14313
14314 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014315}
14316
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014317/************************************************************************
14318 * *
14319 * Public interfaces *
14320 * *
14321 ************************************************************************/
14322
14323/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014324 * xmlXPathEvalPredicate:
14325 * @ctxt: the XPath context
14326 * @res: the Predicate Expression evaluation result
14327 *
14328 * Evaluate a predicate result for the current node.
14329 * A PredicateExpr is evaluated by evaluating the Expr and converting
14330 * the result to a boolean. If the result is a number, the result will
14331 * be converted to true if the number is equal to the position of the
14332 * context node in the context node list (as returned by the position
14333 * function) and will be converted to false otherwise; if the result
14334 * is not a number, then the result will be converted as if by a call
14335 * to the boolean function.
14336 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014337 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014338 */
14339int
14340xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014341 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014342 switch (res->type) {
14343 case XPATH_BOOLEAN:
14344 return(res->boolval);
14345 case XPATH_NUMBER:
14346 return(res->floatval == ctxt->proximityPosition);
14347 case XPATH_NODESET:
14348 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014349 if (res->nodesetval == NULL)
14350 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014351 return(res->nodesetval->nodeNr != 0);
14352 case XPATH_STRING:
14353 return((res->stringval != NULL) &&
14354 (xmlStrlen(res->stringval) != 0));
14355 default:
14356 STRANGE
14357 }
14358 return(0);
14359}
14360
14361/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014362 * xmlXPathEvaluatePredicateResult:
14363 * @ctxt: the XPath Parser context
14364 * @res: the Predicate Expression evaluation result
14365 *
14366 * Evaluate a predicate result for the current node.
14367 * A PredicateExpr is evaluated by evaluating the Expr and converting
14368 * the result to a boolean. If the result is a number, the result will
14369 * be converted to true if the number is equal to the position of the
14370 * context node in the context node list (as returned by the position
14371 * function) and will be converted to false otherwise; if the result
14372 * is not a number, then the result will be converted as if by a call
14373 * to the boolean function.
14374 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014375 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014376 */
14377int
14378xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14379 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014380 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014381 switch (res->type) {
14382 case XPATH_BOOLEAN:
14383 return(res->boolval);
14384 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014385#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014386 return((res->floatval == ctxt->context->proximityPosition) &&
14387 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014388#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014389 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014390#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014391 case XPATH_NODESET:
14392 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014393 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014394 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014395 return(res->nodesetval->nodeNr != 0);
14396 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014397 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014398#ifdef LIBXML_XPTR_ENABLED
14399 case XPATH_LOCATIONSET:{
14400 xmlLocationSetPtr ptr = res->user;
14401 if (ptr == NULL)
14402 return(0);
14403 return (ptr->locNr != 0);
14404 }
14405#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014406 default:
14407 STRANGE
14408 }
14409 return(0);
14410}
14411
Daniel Veillard56de87e2005-02-16 00:22:29 +000014412#ifdef XPATH_STREAMING
14413/**
14414 * xmlXPathTryStreamCompile:
14415 * @ctxt: an XPath context
14416 * @str: the XPath expression
14417 *
14418 * Try to compile the XPath expression as a streamable subset.
14419 *
14420 * Returns the compiled expression or NULL if failed to compile.
14421 */
14422static xmlXPathCompExprPtr
14423xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14424 /*
14425 * Optimization: use streaming patterns when the XPath expression can
14426 * be compiled to a stream lookup
14427 */
14428 xmlPatternPtr stream;
14429 xmlXPathCompExprPtr comp;
14430 xmlDictPtr dict = NULL;
14431 const xmlChar **namespaces = NULL;
14432 xmlNsPtr ns;
14433 int i, j;
14434
14435 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14436 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014437 const xmlChar *tmp;
14438
14439 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014440 * We don't try to handle expressions using the verbose axis
14441 * specifiers ("::"), just the simplied form at this point.
14442 * Additionally, if there is no list of namespaces available and
14443 * there's a ":" in the expression, indicating a prefixed QName,
14444 * then we won't try to compile either. xmlPatterncompile() needs
14445 * to have a list of namespaces at compilation time in order to
14446 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014447 */
14448 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014449 if ((tmp != NULL) &&
14450 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14451 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014452
Daniel Veillard56de87e2005-02-16 00:22:29 +000014453 if (ctxt != NULL) {
14454 dict = ctxt->dict;
14455 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014456 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014457 if (namespaces == NULL) {
14458 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14459 return(NULL);
14460 }
14461 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14462 ns = ctxt->namespaces[j];
14463 namespaces[i++] = ns->href;
14464 namespaces[i++] = ns->prefix;
14465 }
14466 namespaces[i++] = NULL;
14467 namespaces[i++] = NULL;
14468 }
14469 }
14470
William M. Brackea152c02005-06-09 18:12:28 +000014471 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14472 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014473 if (namespaces != NULL) {
14474 xmlFree((xmlChar **)namespaces);
14475 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014476 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14477 comp = xmlXPathNewCompExpr();
14478 if (comp == NULL) {
14479 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14480 return(NULL);
14481 }
14482 comp->stream = stream;
14483 comp->dict = dict;
14484 if (comp->dict)
14485 xmlDictReference(comp->dict);
14486 return(comp);
14487 }
14488 xmlFreePattern(stream);
14489 }
14490 return(NULL);
14491}
14492#endif /* XPATH_STREAMING */
14493
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014494static int
14495xmlXPathCanRewriteDosExpression(xmlChar *expr)
14496{
14497 if (expr == NULL)
14498 return(0);
14499 do {
14500 if ((*expr == '/') && (*(++expr) == '/'))
14501 return(1);
14502 } while (*expr++);
14503 return(0);
14504}
14505static void
14506xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14507{
14508 /*
14509 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14510 * internal representation.
14511 */
14512 if (op->ch1 != -1) {
14513 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14514 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14515 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14516 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14517 {
14518 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014519 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014520 */
14521 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14522
14523 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14524 (prevop->ch1 != -1) &&
14525 ((xmlXPathAxisVal) prevop->value ==
14526 AXIS_DESCENDANT_OR_SELF) &&
14527 (prevop->ch2 == -1) &&
14528 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014529 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14530 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014531 {
14532 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014533 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014534 * Eliminate it.
14535 */
14536 op->ch1 = prevop->ch1;
14537 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14538 }
14539 }
14540 if (op->ch1 != -1)
14541 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14542 }
14543 if (op->ch2 != -1)
14544 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14545}
14546
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014547/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014548 * xmlXPathCtxtCompile:
14549 * @ctxt: an XPath context
14550 * @str: the XPath expression
14551 *
14552 * Compile an XPath expression
14553 *
14554 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14555 * the caller has to free the object.
14556 */
14557xmlXPathCompExprPtr
14558xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14559 xmlXPathParserContextPtr pctxt;
14560 xmlXPathCompExprPtr comp;
14561
Daniel Veillard56de87e2005-02-16 00:22:29 +000014562#ifdef XPATH_STREAMING
14563 comp = xmlXPathTryStreamCompile(ctxt, str);
14564 if (comp != NULL)
14565 return(comp);
14566#endif
14567
Daniel Veillard4773df22004-01-23 13:15:13 +000014568 xmlXPathInit();
14569
14570 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014571 if (pctxt == NULL)
14572 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014573 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014574
14575 if( pctxt->error != XPATH_EXPRESSION_OK )
14576 {
14577 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014578 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014579 }
14580
14581 if (*pctxt->cur != 0) {
14582 /*
14583 * aleksey: in some cases this line prints *second* error message
14584 * (see bug #78858) and probably this should be fixed.
14585 * However, we are not sure that all error messages are printed
14586 * out in other places. It's not critical so we leave it as-is for now
14587 */
14588 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14589 comp = NULL;
14590 } else {
14591 comp = pctxt->comp;
14592 pctxt->comp = NULL;
14593 }
14594 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014595
Daniel Veillard4773df22004-01-23 13:15:13 +000014596 if (comp != NULL) {
14597 comp->expr = xmlStrdup(str);
14598#ifdef DEBUG_EVAL_COUNTS
14599 comp->string = xmlStrdup(str);
14600 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014601#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014602 if ((comp->expr != NULL) &&
14603 (comp->nbStep > 2) &&
14604 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014605 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14606 {
14607 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014608 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014609 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014610 return(comp);
14611}
14612
14613/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014614 * xmlXPathCompile:
14615 * @str: the XPath expression
14616 *
14617 * Compile an XPath expression
14618 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014619 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014620 * the caller has to free the object.
14621 */
14622xmlXPathCompExprPtr
14623xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014624 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014625}
14626
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014627/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014628 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014629 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014630 * @ctxt: the XPath context
14631 * @resObj: the resulting XPath object or NULL
14632 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014633 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014634 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014635 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014636 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014637 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014638 * the caller has to free the object.
14639 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014640static int
14641xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14642 xmlXPathContextPtr ctxt,
14643 xmlXPathObjectPtr *resObj,
14644 int toBool)
14645{
14646 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014647#ifndef LIBXML_THREAD_ENABLED
14648 static int reentance = 0;
14649#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014650 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014651
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014652 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014653
14654 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014655 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014656 xmlXPathInit();
14657
Daniel Veillard81463942001-10-16 12:34:39 +000014658#ifndef LIBXML_THREAD_ENABLED
14659 reentance++;
14660 if (reentance > 1)
14661 xmlXPathDisableOptimizer = 1;
14662#endif
14663
Daniel Veillardf06307e2001-07-03 10:35:50 +000014664#ifdef DEBUG_EVAL_COUNTS
14665 comp->nb++;
14666 if ((comp->string != NULL) && (comp->nb > 100)) {
14667 fprintf(stderr, "100 x %s\n", comp->string);
14668 comp->nb = 0;
14669 }
14670#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014671 pctxt = xmlXPathCompParserContext(comp, ctxt);
14672 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014673
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014674 if (resObj) {
14675 if (pctxt->value == NULL) {
14676 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014677 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014678 *resObj = NULL;
14679 } else {
14680 *resObj = valuePop(pctxt);
14681 }
Owen Taylor3473f882001-02-23 17:55:21 +000014682 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014683
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014684 /*
14685 * Pop all remaining objects from the stack.
14686 */
14687 if (pctxt->valueNr > 0) {
14688 xmlXPathObjectPtr tmp;
14689 int stack = 0;
14690
14691 do {
14692 tmp = valuePop(pctxt);
14693 if (tmp != NULL) {
William M. Brackd2f682a2007-05-15 19:42:08 +000014694 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014695 xmlXPathReleaseObject(ctxt, tmp);
14696 }
14697 } while (tmp != NULL);
14698 if ((stack != 0) &&
14699 ((toBool) || ((resObj) && (*resObj))))
14700 {
14701 xmlGenericError(xmlGenericErrorContext,
14702 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14703 stack);
14704 }
Owen Taylor3473f882001-02-23 17:55:21 +000014705 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014706
14707 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14708 xmlXPathFreeObject(*resObj);
14709 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014710 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014711 pctxt->comp = NULL;
14712 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014713#ifndef LIBXML_THREAD_ENABLED
14714 reentance--;
14715#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014716
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014717 return(res);
14718}
14719
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014720/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014721 * xmlXPathCompiledEval:
14722 * @comp: the compiled XPath expression
14723 * @ctx: the XPath context
14724 *
14725 * Evaluate the Precompiled XPath expression in the given context.
14726 *
14727 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14728 * the caller has to free the object.
14729 */
14730xmlXPathObjectPtr
14731xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14732{
14733 xmlXPathObjectPtr res = NULL;
14734
14735 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14736 return(res);
14737}
14738
14739/**
14740 * xmlXPathCompiledEvalToBoolean:
14741 * @comp: the compiled XPath expression
14742 * @ctxt: the XPath context
14743 *
14744 * Applies the XPath boolean() function on the result of the given
14745 * compiled expression.
14746 *
14747 * Returns 1 if the expression evaluated to true, 0 if to false and
14748 * -1 in API and internal errors.
14749 */
14750int
14751xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14752 xmlXPathContextPtr ctxt)
14753{
14754 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14755}
14756
14757/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014758 * xmlXPathEvalExpr:
14759 * @ctxt: the XPath Parser context
14760 *
14761 * Parse and evaluate an XPath expression in the given context,
14762 * then push the result on the context stack
14763 */
14764void
14765xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014766#ifdef XPATH_STREAMING
14767 xmlXPathCompExprPtr comp;
14768#endif
14769
Daniel Veillarda82b1822004-11-08 16:24:57 +000014770 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014771
14772#ifdef XPATH_STREAMING
14773 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14774 if (comp != NULL) {
14775 if (ctxt->comp != NULL)
14776 xmlXPathFreeCompExpr(ctxt->comp);
14777 ctxt->comp = comp;
14778 if (ctxt->cur != NULL)
14779 while (*ctxt->cur != 0) ctxt->cur++;
14780 } else
14781#endif
14782 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014783 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014784 /*
14785 * In this scenario the expression string will sit in ctxt->base.
14786 */
14787 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14788 (ctxt->comp != NULL) &&
14789 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014790 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014791 (ctxt->comp->last >= 0) &&
14792 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014793 {
14794 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014795 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014796 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014797 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014798 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014799 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014800}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014801
14802/**
14803 * xmlXPathEval:
14804 * @str: the XPath expression
14805 * @ctx: the XPath context
14806 *
14807 * Evaluate the XPath Location Path in the given context.
14808 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014809 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014810 * the caller has to free the object.
14811 */
14812xmlXPathObjectPtr
14813xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14814 xmlXPathParserContextPtr ctxt;
14815 xmlXPathObjectPtr res, tmp, init = NULL;
14816 int stack = 0;
14817
William M. Brackf13f77f2004-11-12 16:03:48 +000014818 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014819
William M. Brackf13f77f2004-11-12 16:03:48 +000014820 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014821
14822 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014823 if (ctxt == NULL)
14824 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014825 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014826
14827 if (ctxt->value == NULL) {
14828 xmlGenericError(xmlGenericErrorContext,
14829 "xmlXPathEval: evaluation failed\n");
14830 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014831 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14832#ifdef XPATH_STREAMING
14833 && (ctxt->comp->stream == NULL)
14834#endif
14835 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014836 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14837 res = NULL;
14838 } else {
14839 res = valuePop(ctxt);
14840 }
14841
14842 do {
14843 tmp = valuePop(ctxt);
14844 if (tmp != NULL) {
14845 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014846 stack++;
14847 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014848 }
14849 } while (tmp != NULL);
14850 if ((stack != 0) && (res != NULL)) {
14851 xmlGenericError(xmlGenericErrorContext,
14852 "xmlXPathEval: %d object left on the stack\n",
14853 stack);
14854 }
14855 if (ctxt->error != XPATH_EXPRESSION_OK) {
14856 xmlXPathFreeObject(res);
14857 res = NULL;
14858 }
14859
Owen Taylor3473f882001-02-23 17:55:21 +000014860 xmlXPathFreeParserContext(ctxt);
14861 return(res);
14862}
14863
14864/**
14865 * xmlXPathEvalExpression:
14866 * @str: the XPath expression
14867 * @ctxt: the XPath context
14868 *
14869 * Evaluate the XPath expression in the given context.
14870 *
14871 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14872 * the caller has to free the object.
14873 */
14874xmlXPathObjectPtr
14875xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14876 xmlXPathParserContextPtr pctxt;
14877 xmlXPathObjectPtr res, tmp;
14878 int stack = 0;
14879
William M. Brackf13f77f2004-11-12 16:03:48 +000014880 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014881
William M. Brackf13f77f2004-11-12 16:03:48 +000014882 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014883
14884 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014885 if (pctxt == NULL)
14886 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014887 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014888
Daniel Veillardc465ffc2006-10-17 19:39:33 +000014889 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000014890 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14891 res = NULL;
14892 } else {
14893 res = valuePop(pctxt);
14894 }
14895 do {
14896 tmp = valuePop(pctxt);
14897 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014898 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014899 stack++;
14900 }
14901 } while (tmp != NULL);
14902 if ((stack != 0) && (res != NULL)) {
14903 xmlGenericError(xmlGenericErrorContext,
14904 "xmlXPathEvalExpression: %d object left on the stack\n",
14905 stack);
14906 }
14907 xmlXPathFreeParserContext(pctxt);
14908 return(res);
14909}
14910
Daniel Veillard42766c02002-08-22 20:52:17 +000014911/************************************************************************
14912 * *
14913 * Extra functions not pertaining to the XPath spec *
14914 * *
14915 ************************************************************************/
14916/**
14917 * xmlXPathEscapeUriFunction:
14918 * @ctxt: the XPath Parser context
14919 * @nargs: the number of arguments
14920 *
14921 * Implement the escape-uri() XPath function
14922 * string escape-uri(string $str, bool $escape-reserved)
14923 *
14924 * This function applies the URI escaping rules defined in section 2 of [RFC
14925 * 2396] to the string supplied as $uri-part, which typically represents all
14926 * or part of a URI. The effect of the function is to replace any special
14927 * character in the string by an escape sequence of the form %xx%yy...,
14928 * where xxyy... is the hexadecimal representation of the octets used to
14929 * represent the character in UTF-8.
14930 *
14931 * The set of characters that are escaped depends on the setting of the
14932 * boolean argument $escape-reserved.
14933 *
14934 * If $escape-reserved is true, all characters are escaped other than lower
14935 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14936 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14937 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14938 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14939 * A-F).
14940 *
14941 * If $escape-reserved is false, the behavior differs in that characters
14942 * referred to in [RFC 2396] as reserved characters are not escaped. These
14943 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14944 *
14945 * [RFC 2396] does not define whether escaped URIs should use lower case or
14946 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14947 * compared using string comparison functions, this function must always use
14948 * the upper-case letters A-F.
14949 *
14950 * Generally, $escape-reserved should be set to true when escaping a string
14951 * that is to form a single part of a URI, and to false when escaping an
14952 * entire URI or URI reference.
14953 *
14954 * In the case of non-ascii characters, the string is encoded according to
14955 * utf-8 and then converted according to RFC 2396.
14956 *
14957 * Examples
14958 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14959 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14960 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14961 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14962 *
14963 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014964static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014965xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14966 xmlXPathObjectPtr str;
14967 int escape_reserved;
14968 xmlBufferPtr target;
14969 xmlChar *cptr;
14970 xmlChar escape[4];
14971
14972 CHECK_ARITY(2);
14973
14974 escape_reserved = xmlXPathPopBoolean(ctxt);
14975
14976 CAST_TO_STRING;
14977 str = valuePop(ctxt);
14978
14979 target = xmlBufferCreate();
14980
14981 escape[0] = '%';
14982 escape[3] = 0;
14983
14984 if (target) {
14985 for (cptr = str->stringval; *cptr; cptr++) {
14986 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14987 (*cptr >= 'a' && *cptr <= 'z') ||
14988 (*cptr >= '0' && *cptr <= '9') ||
14989 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14990 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14991 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14992 (*cptr == '%' &&
14993 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14994 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14995 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14996 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14997 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14998 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14999 (!escape_reserved &&
15000 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15001 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15002 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15003 *cptr == ','))) {
15004 xmlBufferAdd(target, cptr, 1);
15005 } else {
15006 if ((*cptr >> 4) < 10)
15007 escape[1] = '0' + (*cptr >> 4);
15008 else
15009 escape[1] = 'A' - 10 + (*cptr >> 4);
15010 if ((*cptr & 0xF) < 10)
15011 escape[2] = '0' + (*cptr & 0xF);
15012 else
15013 escape[2] = 'A' - 10 + (*cptr & 0xF);
15014
15015 xmlBufferAdd(target, &escape[0], 3);
15016 }
15017 }
15018 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015019 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15020 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015021 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015022 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015023}
15024
Owen Taylor3473f882001-02-23 17:55:21 +000015025/**
15026 * xmlXPathRegisterAllFunctions:
15027 * @ctxt: the XPath context
15028 *
15029 * Registers all default XPath functions in this context
15030 */
15031void
15032xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15033{
15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15035 xmlXPathBooleanFunction);
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15037 xmlXPathCeilingFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15039 xmlXPathCountFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15041 xmlXPathConcatFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15043 xmlXPathContainsFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15045 xmlXPathIdFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15047 xmlXPathFalseFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15049 xmlXPathFloorFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15051 xmlXPathLastFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15053 xmlXPathLangFunction);
15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15055 xmlXPathLocalNameFunction);
15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15057 xmlXPathNotFunction);
15058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15059 xmlXPathNameFunction);
15060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15061 xmlXPathNamespaceURIFunction);
15062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15063 xmlXPathNormalizeFunction);
15064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15065 xmlXPathNumberFunction);
15066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15067 xmlXPathPositionFunction);
15068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15069 xmlXPathRoundFunction);
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15071 xmlXPathStringFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15073 xmlXPathStringLengthFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15075 xmlXPathStartsWithFunction);
15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15077 xmlXPathSubstringFunction);
15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15079 xmlXPathSubstringBeforeFunction);
15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15081 xmlXPathSubstringAfterFunction);
15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15083 xmlXPathSumFunction);
15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15085 xmlXPathTrueFunction);
15086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15087 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015088
15089 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15090 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15091 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015092}
15093
15094#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015095#define bottom_xpath
15096#include "elfgcchack.h"