blob: 8c35e3078489190067bee18dd916a990b47aa93b [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
2651
2652#define INTEGER_DIGITS DBL_DIG
2653#define FRACTION_DIGITS (DBL_DIG + 1)
2654#define EXPONENT_DIGITS (3 + 2)
2655
2656/**
2657 * xmlXPathFormatNumber:
2658 * @number: number to format
2659 * @buffer: output buffer
2660 * @buffersize: size of output buffer
2661 *
2662 * Convert the number into a string representation.
2663 */
2664static void
2665xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2666{
Daniel Veillardcda96922001-08-21 10:56:31 +00002667 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002668 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002669 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002670 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002671 break;
2672 case -1:
2673 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002674 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002675 break;
2676 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002677 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002678 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002679 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002680 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002681 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002682 } else if (number == ((int) number)) {
2683 char work[30];
2684 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002685 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002686
2687 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002688 if (value == 0) {
2689 *ptr++ = '0';
2690 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002691 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002692 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002693 while ((*cur) && (ptr - buffer < buffersize)) {
2694 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002695 }
2696 }
2697 if (ptr - buffer < buffersize) {
2698 *ptr = 0;
2699 } else if (buffersize > 0) {
2700 ptr--;
2701 *ptr = 0;
2702 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002703 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002704 /* 3 is sign, decimal point, and terminating zero */
2705 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2706 int integer_place, fraction_place;
2707 char *ptr;
2708 char *after_fraction;
2709 double absolute_value;
2710 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002711
Bjorn Reese70a9da52001-04-21 16:57:29 +00002712 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002713
Bjorn Reese70a9da52001-04-21 16:57:29 +00002714 /*
2715 * First choose format - scientific or regular floating point.
2716 * In either case, result is in work, and after_fraction points
2717 * just past the fractional part.
2718 */
2719 if ( ((absolute_value > UPPER_DOUBLE) ||
2720 (absolute_value < LOWER_DOUBLE)) &&
2721 (absolute_value != 0.0) ) {
2722 /* Use scientific notation */
2723 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2724 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002725 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002726 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002727 while ((size > 0) && (work[size] != 'e')) size--;
2728 after_fraction = work + size;
2729
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002730 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002731 else {
2732 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002733 if (absolute_value > 0.0)
2734 integer_place = 1 + (int)log10(absolute_value);
2735 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002736 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002737 fraction_place = (integer_place > 0)
2738 ? DBL_DIG - integer_place
2739 : DBL_DIG;
2740 size = snprintf(work, sizeof(work), "%0.*f",
2741 fraction_place, number);
2742 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002743 }
2744
Bjorn Reese70a9da52001-04-21 16:57:29 +00002745 /* Remove fractional trailing zeroes */
2746 ptr = after_fraction;
2747 while (*(--ptr) == '0')
2748 ;
2749 if (*ptr != '.')
2750 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002751 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002752
2753 /* Finally copy result back to caller */
2754 size = strlen(work) + 1;
2755 if (size > buffersize) {
2756 work[buffersize - 1] = 0;
2757 size = buffersize;
2758 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002759 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002760 }
2761 break;
2762 }
2763}
2764
Owen Taylor3473f882001-02-23 17:55:21 +00002765
2766/************************************************************************
2767 * *
2768 * Routines to handle NodeSets *
2769 * *
2770 ************************************************************************/
2771
2772/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002773 * xmlXPathOrderDocElems:
2774 * @doc: an input document
2775 *
2776 * Call this routine to speed up XPath computation on static documents.
2777 * This stamps all the element nodes with the document order
2778 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002779 * field, the value stored is actually - the node number (starting at -1)
2780 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002781 *
William M. Brack08171912003-12-29 02:52:11 +00002782 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002783 * of error.
2784 */
2785long
2786xmlXPathOrderDocElems(xmlDocPtr doc) {
2787 long count = 0;
2788 xmlNodePtr cur;
2789
2790 if (doc == NULL)
2791 return(-1);
2792 cur = doc->children;
2793 while (cur != NULL) {
2794 if (cur->type == XML_ELEMENT_NODE) {
2795 cur->content = (void *) (-(++count));
2796 if (cur->children != NULL) {
2797 cur = cur->children;
2798 continue;
2799 }
2800 }
2801 if (cur->next != NULL) {
2802 cur = cur->next;
2803 continue;
2804 }
2805 do {
2806 cur = cur->parent;
2807 if (cur == NULL)
2808 break;
2809 if (cur == (xmlNodePtr) doc) {
2810 cur = NULL;
2811 break;
2812 }
2813 if (cur->next != NULL) {
2814 cur = cur->next;
2815 break;
2816 }
2817 } while (cur != NULL);
2818 }
2819 return(count);
2820}
2821
2822/**
Owen Taylor3473f882001-02-23 17:55:21 +00002823 * xmlXPathCmpNodes:
2824 * @node1: the first node
2825 * @node2: the second node
2826 *
2827 * Compare two nodes w.r.t document order
2828 *
2829 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002830 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002831 */
2832int
2833xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2834 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002835 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002836 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlNodePtr cur, root;
2838
2839 if ((node1 == NULL) || (node2 == NULL))
2840 return(-2);
2841 /*
2842 * a couple of optimizations which will avoid computations in most cases
2843 */
William M. Brackee0b9822007-03-07 08:15:01 +00002844 if (node1 == node2) /* trivial case */
2845 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002846 if (node1->type == XML_ATTRIBUTE_NODE) {
2847 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002848 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002849 node1 = node1->parent;
2850 }
2851 if (node2->type == XML_ATTRIBUTE_NODE) {
2852 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002853 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002854 node2 = node2->parent;
2855 }
2856 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002857 if (attr1 == attr2) {
2858 /* not required, but we keep attributes in order */
2859 if (attr1 != 0) {
2860 cur = attrNode2->prev;
2861 while (cur != NULL) {
2862 if (cur == attrNode1)
2863 return (1);
2864 cur = cur->prev;
2865 }
2866 return (-1);
2867 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002868 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002869 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002870 if (attr2 == 1)
2871 return(1);
2872 return(-1);
2873 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002874 if ((node1->type == XML_NAMESPACE_DECL) ||
2875 (node2->type == XML_NAMESPACE_DECL))
2876 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002877 if (node1 == node2->prev)
2878 return(1);
2879 if (node1 == node2->next)
2880 return(-1);
2881
2882 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002883 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002884 */
2885 if ((node1->type == XML_ELEMENT_NODE) &&
2886 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002887 (0 > (long) node1->content) &&
2888 (0 > (long) node2->content) &&
2889 (node1->doc == node2->doc)) {
2890 long l1, l2;
2891
2892 l1 = -((long) node1->content);
2893 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002894 if (l1 < l2)
2895 return(1);
2896 if (l1 > l2)
2897 return(-1);
2898 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002899
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002900 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002901 * compute depth to root
2902 */
2903 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2904 if (cur == node1)
2905 return(1);
2906 depth2++;
2907 }
2908 root = cur;
2909 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2910 if (cur == node2)
2911 return(-1);
2912 depth1++;
2913 }
2914 /*
2915 * Distinct document (or distinct entities :-( ) case.
2916 */
2917 if (root != cur) {
2918 return(-2);
2919 }
2920 /*
2921 * get the nearest common ancestor.
2922 */
2923 while (depth1 > depth2) {
2924 depth1--;
2925 node1 = node1->parent;
2926 }
2927 while (depth2 > depth1) {
2928 depth2--;
2929 node2 = node2->parent;
2930 }
2931 while (node1->parent != node2->parent) {
2932 node1 = node1->parent;
2933 node2 = node2->parent;
2934 /* should not happen but just in case ... */
2935 if ((node1 == NULL) || (node2 == NULL))
2936 return(-2);
2937 }
2938 /*
2939 * Find who's first.
2940 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002941 if (node1 == node2->prev)
2942 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002943 if (node1 == node2->next)
2944 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002945 /*
2946 * Speedup using document order if availble.
2947 */
2948 if ((node1->type == XML_ELEMENT_NODE) &&
2949 (node2->type == XML_ELEMENT_NODE) &&
2950 (0 > (long) node1->content) &&
2951 (0 > (long) node2->content) &&
2952 (node1->doc == node2->doc)) {
2953 long l1, l2;
2954
2955 l1 = -((long) node1->content);
2956 l2 = -((long) node2->content);
2957 if (l1 < l2)
2958 return(1);
2959 if (l1 > l2)
2960 return(-1);
2961 }
2962
Owen Taylor3473f882001-02-23 17:55:21 +00002963 for (cur = node1->next;cur != NULL;cur = cur->next)
2964 if (cur == node2)
2965 return(1);
2966 return(-1); /* assume there is no sibling list corruption */
2967}
2968
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002969#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002970/**
2971 * xmlXPathCmpNodesExt:
2972 * @node1: the first node
2973 * @node2: the second node
2974 *
2975 * Compare two nodes w.r.t document order.
2976 * This one is optimized for handling of non-element nodes.
2977 *
2978 * Returns -2 in case of error 1 if first point < second point, 0 if
2979 * it's the same node, -1 otherwise
2980 */
2981static int
2982xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2983 int depth1, depth2;
2984 int misc = 0, precedence1 = 0, precedence2 = 0;
2985 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2986 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002987 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002988
2989 if ((node1 == NULL) || (node2 == NULL))
2990 return(-2);
2991
2992 if (node1 == node2)
2993 return(0);
2994
2995 /*
2996 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002998 switch (node1->type) {
2999 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003000 if (node2->type == XML_ELEMENT_NODE) {
3001 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3002 (0 > (long) node2->content) &&
3003 (node1->doc == node2->doc))
3004 {
3005 l1 = -((long) node1->content);
3006 l2 = -((long) node2->content);
3007 if (l1 < l2)
3008 return(1);
3009 if (l1 > l2)
3010 return(-1);
3011 } else
3012 goto turtle_comparison;
3013 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003014 break;
3015 case XML_ATTRIBUTE_NODE:
3016 precedence1 = 1; /* element is owner */
3017 miscNode1 = node1;
3018 node1 = node1->parent;
3019 misc = 1;
3020 break;
3021 case XML_TEXT_NODE:
3022 case XML_CDATA_SECTION_NODE:
3023 case XML_COMMENT_NODE:
3024 case XML_PI_NODE: {
3025 miscNode1 = node1;
3026 /*
3027 * Find nearest element node.
3028 */
3029 if (node1->prev != NULL) {
3030 do {
3031 node1 = node1->prev;
3032 if (node1->type == XML_ELEMENT_NODE) {
3033 precedence1 = 3; /* element in prev-sibl axis */
3034 break;
3035 }
3036 if (node1->prev == NULL) {
3037 precedence1 = 2; /* element is parent */
3038 /*
3039 * URGENT TODO: Are there any cases, where the
3040 * parent of such a node is not an element node?
3041 */
3042 node1 = node1->parent;
3043 break;
3044 }
3045 } while (1);
3046 } else {
3047 precedence1 = 2; /* element is parent */
3048 node1 = node1->parent;
3049 }
3050 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3051 /*
3052 * Fallback for whatever case.
3053 */
3054 node1 = miscNode1;
3055 precedence1 = 0;
3056 } else
3057 misc = 1;
3058 }
3059 break;
3060 case XML_NAMESPACE_DECL:
3061 /*
3062 * TODO: why do we return 1 for namespace nodes?
3063 */
3064 return(1);
3065 default:
3066 break;
3067 }
3068 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003069 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003070 break;
3071 case XML_ATTRIBUTE_NODE:
3072 precedence2 = 1; /* element is owner */
3073 miscNode2 = node2;
3074 node2 = node2->parent;
3075 misc = 1;
3076 break;
3077 case XML_TEXT_NODE:
3078 case XML_CDATA_SECTION_NODE:
3079 case XML_COMMENT_NODE:
3080 case XML_PI_NODE: {
3081 miscNode2 = node2;
3082 if (node2->prev != NULL) {
3083 do {
3084 node2 = node2->prev;
3085 if (node2->type == XML_ELEMENT_NODE) {
3086 precedence2 = 3; /* element in prev-sibl axis */
3087 break;
3088 }
3089 if (node2->prev == NULL) {
3090 precedence2 = 2; /* element is parent */
3091 node2 = node2->parent;
3092 break;
3093 }
3094 } while (1);
3095 } else {
3096 precedence2 = 2; /* element is parent */
3097 node2 = node2->parent;
3098 }
3099 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3100 (0 <= (long) node1->content))
3101 {
3102 node2 = miscNode2;
3103 precedence2 = 0;
3104 } else
3105 misc = 1;
3106 }
3107 break;
3108 case XML_NAMESPACE_DECL:
3109 return(1);
3110 default:
3111 break;
3112 }
3113 if (misc) {
3114 if (node1 == node2) {
3115 if (precedence1 == precedence2) {
3116 /*
3117 * The ugly case; but normally there aren't many
3118 * adjacent non-element nodes around.
3119 */
3120 cur = miscNode2->prev;
3121 while (cur != NULL) {
3122 if (cur == miscNode1)
3123 return(1);
3124 if (cur->type == XML_ELEMENT_NODE)
3125 return(-1);
3126 cur = cur->prev;
3127 }
3128 return (-1);
3129 } else {
3130 /*
3131 * Evaluate based on higher precedence wrt to the element.
3132 * TODO: This assumes attributes are sorted before content.
3133 * Is this 100% correct?
3134 */
3135 if (precedence1 < precedence2)
3136 return(1);
3137 else
3138 return(-1);
3139 }
3140 }
3141 /*
3142 * Special case: One of the helper-elements is contained by the other.
3143 * <foo>
3144 * <node2>
3145 * <node1>Text-1(precedence1 == 2)</node1>
3146 * </node2>
3147 * Text-6(precedence2 == 3)
3148 * </foo>
3149 */
3150 if ((precedence2 == 3) && (precedence1 > 1)) {
3151 cur = node1->parent;
3152 while (cur) {
3153 if (cur == node2)
3154 return(1);
3155 cur = cur->parent;
3156 }
3157 }
3158 if ((precedence1 == 3) && (precedence2 > 1)) {
3159 cur = node2->parent;
3160 while (cur) {
3161 if (cur == node1)
3162 return(-1);
3163 cur = cur->parent;
3164 }
3165 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003166 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003167
3168 /*
3169 * Speedup using document order if availble.
3170 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003171 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003172 (node2->type == XML_ELEMENT_NODE) &&
3173 (0 > (long) node1->content) &&
3174 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003175 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003176
3177 l1 = -((long) node1->content);
3178 l2 = -((long) node2->content);
3179 if (l1 < l2)
3180 return(1);
3181 if (l1 > l2)
3182 return(-1);
3183 }
3184
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003185turtle_comparison:
3186
3187 if (node1 == node2->prev)
3188 return(1);
3189 if (node1 == node2->next)
3190 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003191 /*
3192 * compute depth to root
3193 */
3194 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3195 if (cur == node1)
3196 return(1);
3197 depth2++;
3198 }
3199 root = cur;
3200 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3201 if (cur == node2)
3202 return(-1);
3203 depth1++;
3204 }
3205 /*
3206 * Distinct document (or distinct entities :-( ) case.
3207 */
3208 if (root != cur) {
3209 return(-2);
3210 }
3211 /*
3212 * get the nearest common ancestor.
3213 */
3214 while (depth1 > depth2) {
3215 depth1--;
3216 node1 = node1->parent;
3217 }
3218 while (depth2 > depth1) {
3219 depth2--;
3220 node2 = node2->parent;
3221 }
3222 while (node1->parent != node2->parent) {
3223 node1 = node1->parent;
3224 node2 = node2->parent;
3225 /* should not happen but just in case ... */
3226 if ((node1 == NULL) || (node2 == NULL))
3227 return(-2);
3228 }
3229 /*
3230 * Find who's first.
3231 */
3232 if (node1 == node2->prev)
3233 return(1);
3234 if (node1 == node2->next)
3235 return(-1);
3236 /*
3237 * Speedup using document order if availble.
3238 */
3239 if ((node1->type == XML_ELEMENT_NODE) &&
3240 (node2->type == XML_ELEMENT_NODE) &&
3241 (0 > (long) node1->content) &&
3242 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003243 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003244
3245 l1 = -((long) node1->content);
3246 l2 = -((long) node2->content);
3247 if (l1 < l2)
3248 return(1);
3249 if (l1 > l2)
3250 return(-1);
3251 }
3252
3253 for (cur = node1->next;cur != NULL;cur = cur->next)
3254 if (cur == node2)
3255 return(1);
3256 return(-1); /* assume there is no sibling list corruption */
3257}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003258#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003259
Owen Taylor3473f882001-02-23 17:55:21 +00003260/**
3261 * xmlXPathNodeSetSort:
3262 * @set: the node set
3263 *
3264 * Sort the node set in document order
3265 */
3266void
3267xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003268 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003269 xmlNodePtr tmp;
3270
3271 if (set == NULL)
3272 return;
3273
3274 /* Use Shell's sort to sort the node-set */
3275 len = set->nodeNr;
3276 for (incr = len / 2; incr > 0; incr /= 2) {
3277 for (i = incr; i < len; i++) {
3278 j = i - incr;
3279 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003280#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003281 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3282 set->nodeTab[j + incr]) == -1)
3283#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003284 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003285 set->nodeTab[j + incr]) == -1)
3286#endif
3287 {
Owen Taylor3473f882001-02-23 17:55:21 +00003288 tmp = set->nodeTab[j];
3289 set->nodeTab[j] = set->nodeTab[j + incr];
3290 set->nodeTab[j + incr] = tmp;
3291 j -= incr;
3292 } else
3293 break;
3294 }
3295 }
3296 }
3297}
3298
3299#define XML_NODESET_DEFAULT 10
3300/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003301 * xmlXPathNodeSetDupNs:
3302 * @node: the parent node of the namespace XPath node
3303 * @ns: the libxml namespace declaration node.
3304 *
3305 * Namespace node in libxml don't match the XPath semantic. In a node set
3306 * the namespace nodes are duplicated and the next pointer is set to the
3307 * parent node in the XPath semantic.
3308 *
3309 * Returns the newly created object.
3310 */
3311static xmlNodePtr
3312xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3313 xmlNsPtr cur;
3314
3315 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3316 return(NULL);
3317 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3318 return((xmlNodePtr) ns);
3319
3320 /*
3321 * Allocate a new Namespace and fill the fields.
3322 */
3323 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3324 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003325 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003326 return(NULL);
3327 }
3328 memset(cur, 0, sizeof(xmlNs));
3329 cur->type = XML_NAMESPACE_DECL;
3330 if (ns->href != NULL)
3331 cur->href = xmlStrdup(ns->href);
3332 if (ns->prefix != NULL)
3333 cur->prefix = xmlStrdup(ns->prefix);
3334 cur->next = (xmlNsPtr) node;
3335 return((xmlNodePtr) cur);
3336}
3337
3338/**
3339 * xmlXPathNodeSetFreeNs:
3340 * @ns: the XPath namespace node found in a nodeset.
3341 *
William M. Brack08171912003-12-29 02:52:11 +00003342 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003343 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003344 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003345 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003346void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003347xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3348 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3349 return;
3350
3351 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3352 if (ns->href != NULL)
3353 xmlFree((xmlChar *)ns->href);
3354 if (ns->prefix != NULL)
3355 xmlFree((xmlChar *)ns->prefix);
3356 xmlFree(ns);
3357 }
3358}
3359
3360/**
Owen Taylor3473f882001-02-23 17:55:21 +00003361 * xmlXPathNodeSetCreate:
3362 * @val: an initial xmlNodePtr, or NULL
3363 *
3364 * Create a new xmlNodeSetPtr of type double and of value @val
3365 *
3366 * Returns the newly created object.
3367 */
3368xmlNodeSetPtr
3369xmlXPathNodeSetCreate(xmlNodePtr val) {
3370 xmlNodeSetPtr ret;
3371
3372 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3373 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003374 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003375 return(NULL);
3376 }
3377 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3378 if (val != NULL) {
3379 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3380 sizeof(xmlNodePtr));
3381 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003382 xmlXPathErrMemory(NULL, "creating nodeset\n");
3383 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003384 return(NULL);
3385 }
3386 memset(ret->nodeTab, 0 ,
3387 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3388 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003389 if (val->type == XML_NAMESPACE_DECL) {
3390 xmlNsPtr ns = (xmlNsPtr) val;
3391
3392 ret->nodeTab[ret->nodeNr++] =
3393 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3394 } else
3395 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003396 }
3397 return(ret);
3398}
3399
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003400/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003401 * xmlXPathNodeSetCreateSize:
3402 * @size: the initial size of the set
3403 *
3404 * Create a new xmlNodeSetPtr of type double and of value @val
3405 *
3406 * Returns the newly created object.
3407 */
3408static xmlNodeSetPtr
3409xmlXPathNodeSetCreateSize(int size) {
3410 xmlNodeSetPtr ret;
3411
3412 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3413 if (ret == NULL) {
3414 xmlXPathErrMemory(NULL, "creating nodeset\n");
3415 return(NULL);
3416 }
3417 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3418 if (size < XML_NODESET_DEFAULT)
3419 size = XML_NODESET_DEFAULT;
3420 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3421 if (ret->nodeTab == NULL) {
3422 xmlXPathErrMemory(NULL, "creating nodeset\n");
3423 xmlFree(ret);
3424 return(NULL);
3425 }
3426 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3427 ret->nodeMax = size;
3428 return(ret);
3429}
3430
3431/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003432 * xmlXPathNodeSetContains:
3433 * @cur: the node-set
3434 * @val: the node
3435 *
3436 * checks whether @cur contains @val
3437 *
3438 * Returns true (1) if @cur contains @val, false (0) otherwise
3439 */
3440int
3441xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3442 int i;
3443
Daniel Veillarda82b1822004-11-08 16:24:57 +00003444 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003445 if (val->type == XML_NAMESPACE_DECL) {
3446 for (i = 0; i < cur->nodeNr; i++) {
3447 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3448 xmlNsPtr ns1, ns2;
3449
3450 ns1 = (xmlNsPtr) val;
3451 ns2 = (xmlNsPtr) cur->nodeTab[i];
3452 if (ns1 == ns2)
3453 return(1);
3454 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3455 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3456 return(1);
3457 }
3458 }
3459 } else {
3460 for (i = 0; i < cur->nodeNr; i++) {
3461 if (cur->nodeTab[i] == val)
3462 return(1);
3463 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003464 }
3465 return(0);
3466}
3467
3468/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003469 * xmlXPathNodeSetAddNs:
3470 * @cur: the initial node set
3471 * @node: the hosting node
3472 * @ns: a the namespace node
3473 *
3474 * add a new namespace node to an existing NodeSet
3475 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003476void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003477xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3478 int i;
3479
Daniel Veillarda82b1822004-11-08 16:24:57 +00003480
3481 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3482 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003483 (node->type != XML_ELEMENT_NODE))
3484 return;
3485
William M. Brack08171912003-12-29 02:52:11 +00003486 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003487 /*
William M. Brack08171912003-12-29 02:52:11 +00003488 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003489 */
3490 for (i = 0;i < cur->nodeNr;i++) {
3491 if ((cur->nodeTab[i] != NULL) &&
3492 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003493 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003494 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3495 return;
3496 }
3497
3498 /*
3499 * grow the nodeTab if needed
3500 */
3501 if (cur->nodeMax == 0) {
3502 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3503 sizeof(xmlNodePtr));
3504 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003505 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003506 return;
3507 }
3508 memset(cur->nodeTab, 0 ,
3509 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3510 cur->nodeMax = XML_NODESET_DEFAULT;
3511 } else if (cur->nodeNr == cur->nodeMax) {
3512 xmlNodePtr *temp;
3513
3514 cur->nodeMax *= 2;
3515 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3516 sizeof(xmlNodePtr));
3517 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003518 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003519 return;
3520 }
3521 cur->nodeTab = temp;
3522 }
3523 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3524}
3525
3526/**
Owen Taylor3473f882001-02-23 17:55:21 +00003527 * xmlXPathNodeSetAdd:
3528 * @cur: the initial node set
3529 * @val: a new xmlNodePtr
3530 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003531 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003532 */
3533void
3534xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3535 int i;
3536
Daniel Veillarda82b1822004-11-08 16:24:57 +00003537 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003538
Daniel Veillardef0b4502003-03-24 13:57:34 +00003539#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003540 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3541 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003542#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003543
William M. Brack08171912003-12-29 02:52:11 +00003544 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003545 /*
William M. Brack08171912003-12-29 02:52:11 +00003546 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003547 */
3548 for (i = 0;i < cur->nodeNr;i++)
3549 if (cur->nodeTab[i] == val) return;
3550
3551 /*
3552 * grow the nodeTab if needed
3553 */
3554 if (cur->nodeMax == 0) {
3555 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3556 sizeof(xmlNodePtr));
3557 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003558 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003559 return;
3560 }
3561 memset(cur->nodeTab, 0 ,
3562 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3563 cur->nodeMax = XML_NODESET_DEFAULT;
3564 } else if (cur->nodeNr == cur->nodeMax) {
3565 xmlNodePtr *temp;
3566
3567 cur->nodeMax *= 2;
3568 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3569 sizeof(xmlNodePtr));
3570 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003571 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003572 return;
3573 }
3574 cur->nodeTab = temp;
3575 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003576 if (val->type == XML_NAMESPACE_DECL) {
3577 xmlNsPtr ns = (xmlNsPtr) val;
3578
3579 cur->nodeTab[cur->nodeNr++] =
3580 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3581 } else
3582 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003583}
3584
3585/**
3586 * xmlXPathNodeSetAddUnique:
3587 * @cur: the initial node set
3588 * @val: a new xmlNodePtr
3589 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003590 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003591 * when we are sure the node is not already in the set.
3592 */
3593void
3594xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003595 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003596
Daniel Veillardef0b4502003-03-24 13:57:34 +00003597#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003598 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3599 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003600#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003601
William M. Brack08171912003-12-29 02:52:11 +00003602 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003603 /*
3604 * grow the nodeTab if needed
3605 */
3606 if (cur->nodeMax == 0) {
3607 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3608 sizeof(xmlNodePtr));
3609 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003610 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003611 return;
3612 }
3613 memset(cur->nodeTab, 0 ,
3614 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3615 cur->nodeMax = XML_NODESET_DEFAULT;
3616 } else if (cur->nodeNr == cur->nodeMax) {
3617 xmlNodePtr *temp;
3618
3619 cur->nodeMax *= 2;
3620 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3621 sizeof(xmlNodePtr));
3622 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003623 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003624 return;
3625 }
3626 cur->nodeTab = temp;
3627 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003628 if (val->type == XML_NAMESPACE_DECL) {
3629 xmlNsPtr ns = (xmlNsPtr) val;
3630
3631 cur->nodeTab[cur->nodeNr++] =
3632 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3633 } else
3634 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003635}
3636
3637/**
3638 * xmlXPathNodeSetMerge:
3639 * @val1: the first NodeSet or NULL
3640 * @val2: the second NodeSet
3641 *
3642 * Merges two nodesets, all nodes from @val2 are added to @val1
3643 * if @val1 is NULL, a new set is created and copied from @val2
3644 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003645 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003646 */
3647xmlNodeSetPtr
3648xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003649 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003650 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003651
3652 if (val2 == NULL) return(val1);
3653 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003654 val1 = xmlXPathNodeSetCreate(NULL);
3655#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003656 /*
3657 * TODO: The optimization won't work in every case, since
3658 * those nasty namespace nodes need to be added with
3659 * xmlXPathNodeSetDupNs() to the set; thus a pure
3660 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003661 * If there was a flag on the nodesetval, indicating that
3662 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003663 */
3664 /*
3665 * Optimization: Create an equally sized node-set
3666 * and memcpy the content.
3667 */
3668 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3669 if (val1 == NULL)
3670 return(NULL);
3671 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003672 if (val2->nodeNr == 1)
3673 *(val1->nodeTab) = *(val2->nodeTab);
3674 else {
3675 memcpy(val1->nodeTab, val2->nodeTab,
3676 val2->nodeNr * sizeof(xmlNodePtr));
3677 }
3678 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003679 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003680 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003681#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003682 }
3683
William M. Brack08171912003-12-29 02:52:11 +00003684 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003685 initNr = val1->nodeNr;
3686
3687 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003688 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003689 /*
William M. Brack08171912003-12-29 02:52:11 +00003690 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003691 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003692 skip = 0;
3693 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003694 n1 = val1->nodeTab[j];
3695 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003696 skip = 1;
3697 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003698 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3699 (n2->type == XML_NAMESPACE_DECL)) {
3700 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3701 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3702 ((xmlNsPtr) n2)->prefix)))
3703 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003704 skip = 1;
3705 break;
3706 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003707 }
3708 }
3709 if (skip)
3710 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003711
3712 /*
3713 * grow the nodeTab if needed
3714 */
3715 if (val1->nodeMax == 0) {
3716 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3717 sizeof(xmlNodePtr));
3718 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003719 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003720 return(NULL);
3721 }
3722 memset(val1->nodeTab, 0 ,
3723 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3724 val1->nodeMax = XML_NODESET_DEFAULT;
3725 } else if (val1->nodeNr == val1->nodeMax) {
3726 xmlNodePtr *temp;
3727
3728 val1->nodeMax *= 2;
3729 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3730 sizeof(xmlNodePtr));
3731 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003732 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003733 return(NULL);
3734 }
3735 val1->nodeTab = temp;
3736 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003737 if (n2->type == XML_NAMESPACE_DECL) {
3738 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003739
3740 val1->nodeTab[val1->nodeNr++] =
3741 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3742 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003743 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003744 }
3745
3746 return(val1);
3747}
3748
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003749#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003750/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003751 * xmlXPathNodeSetMergeUnique:
3752 * @val1: the first NodeSet or NULL
3753 * @val2: the second NodeSet
3754 *
3755 * Merges two nodesets, all nodes from @val2 are added to @val1
3756 * if @val1 is NULL, a new set is created and copied from @val2
3757 *
3758 * Returns @val1 once extended or NULL in case of error.
3759 */
3760static xmlNodeSetPtr
3761xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003762 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003763
3764 if (val2 == NULL) return(val1);
3765 if (val1 == NULL) {
3766 val1 = xmlXPathNodeSetCreate(NULL);
3767 }
3768
William M. Brack08171912003-12-29 02:52:11 +00003769 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003770
3771 for (i = 0;i < val2->nodeNr;i++) {
3772 /*
3773 * grow the nodeTab if needed
3774 */
3775 if (val1->nodeMax == 0) {
3776 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3777 sizeof(xmlNodePtr));
3778 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003779 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003780 return(NULL);
3781 }
3782 memset(val1->nodeTab, 0 ,
3783 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3784 val1->nodeMax = XML_NODESET_DEFAULT;
3785 } else if (val1->nodeNr == val1->nodeMax) {
3786 xmlNodePtr *temp;
3787
3788 val1->nodeMax *= 2;
3789 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3790 sizeof(xmlNodePtr));
3791 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003792 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003793 return(NULL);
3794 }
3795 val1->nodeTab = temp;
3796 }
3797 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3798 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3799
3800 val1->nodeTab[val1->nodeNr++] =
3801 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3802 } else
3803 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3804 }
3805
3806 return(val1);
3807}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003808#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3809
3810/**
3811 * xmlXPathNodeSetMergeAndClear:
3812 * @set1: the first NodeSet or NULL
3813 * @set2: the second NodeSet
3814 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3815 *
3816 * Merges two nodesets, all nodes from @set2 are added to @set1
3817 * if @set1 is NULL, a new set is created and copied from @set2.
3818 * Checks for duplicate nodes. Clears set2.
3819 *
3820 * Returns @set1 once extended or NULL in case of error.
3821 */
3822static xmlNodeSetPtr
3823xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3824 int hasNullEntries)
3825{
3826 if ((set1 == NULL) && (hasNullEntries == 0)) {
3827 /*
3828 * Note that doing a memcpy of the list, namespace nodes are
3829 * just assigned to set1, since set2 is cleared anyway.
3830 */
3831 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3832 if (set1 == NULL)
3833 return(NULL);
3834 if (set2->nodeNr != 0) {
3835 memcpy(set1->nodeTab, set2->nodeTab,
3836 set2->nodeNr * sizeof(xmlNodePtr));
3837 set1->nodeNr = set2->nodeNr;
3838 }
3839 } else {
3840 int i, j, initNbSet1;
3841 xmlNodePtr n1, n2;
3842
3843 if (set1 == NULL)
3844 set1 = xmlXPathNodeSetCreate(NULL);
3845
3846 initNbSet1 = set1->nodeNr;
3847 for (i = 0;i < set2->nodeNr;i++) {
3848 n2 = set2->nodeTab[i];
3849 /*
3850 * Skip NULLed entries.
3851 */
3852 if (n2 == NULL)
3853 continue;
3854 /*
3855 * Skip duplicates.
3856 */
3857 for (j = 0; j < initNbSet1; j++) {
3858 n1 = set1->nodeTab[j];
3859 if (n1 == n2) {
3860 goto skip_node;
3861 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3862 (n2->type == XML_NAMESPACE_DECL))
3863 {
3864 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3865 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3866 ((xmlNsPtr) n2)->prefix)))
3867 {
3868 /*
3869 * Free the namespace node.
3870 */
3871 set2->nodeTab[i] = NULL;
3872 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3873 goto skip_node;
3874 }
3875 }
3876 }
3877 /*
3878 * grow the nodeTab if needed
3879 */
3880 if (set1->nodeMax == 0) {
3881 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3882 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3883 if (set1->nodeTab == NULL) {
3884 xmlXPathErrMemory(NULL, "merging nodeset\n");
3885 return(NULL);
3886 }
3887 memset(set1->nodeTab, 0,
3888 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3889 set1->nodeMax = XML_NODESET_DEFAULT;
3890 } else if (set1->nodeNr >= set1->nodeMax) {
3891 xmlNodePtr *temp;
3892
3893 set1->nodeMax *= 2;
3894 temp = (xmlNodePtr *) xmlRealloc(
3895 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3896 if (temp == NULL) {
3897 xmlXPathErrMemory(NULL, "merging nodeset\n");
3898 return(NULL);
3899 }
3900 set1->nodeTab = temp;
3901 }
3902 if (n2->type == XML_NAMESPACE_DECL) {
3903 xmlNsPtr ns = (xmlNsPtr) n2;
3904
3905 set1->nodeTab[set1->nodeNr++] =
3906 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3907 } else
3908 set1->nodeTab[set1->nodeNr++] = n2;
3909skip_node:
3910 {}
3911 }
3912 }
3913 set2->nodeNr = 0;
3914 return(set1);
3915}
3916
3917/**
3918 * xmlXPathNodeSetMergeAndClearNoDupls:
3919 * @set1: the first NodeSet or NULL
3920 * @set2: the second NodeSet
3921 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3922 *
3923 * Merges two nodesets, all nodes from @set2 are added to @set1
3924 * if @set1 is NULL, a new set is created and copied from @set2.
3925 * Doesn't chack for duplicate nodes. Clears set2.
3926 *
3927 * Returns @set1 once extended or NULL in case of error.
3928 */
3929static xmlNodeSetPtr
3930xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3931 int hasNullEntries)
3932{
3933 if (set2 == NULL)
3934 return(set1);
3935 if ((set1 == NULL) && (hasNullEntries == 0)) {
3936 /*
3937 * Note that doing a memcpy of the list, namespace nodes are
3938 * just assigned to set1, since set2 is cleared anyway.
3939 */
3940 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3941 if (set1 == NULL)
3942 return(NULL);
3943 if (set2->nodeNr != 0) {
3944 memcpy(set1->nodeTab, set2->nodeTab,
3945 set2->nodeNr * sizeof(xmlNodePtr));
3946 set1->nodeNr = set2->nodeNr;
3947 }
3948 } else {
3949 int i;
3950 xmlNodePtr n2;
3951
3952 if (set1 == NULL)
3953 set1 = xmlXPathNodeSetCreate(NULL);
3954
3955 for (i = 0;i < set2->nodeNr;i++) {
3956 n2 = set2->nodeTab[i];
3957 /*
3958 * Skip NULLed entries.
3959 */
3960 if (n2 == NULL)
3961 continue;
3962 if (set1->nodeMax == 0) {
3963 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3964 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3965 if (set1->nodeTab == NULL) {
3966 xmlXPathErrMemory(NULL, "merging nodeset\n");
3967 return(NULL);
3968 }
3969 memset(set1->nodeTab, 0,
3970 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3971 set1->nodeMax = XML_NODESET_DEFAULT;
3972 } else if (set1->nodeNr >= set1->nodeMax) {
3973 xmlNodePtr *temp;
3974
3975 set1->nodeMax *= 2;
3976 temp = (xmlNodePtr *) xmlRealloc(
3977 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3978 if (temp == NULL) {
3979 xmlXPathErrMemory(NULL, "merging nodeset\n");
3980 return(NULL);
3981 }
3982 set1->nodeTab = temp;
3983 }
3984 set1->nodeTab[set1->nodeNr++] = n2;
3985 }
3986 }
3987 set2->nodeNr = 0;
3988 return(set1);
3989}
Daniel Veillard75be0132002-03-13 10:03:35 +00003990
3991/**
Owen Taylor3473f882001-02-23 17:55:21 +00003992 * xmlXPathNodeSetDel:
3993 * @cur: the initial node set
3994 * @val: an xmlNodePtr
3995 *
3996 * Removes an xmlNodePtr from an existing NodeSet
3997 */
3998void
3999xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4000 int i;
4001
4002 if (cur == NULL) return;
4003 if (val == NULL) return;
4004
4005 /*
William M. Brack08171912003-12-29 02:52:11 +00004006 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004007 */
4008 for (i = 0;i < cur->nodeNr;i++)
4009 if (cur->nodeTab[i] == val) break;
4010
William M. Brack08171912003-12-29 02:52:11 +00004011 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004012#ifdef DEBUG
4013 xmlGenericError(xmlGenericErrorContext,
4014 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4015 val->name);
4016#endif
4017 return;
4018 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004019 if ((cur->nodeTab[i] != NULL) &&
4020 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4021 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004022 cur->nodeNr--;
4023 for (;i < cur->nodeNr;i++)
4024 cur->nodeTab[i] = cur->nodeTab[i + 1];
4025 cur->nodeTab[cur->nodeNr] = NULL;
4026}
4027
4028/**
4029 * xmlXPathNodeSetRemove:
4030 * @cur: the initial node set
4031 * @val: the index to remove
4032 *
4033 * Removes an entry from an existing NodeSet list.
4034 */
4035void
4036xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4037 if (cur == NULL) return;
4038 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004039 if ((cur->nodeTab[val] != NULL) &&
4040 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4041 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004042 cur->nodeNr--;
4043 for (;val < cur->nodeNr;val++)
4044 cur->nodeTab[val] = cur->nodeTab[val + 1];
4045 cur->nodeTab[cur->nodeNr] = NULL;
4046}
4047
4048/**
4049 * xmlXPathFreeNodeSet:
4050 * @obj: the xmlNodeSetPtr to free
4051 *
4052 * Free the NodeSet compound (not the actual nodes !).
4053 */
4054void
4055xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4056 if (obj == NULL) return;
4057 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004058 int i;
4059
William M. Brack08171912003-12-29 02:52:11 +00004060 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004061 for (i = 0;i < obj->nodeNr;i++)
4062 if ((obj->nodeTab[i] != NULL) &&
4063 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4064 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004065 xmlFree(obj->nodeTab);
4066 }
Owen Taylor3473f882001-02-23 17:55:21 +00004067 xmlFree(obj);
4068}
4069
4070/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004071 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004072 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004073 *
4074 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4075 * are feed), but does *not* free the list itself. Sets the length of the
4076 * list to 0.
4077 */
4078static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004079xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4080{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004081 if ((set == NULL) || (set->nodeNr <= 0))
4082 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004083 else if (hasNsNodes) {
4084 int i;
4085 xmlNodePtr node;
4086
4087 for (i = 0; i < set->nodeNr; i++) {
4088 node = set->nodeTab[i];
4089 if ((node != NULL) &&
4090 (node->type == XML_NAMESPACE_DECL))
4091 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4092 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004093 }
4094 set->nodeNr = 0;
4095}
4096
4097/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004098 * xmlXPathNodeSetClearFromPos:
4099 * @set: the node set to be cleared
4100 * @pos: the start position to clear from
4101 *
4102 * Clears the list from temporary XPath objects (e.g. namespace nodes
4103 * are feed) starting with the entry at @pos, but does *not* free the list
4104 * itself. Sets the length of the list to @pos.
4105 */
4106static void
4107xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4108{
4109 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4110 return;
4111 else if ((hasNsNodes)) {
4112 int i;
4113 xmlNodePtr node;
4114
4115 for (i = pos; i < set->nodeNr; i++) {
4116 node = set->nodeTab[i];
4117 if ((node != NULL) &&
4118 (node->type == XML_NAMESPACE_DECL))
4119 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4120 }
4121 }
4122 set->nodeNr = pos;
4123}
4124
4125/**
Owen Taylor3473f882001-02-23 17:55:21 +00004126 * xmlXPathFreeValueTree:
4127 * @obj: the xmlNodeSetPtr to free
4128 *
4129 * Free the NodeSet compound and the actual tree, this is different
4130 * from xmlXPathFreeNodeSet()
4131 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004132static void
Owen Taylor3473f882001-02-23 17:55:21 +00004133xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4134 int i;
4135
4136 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004137
4138 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004139 for (i = 0;i < obj->nodeNr;i++) {
4140 if (obj->nodeTab[i] != NULL) {
4141 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4142 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4143 } else {
4144 xmlFreeNodeList(obj->nodeTab[i]);
4145 }
4146 }
4147 }
Owen Taylor3473f882001-02-23 17:55:21 +00004148 xmlFree(obj->nodeTab);
4149 }
Owen Taylor3473f882001-02-23 17:55:21 +00004150 xmlFree(obj);
4151}
4152
4153#if defined(DEBUG) || defined(DEBUG_STEP)
4154/**
4155 * xmlGenericErrorContextNodeSet:
4156 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004157 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004158 *
4159 * Quick display of a NodeSet
4160 */
4161void
4162xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4163 int i;
4164
4165 if (output == NULL) output = xmlGenericErrorContext;
4166 if (obj == NULL) {
4167 fprintf(output, "NodeSet == NULL !\n");
4168 return;
4169 }
4170 if (obj->nodeNr == 0) {
4171 fprintf(output, "NodeSet is empty\n");
4172 return;
4173 }
4174 if (obj->nodeTab == NULL) {
4175 fprintf(output, " nodeTab == NULL !\n");
4176 return;
4177 }
4178 for (i = 0; i < obj->nodeNr; i++) {
4179 if (obj->nodeTab[i] == NULL) {
4180 fprintf(output, " NULL !\n");
4181 return;
4182 }
4183 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4184 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4185 fprintf(output, " /");
4186 else if (obj->nodeTab[i]->name == NULL)
4187 fprintf(output, " noname!");
4188 else fprintf(output, " %s", obj->nodeTab[i]->name);
4189 }
4190 fprintf(output, "\n");
4191}
4192#endif
4193
4194/**
4195 * xmlXPathNewNodeSet:
4196 * @val: the NodePtr value
4197 *
4198 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4199 * it with the single Node @val
4200 *
4201 * Returns the newly created object.
4202 */
4203xmlXPathObjectPtr
4204xmlXPathNewNodeSet(xmlNodePtr val) {
4205 xmlXPathObjectPtr ret;
4206
4207 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4208 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004209 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004210 return(NULL);
4211 }
4212 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4213 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004214 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004215 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004216 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004217#ifdef XP_DEBUG_OBJ_USAGE
4218 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4219#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004220 return(ret);
4221}
4222
4223/**
4224 * xmlXPathNewValueTree:
4225 * @val: the NodePtr value
4226 *
4227 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4228 * it with the tree root @val
4229 *
4230 * Returns the newly created object.
4231 */
4232xmlXPathObjectPtr
4233xmlXPathNewValueTree(xmlNodePtr val) {
4234 xmlXPathObjectPtr ret;
4235
4236 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4237 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004238 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004239 return(NULL);
4240 }
4241 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4242 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004243 ret->boolval = 1;
4244 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004245 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004246#ifdef XP_DEBUG_OBJ_USAGE
4247 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4248#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004249 return(ret);
4250}
4251
4252/**
4253 * xmlXPathNewNodeSetList:
4254 * @val: an existing NodeSet
4255 *
4256 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4257 * it with the Nodeset @val
4258 *
4259 * Returns the newly created object.
4260 */
4261xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004262xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4263{
Owen Taylor3473f882001-02-23 17:55:21 +00004264 xmlXPathObjectPtr ret;
4265 int i;
4266
4267 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004268 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004269 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004270 ret = xmlXPathNewNodeSet(NULL);
4271 else {
4272 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4273 for (i = 1; i < val->nodeNr; ++i)
4274 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4275 }
Owen Taylor3473f882001-02-23 17:55:21 +00004276
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004277 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004278}
4279
4280/**
4281 * xmlXPathWrapNodeSet:
4282 * @val: the NodePtr value
4283 *
4284 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4285 *
4286 * Returns the newly created object.
4287 */
4288xmlXPathObjectPtr
4289xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4290 xmlXPathObjectPtr ret;
4291
4292 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4293 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004294 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004295 return(NULL);
4296 }
4297 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4298 ret->type = XPATH_NODESET;
4299 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004300#ifdef XP_DEBUG_OBJ_USAGE
4301 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4302#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004303 return(ret);
4304}
4305
4306/**
4307 * xmlXPathFreeNodeSetList:
4308 * @obj: an existing NodeSetList object
4309 *
4310 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4311 * the list contrary to xmlXPathFreeObject().
4312 */
4313void
4314xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4315 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004316#ifdef XP_DEBUG_OBJ_USAGE
4317 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4318#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004319 xmlFree(obj);
4320}
4321
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004322/**
4323 * xmlXPathDifference:
4324 * @nodes1: a node-set
4325 * @nodes2: a node-set
4326 *
4327 * Implements the EXSLT - Sets difference() function:
4328 * node-set set:difference (node-set, node-set)
4329 *
4330 * Returns the difference between the two node sets, or nodes1 if
4331 * nodes2 is empty
4332 */
4333xmlNodeSetPtr
4334xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4335 xmlNodeSetPtr ret;
4336 int i, l1;
4337 xmlNodePtr cur;
4338
4339 if (xmlXPathNodeSetIsEmpty(nodes2))
4340 return(nodes1);
4341
4342 ret = xmlXPathNodeSetCreate(NULL);
4343 if (xmlXPathNodeSetIsEmpty(nodes1))
4344 return(ret);
4345
4346 l1 = xmlXPathNodeSetGetLength(nodes1);
4347
4348 for (i = 0; i < l1; i++) {
4349 cur = xmlXPathNodeSetItem(nodes1, i);
4350 if (!xmlXPathNodeSetContains(nodes2, cur))
4351 xmlXPathNodeSetAddUnique(ret, cur);
4352 }
4353 return(ret);
4354}
4355
4356/**
4357 * xmlXPathIntersection:
4358 * @nodes1: a node-set
4359 * @nodes2: a node-set
4360 *
4361 * Implements the EXSLT - Sets intersection() function:
4362 * node-set set:intersection (node-set, node-set)
4363 *
4364 * Returns a node set comprising the nodes that are within both the
4365 * node sets passed as arguments
4366 */
4367xmlNodeSetPtr
4368xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4369 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4370 int i, l1;
4371 xmlNodePtr cur;
4372
4373 if (xmlXPathNodeSetIsEmpty(nodes1))
4374 return(ret);
4375 if (xmlXPathNodeSetIsEmpty(nodes2))
4376 return(ret);
4377
4378 l1 = xmlXPathNodeSetGetLength(nodes1);
4379
4380 for (i = 0; i < l1; i++) {
4381 cur = xmlXPathNodeSetItem(nodes1, i);
4382 if (xmlXPathNodeSetContains(nodes2, cur))
4383 xmlXPathNodeSetAddUnique(ret, cur);
4384 }
4385 return(ret);
4386}
4387
4388/**
4389 * xmlXPathDistinctSorted:
4390 * @nodes: a node-set, sorted by document order
4391 *
4392 * Implements the EXSLT - Sets distinct() function:
4393 * node-set set:distinct (node-set)
4394 *
4395 * Returns a subset of the nodes contained in @nodes, or @nodes if
4396 * it is empty
4397 */
4398xmlNodeSetPtr
4399xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4400 xmlNodeSetPtr ret;
4401 xmlHashTablePtr hash;
4402 int i, l;
4403 xmlChar * strval;
4404 xmlNodePtr cur;
4405
4406 if (xmlXPathNodeSetIsEmpty(nodes))
4407 return(nodes);
4408
4409 ret = xmlXPathNodeSetCreate(NULL);
4410 l = xmlXPathNodeSetGetLength(nodes);
4411 hash = xmlHashCreate (l);
4412 for (i = 0; i < l; i++) {
4413 cur = xmlXPathNodeSetItem(nodes, i);
4414 strval = xmlXPathCastNodeToString(cur);
4415 if (xmlHashLookup(hash, strval) == NULL) {
4416 xmlHashAddEntry(hash, strval, strval);
4417 xmlXPathNodeSetAddUnique(ret, cur);
4418 } else {
4419 xmlFree(strval);
4420 }
4421 }
4422 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4423 return(ret);
4424}
4425
4426/**
4427 * xmlXPathDistinct:
4428 * @nodes: a node-set
4429 *
4430 * Implements the EXSLT - Sets distinct() function:
4431 * node-set set:distinct (node-set)
4432 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4433 * is called with the sorted node-set
4434 *
4435 * Returns a subset of the nodes contained in @nodes, or @nodes if
4436 * it is empty
4437 */
4438xmlNodeSetPtr
4439xmlXPathDistinct (xmlNodeSetPtr nodes) {
4440 if (xmlXPathNodeSetIsEmpty(nodes))
4441 return(nodes);
4442
4443 xmlXPathNodeSetSort(nodes);
4444 return(xmlXPathDistinctSorted(nodes));
4445}
4446
4447/**
4448 * xmlXPathHasSameNodes:
4449 * @nodes1: a node-set
4450 * @nodes2: a node-set
4451 *
4452 * Implements the EXSLT - Sets has-same-nodes function:
4453 * boolean set:has-same-node(node-set, node-set)
4454 *
4455 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4456 * otherwise
4457 */
4458int
4459xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4460 int i, l;
4461 xmlNodePtr cur;
4462
4463 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4464 xmlXPathNodeSetIsEmpty(nodes2))
4465 return(0);
4466
4467 l = xmlXPathNodeSetGetLength(nodes1);
4468 for (i = 0; i < l; i++) {
4469 cur = xmlXPathNodeSetItem(nodes1, i);
4470 if (xmlXPathNodeSetContains(nodes2, cur))
4471 return(1);
4472 }
4473 return(0);
4474}
4475
4476/**
4477 * xmlXPathNodeLeadingSorted:
4478 * @nodes: a node-set, sorted by document order
4479 * @node: a node
4480 *
4481 * Implements the EXSLT - Sets leading() function:
4482 * node-set set:leading (node-set, node-set)
4483 *
4484 * Returns the nodes in @nodes that precede @node in document order,
4485 * @nodes if @node is NULL or an empty node-set if @nodes
4486 * doesn't contain @node
4487 */
4488xmlNodeSetPtr
4489xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4490 int i, l;
4491 xmlNodePtr cur;
4492 xmlNodeSetPtr ret;
4493
4494 if (node == NULL)
4495 return(nodes);
4496
4497 ret = xmlXPathNodeSetCreate(NULL);
4498 if (xmlXPathNodeSetIsEmpty(nodes) ||
4499 (!xmlXPathNodeSetContains(nodes, node)))
4500 return(ret);
4501
4502 l = xmlXPathNodeSetGetLength(nodes);
4503 for (i = 0; i < l; i++) {
4504 cur = xmlXPathNodeSetItem(nodes, i);
4505 if (cur == node)
4506 break;
4507 xmlXPathNodeSetAddUnique(ret, cur);
4508 }
4509 return(ret);
4510}
4511
4512/**
4513 * xmlXPathNodeLeading:
4514 * @nodes: a node-set
4515 * @node: a node
4516 *
4517 * Implements the EXSLT - Sets leading() function:
4518 * node-set set:leading (node-set, node-set)
4519 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4520 * is called.
4521 *
4522 * Returns the nodes in @nodes that precede @node in document order,
4523 * @nodes if @node is NULL or an empty node-set if @nodes
4524 * doesn't contain @node
4525 */
4526xmlNodeSetPtr
4527xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4528 xmlXPathNodeSetSort(nodes);
4529 return(xmlXPathNodeLeadingSorted(nodes, node));
4530}
4531
4532/**
4533 * xmlXPathLeadingSorted:
4534 * @nodes1: a node-set, sorted by document order
4535 * @nodes2: a node-set, sorted by document order
4536 *
4537 * Implements the EXSLT - Sets leading() function:
4538 * node-set set:leading (node-set, node-set)
4539 *
4540 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4541 * in document order, @nodes1 if @nodes2 is NULL or empty or
4542 * an empty node-set if @nodes1 doesn't contain @nodes2
4543 */
4544xmlNodeSetPtr
4545xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4546 if (xmlXPathNodeSetIsEmpty(nodes2))
4547 return(nodes1);
4548 return(xmlXPathNodeLeadingSorted(nodes1,
4549 xmlXPathNodeSetItem(nodes2, 1)));
4550}
4551
4552/**
4553 * xmlXPathLeading:
4554 * @nodes1: a node-set
4555 * @nodes2: a node-set
4556 *
4557 * Implements the EXSLT - Sets leading() function:
4558 * node-set set:leading (node-set, node-set)
4559 * @nodes1 and @nodes2 are sorted by document order, then
4560 * #exslSetsLeadingSorted is called.
4561 *
4562 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4563 * in document order, @nodes1 if @nodes2 is NULL or empty or
4564 * an empty node-set if @nodes1 doesn't contain @nodes2
4565 */
4566xmlNodeSetPtr
4567xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4568 if (xmlXPathNodeSetIsEmpty(nodes2))
4569 return(nodes1);
4570 if (xmlXPathNodeSetIsEmpty(nodes1))
4571 return(xmlXPathNodeSetCreate(NULL));
4572 xmlXPathNodeSetSort(nodes1);
4573 xmlXPathNodeSetSort(nodes2);
4574 return(xmlXPathNodeLeadingSorted(nodes1,
4575 xmlXPathNodeSetItem(nodes2, 1)));
4576}
4577
4578/**
4579 * xmlXPathNodeTrailingSorted:
4580 * @nodes: a node-set, sorted by document order
4581 * @node: a node
4582 *
4583 * Implements the EXSLT - Sets trailing() function:
4584 * node-set set:trailing (node-set, node-set)
4585 *
4586 * Returns the nodes in @nodes that follow @node in document order,
4587 * @nodes if @node is NULL or an empty node-set if @nodes
4588 * doesn't contain @node
4589 */
4590xmlNodeSetPtr
4591xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4592 int i, l;
4593 xmlNodePtr cur;
4594 xmlNodeSetPtr ret;
4595
4596 if (node == NULL)
4597 return(nodes);
4598
4599 ret = xmlXPathNodeSetCreate(NULL);
4600 if (xmlXPathNodeSetIsEmpty(nodes) ||
4601 (!xmlXPathNodeSetContains(nodes, node)))
4602 return(ret);
4603
4604 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004605 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004606 cur = xmlXPathNodeSetItem(nodes, i);
4607 if (cur == node)
4608 break;
4609 xmlXPathNodeSetAddUnique(ret, cur);
4610 }
4611 return(ret);
4612}
4613
4614/**
4615 * xmlXPathNodeTrailing:
4616 * @nodes: a node-set
4617 * @node: a node
4618 *
4619 * Implements the EXSLT - Sets trailing() function:
4620 * node-set set:trailing (node-set, node-set)
4621 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4622 * is called.
4623 *
4624 * Returns the nodes in @nodes that follow @node in document order,
4625 * @nodes if @node is NULL or an empty node-set if @nodes
4626 * doesn't contain @node
4627 */
4628xmlNodeSetPtr
4629xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4630 xmlXPathNodeSetSort(nodes);
4631 return(xmlXPathNodeTrailingSorted(nodes, node));
4632}
4633
4634/**
4635 * xmlXPathTrailingSorted:
4636 * @nodes1: a node-set, sorted by document order
4637 * @nodes2: a node-set, sorted by document order
4638 *
4639 * Implements the EXSLT - Sets trailing() function:
4640 * node-set set:trailing (node-set, node-set)
4641 *
4642 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4643 * in document order, @nodes1 if @nodes2 is NULL or empty or
4644 * an empty node-set if @nodes1 doesn't contain @nodes2
4645 */
4646xmlNodeSetPtr
4647xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4648 if (xmlXPathNodeSetIsEmpty(nodes2))
4649 return(nodes1);
4650 return(xmlXPathNodeTrailingSorted(nodes1,
4651 xmlXPathNodeSetItem(nodes2, 0)));
4652}
4653
4654/**
4655 * xmlXPathTrailing:
4656 * @nodes1: a node-set
4657 * @nodes2: a node-set
4658 *
4659 * Implements the EXSLT - Sets trailing() function:
4660 * node-set set:trailing (node-set, node-set)
4661 * @nodes1 and @nodes2 are sorted by document order, then
4662 * #xmlXPathTrailingSorted is called.
4663 *
4664 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4665 * in document order, @nodes1 if @nodes2 is NULL or empty or
4666 * an empty node-set if @nodes1 doesn't contain @nodes2
4667 */
4668xmlNodeSetPtr
4669xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4670 if (xmlXPathNodeSetIsEmpty(nodes2))
4671 return(nodes1);
4672 if (xmlXPathNodeSetIsEmpty(nodes1))
4673 return(xmlXPathNodeSetCreate(NULL));
4674 xmlXPathNodeSetSort(nodes1);
4675 xmlXPathNodeSetSort(nodes2);
4676 return(xmlXPathNodeTrailingSorted(nodes1,
4677 xmlXPathNodeSetItem(nodes2, 0)));
4678}
4679
Owen Taylor3473f882001-02-23 17:55:21 +00004680/************************************************************************
4681 * *
4682 * Routines to handle extra functions *
4683 * *
4684 ************************************************************************/
4685
4686/**
4687 * xmlXPathRegisterFunc:
4688 * @ctxt: the XPath context
4689 * @name: the function name
4690 * @f: the function implementation or NULL
4691 *
4692 * Register a new function. If @f is NULL it unregisters the function
4693 *
4694 * Returns 0 in case of success, -1 in case of error
4695 */
4696int
4697xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4698 xmlXPathFunction f) {
4699 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4700}
4701
4702/**
4703 * xmlXPathRegisterFuncNS:
4704 * @ctxt: the XPath context
4705 * @name: the function name
4706 * @ns_uri: the function namespace URI
4707 * @f: the function implementation or NULL
4708 *
4709 * Register a new function. If @f is NULL it unregisters the function
4710 *
4711 * Returns 0 in case of success, -1 in case of error
4712 */
4713int
4714xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4715 const xmlChar *ns_uri, xmlXPathFunction f) {
4716 if (ctxt == NULL)
4717 return(-1);
4718 if (name == NULL)
4719 return(-1);
4720
4721 if (ctxt->funcHash == NULL)
4722 ctxt->funcHash = xmlHashCreate(0);
4723 if (ctxt->funcHash == NULL)
4724 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004725 if (f == NULL)
4726 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004727 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004728}
4729
4730/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004731 * xmlXPathRegisterFuncLookup:
4732 * @ctxt: the XPath context
4733 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004734 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004735 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004736 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004737 */
4738void
4739xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4740 xmlXPathFuncLookupFunc f,
4741 void *funcCtxt) {
4742 if (ctxt == NULL)
4743 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004744 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004745 ctxt->funcLookupData = funcCtxt;
4746}
4747
4748/**
Owen Taylor3473f882001-02-23 17:55:21 +00004749 * xmlXPathFunctionLookup:
4750 * @ctxt: the XPath context
4751 * @name: the function name
4752 *
4753 * Search in the Function array of the context for the given
4754 * function.
4755 *
4756 * Returns the xmlXPathFunction or NULL if not found
4757 */
4758xmlXPathFunction
4759xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004760 if (ctxt == NULL)
4761 return (NULL);
4762
4763 if (ctxt->funcLookupFunc != NULL) {
4764 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004765 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004766
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004767 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004768 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004769 if (ret != NULL)
4770 return(ret);
4771 }
Owen Taylor3473f882001-02-23 17:55:21 +00004772 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4773}
4774
4775/**
4776 * xmlXPathFunctionLookupNS:
4777 * @ctxt: the XPath context
4778 * @name: the function name
4779 * @ns_uri: the function namespace URI
4780 *
4781 * Search in the Function array of the context for the given
4782 * function.
4783 *
4784 * Returns the xmlXPathFunction or NULL if not found
4785 */
4786xmlXPathFunction
4787xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4788 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004789 xmlXPathFunction ret;
4790
Owen Taylor3473f882001-02-23 17:55:21 +00004791 if (ctxt == NULL)
4792 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004793 if (name == NULL)
4794 return(NULL);
4795
Thomas Broyerba4ad322001-07-26 16:55:21 +00004796 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004797 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004798
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004799 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004800 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004801 if (ret != NULL)
4802 return(ret);
4803 }
4804
4805 if (ctxt->funcHash == NULL)
4806 return(NULL);
4807
William M. Brackad0e67c2004-12-01 14:35:10 +00004808 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4809 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004810}
4811
4812/**
4813 * xmlXPathRegisteredFuncsCleanup:
4814 * @ctxt: the XPath context
4815 *
4816 * Cleanup the XPath context data associated to registered functions
4817 */
4818void
4819xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4820 if (ctxt == NULL)
4821 return;
4822
4823 xmlHashFree(ctxt->funcHash, NULL);
4824 ctxt->funcHash = NULL;
4825}
4826
4827/************************************************************************
4828 * *
William M. Brack08171912003-12-29 02:52:11 +00004829 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004830 * *
4831 ************************************************************************/
4832
4833/**
4834 * xmlXPathRegisterVariable:
4835 * @ctxt: the XPath context
4836 * @name: the variable name
4837 * @value: the variable value or NULL
4838 *
4839 * Register a new variable value. If @value is NULL it unregisters
4840 * the variable
4841 *
4842 * Returns 0 in case of success, -1 in case of error
4843 */
4844int
4845xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4846 xmlXPathObjectPtr value) {
4847 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4848}
4849
4850/**
4851 * xmlXPathRegisterVariableNS:
4852 * @ctxt: the XPath context
4853 * @name: the variable name
4854 * @ns_uri: the variable namespace URI
4855 * @value: the variable value or NULL
4856 *
4857 * Register a new variable value. If @value is NULL it unregisters
4858 * the variable
4859 *
4860 * Returns 0 in case of success, -1 in case of error
4861 */
4862int
4863xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4864 const xmlChar *ns_uri,
4865 xmlXPathObjectPtr value) {
4866 if (ctxt == NULL)
4867 return(-1);
4868 if (name == NULL)
4869 return(-1);
4870
4871 if (ctxt->varHash == NULL)
4872 ctxt->varHash = xmlHashCreate(0);
4873 if (ctxt->varHash == NULL)
4874 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004875 if (value == NULL)
4876 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4877 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004878 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4879 (void *) value,
4880 (xmlHashDeallocator)xmlXPathFreeObject));
4881}
4882
4883/**
4884 * xmlXPathRegisterVariableLookup:
4885 * @ctxt: the XPath context
4886 * @f: the lookup function
4887 * @data: the lookup data
4888 *
4889 * register an external mechanism to do variable lookup
4890 */
4891void
4892xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4893 xmlXPathVariableLookupFunc f, void *data) {
4894 if (ctxt == NULL)
4895 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004896 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004897 ctxt->varLookupData = data;
4898}
4899
4900/**
4901 * xmlXPathVariableLookup:
4902 * @ctxt: the XPath context
4903 * @name: the variable name
4904 *
4905 * Search in the Variable array of the context for the given
4906 * variable value.
4907 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004908 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004909 */
4910xmlXPathObjectPtr
4911xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4912 if (ctxt == NULL)
4913 return(NULL);
4914
4915 if (ctxt->varLookupFunc != NULL) {
4916 xmlXPathObjectPtr ret;
4917
4918 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4919 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004920 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004921 }
4922 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4923}
4924
4925/**
4926 * xmlXPathVariableLookupNS:
4927 * @ctxt: the XPath context
4928 * @name: the variable name
4929 * @ns_uri: the variable namespace URI
4930 *
4931 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004932 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004933 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004934 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004935 */
4936xmlXPathObjectPtr
4937xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4938 const xmlChar *ns_uri) {
4939 if (ctxt == NULL)
4940 return(NULL);
4941
4942 if (ctxt->varLookupFunc != NULL) {
4943 xmlXPathObjectPtr ret;
4944
4945 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4946 (ctxt->varLookupData, name, ns_uri);
4947 if (ret != NULL) return(ret);
4948 }
4949
4950 if (ctxt->varHash == NULL)
4951 return(NULL);
4952 if (name == NULL)
4953 return(NULL);
4954
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004955 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004956 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004957}
4958
4959/**
4960 * xmlXPathRegisteredVariablesCleanup:
4961 * @ctxt: the XPath context
4962 *
4963 * Cleanup the XPath context data associated to registered variables
4964 */
4965void
4966xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4967 if (ctxt == NULL)
4968 return;
4969
Daniel Veillard76d66f42001-05-16 21:05:17 +00004970 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004971 ctxt->varHash = NULL;
4972}
4973
4974/**
4975 * xmlXPathRegisterNs:
4976 * @ctxt: the XPath context
4977 * @prefix: the namespace prefix
4978 * @ns_uri: the namespace name
4979 *
4980 * Register a new namespace. If @ns_uri is NULL it unregisters
4981 * the namespace
4982 *
4983 * Returns 0 in case of success, -1 in case of error
4984 */
4985int
4986xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4987 const xmlChar *ns_uri) {
4988 if (ctxt == NULL)
4989 return(-1);
4990 if (prefix == NULL)
4991 return(-1);
4992
4993 if (ctxt->nsHash == NULL)
4994 ctxt->nsHash = xmlHashCreate(10);
4995 if (ctxt->nsHash == NULL)
4996 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004997 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004998 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004999 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005000 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005001 (xmlHashDeallocator)xmlFree));
5002}
5003
5004/**
5005 * xmlXPathNsLookup:
5006 * @ctxt: the XPath context
5007 * @prefix: the namespace prefix value
5008 *
5009 * Search in the namespace declaration array of the context for the given
5010 * namespace name associated to the given prefix
5011 *
5012 * Returns the value or NULL if not found
5013 */
5014const xmlChar *
5015xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5016 if (ctxt == NULL)
5017 return(NULL);
5018 if (prefix == NULL)
5019 return(NULL);
5020
5021#ifdef XML_XML_NAMESPACE
5022 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5023 return(XML_XML_NAMESPACE);
5024#endif
5025
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005026 if (ctxt->namespaces != NULL) {
5027 int i;
5028
5029 for (i = 0;i < ctxt->nsNr;i++) {
5030 if ((ctxt->namespaces[i] != NULL) &&
5031 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5032 return(ctxt->namespaces[i]->href);
5033 }
5034 }
Owen Taylor3473f882001-02-23 17:55:21 +00005035
5036 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5037}
5038
5039/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005040 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005041 * @ctxt: the XPath context
5042 *
5043 * Cleanup the XPath context data associated to registered variables
5044 */
5045void
5046xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5047 if (ctxt == NULL)
5048 return;
5049
Daniel Veillard42766c02002-08-22 20:52:17 +00005050 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005051 ctxt->nsHash = NULL;
5052}
5053
5054/************************************************************************
5055 * *
5056 * Routines to handle Values *
5057 * *
5058 ************************************************************************/
5059
William M. Brack08171912003-12-29 02:52:11 +00005060/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005061
5062/**
5063 * xmlXPathNewFloat:
5064 * @val: the double value
5065 *
5066 * Create a new xmlXPathObjectPtr of type double and of value @val
5067 *
5068 * Returns the newly created object.
5069 */
5070xmlXPathObjectPtr
5071xmlXPathNewFloat(double val) {
5072 xmlXPathObjectPtr ret;
5073
5074 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5075 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005076 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005077 return(NULL);
5078 }
5079 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5080 ret->type = XPATH_NUMBER;
5081 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005082#ifdef XP_DEBUG_OBJ_USAGE
5083 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5084#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005085 return(ret);
5086}
5087
5088/**
5089 * xmlXPathNewBoolean:
5090 * @val: the boolean value
5091 *
5092 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5093 *
5094 * Returns the newly created object.
5095 */
5096xmlXPathObjectPtr
5097xmlXPathNewBoolean(int val) {
5098 xmlXPathObjectPtr ret;
5099
5100 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5101 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005102 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005103 return(NULL);
5104 }
5105 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5106 ret->type = XPATH_BOOLEAN;
5107 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005108#ifdef XP_DEBUG_OBJ_USAGE
5109 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5110#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005111 return(ret);
5112}
5113
5114/**
5115 * xmlXPathNewString:
5116 * @val: the xmlChar * value
5117 *
5118 * Create a new xmlXPathObjectPtr of type string and of value @val
5119 *
5120 * Returns the newly created object.
5121 */
5122xmlXPathObjectPtr
5123xmlXPathNewString(const xmlChar *val) {
5124 xmlXPathObjectPtr ret;
5125
5126 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5127 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005128 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005129 return(NULL);
5130 }
5131 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5132 ret->type = XPATH_STRING;
5133 if (val != NULL)
5134 ret->stringval = xmlStrdup(val);
5135 else
5136 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005137#ifdef XP_DEBUG_OBJ_USAGE
5138 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5139#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005140 return(ret);
5141}
5142
5143/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005144 * xmlXPathWrapString:
5145 * @val: the xmlChar * value
5146 *
5147 * Wraps the @val string into an XPath object.
5148 *
5149 * Returns the newly created object.
5150 */
5151xmlXPathObjectPtr
5152xmlXPathWrapString (xmlChar *val) {
5153 xmlXPathObjectPtr ret;
5154
5155 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5156 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005157 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005158 return(NULL);
5159 }
5160 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5161 ret->type = XPATH_STRING;
5162 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005163#ifdef XP_DEBUG_OBJ_USAGE
5164 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5165#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005166 return(ret);
5167}
5168
5169/**
Owen Taylor3473f882001-02-23 17:55:21 +00005170 * xmlXPathNewCString:
5171 * @val: the char * value
5172 *
5173 * Create a new xmlXPathObjectPtr of type string and of value @val
5174 *
5175 * Returns the newly created object.
5176 */
5177xmlXPathObjectPtr
5178xmlXPathNewCString(const char *val) {
5179 xmlXPathObjectPtr ret;
5180
5181 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5182 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005183 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005184 return(NULL);
5185 }
5186 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5187 ret->type = XPATH_STRING;
5188 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005189#ifdef XP_DEBUG_OBJ_USAGE
5190 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5191#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005192 return(ret);
5193}
5194
5195/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005196 * xmlXPathWrapCString:
5197 * @val: the char * value
5198 *
5199 * Wraps a string into an XPath object.
5200 *
5201 * Returns the newly created object.
5202 */
5203xmlXPathObjectPtr
5204xmlXPathWrapCString (char * val) {
5205 return(xmlXPathWrapString((xmlChar *)(val)));
5206}
5207
5208/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005209 * xmlXPathWrapExternal:
5210 * @val: the user data
5211 *
5212 * Wraps the @val data into an XPath object.
5213 *
5214 * Returns the newly created object.
5215 */
5216xmlXPathObjectPtr
5217xmlXPathWrapExternal (void *val) {
5218 xmlXPathObjectPtr ret;
5219
5220 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005222 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005223 return(NULL);
5224 }
5225 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5226 ret->type = XPATH_USERS;
5227 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005228#ifdef XP_DEBUG_OBJ_USAGE
5229 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5230#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005231 return(ret);
5232}
5233
5234/**
Owen Taylor3473f882001-02-23 17:55:21 +00005235 * xmlXPathObjectCopy:
5236 * @val: the original object
5237 *
5238 * allocate a new copy of a given object
5239 *
5240 * Returns the newly created object.
5241 */
5242xmlXPathObjectPtr
5243xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5244 xmlXPathObjectPtr ret;
5245
5246 if (val == NULL)
5247 return(NULL);
5248
5249 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5250 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005251 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005252 return(NULL);
5253 }
5254 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005255#ifdef XP_DEBUG_OBJ_USAGE
5256 xmlXPathDebugObjUsageRequested(NULL, val->type);
5257#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005258 switch (val->type) {
5259 case XPATH_BOOLEAN:
5260 case XPATH_NUMBER:
5261 case XPATH_POINT:
5262 case XPATH_RANGE:
5263 break;
5264 case XPATH_STRING:
5265 ret->stringval = xmlStrdup(val->stringval);
5266 break;
5267 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005268#if 0
5269/*
5270 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5271 this previous handling is no longer correct, and can cause some serious
5272 problems (ref. bug 145547)
5273*/
Owen Taylor3473f882001-02-23 17:55:21 +00005274 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005275 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005276 xmlNodePtr cur, tmp;
5277 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005278
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005279 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005280 top = xmlNewDoc(NULL);
5281 top->name = (char *)
5282 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005283 ret->user = top;
5284 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005285 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005286 cur = val->nodesetval->nodeTab[0]->children;
5287 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005288 tmp = xmlDocCopyNode(cur, top, 1);
5289 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005290 cur = cur->next;
5291 }
5292 }
William M. Bracke9449c52004-07-11 14:41:20 +00005293
Daniel Veillard9adc0462003-03-24 18:39:54 +00005294 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005295 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005296 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005297 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005298 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005299#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005300 case XPATH_NODESET:
5301 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005302 /* Do not deallocate the copied tree value */
5303 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005304 break;
5305 case XPATH_LOCATIONSET:
5306#ifdef LIBXML_XPTR_ENABLED
5307 {
5308 xmlLocationSetPtr loc = val->user;
5309 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5310 break;
5311 }
5312#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005313 case XPATH_USERS:
5314 ret->user = val->user;
5315 break;
5316 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005317 xmlGenericError(xmlGenericErrorContext,
5318 "xmlXPathObjectCopy: unsupported type %d\n",
5319 val->type);
5320 break;
5321 }
5322 return(ret);
5323}
5324
5325/**
5326 * xmlXPathFreeObject:
5327 * @obj: the object to free
5328 *
5329 * Free up an xmlXPathObjectPtr object.
5330 */
5331void
5332xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5333 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005334 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005335 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005336#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005337 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005338 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005339 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005340 } else
5341#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005342 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005343 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005344 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005345 } else {
5346 if (obj->nodesetval != NULL)
5347 xmlXPathFreeNodeSet(obj->nodesetval);
5348 }
Owen Taylor3473f882001-02-23 17:55:21 +00005349#ifdef LIBXML_XPTR_ENABLED
5350 } else if (obj->type == XPATH_LOCATIONSET) {
5351 if (obj->user != NULL)
5352 xmlXPtrFreeLocationSet(obj->user);
5353#endif
5354 } else if (obj->type == XPATH_STRING) {
5355 if (obj->stringval != NULL)
5356 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005357 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005358#ifdef XP_DEBUG_OBJ_USAGE
5359 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5360#endif
5361 xmlFree(obj);
5362}
Owen Taylor3473f882001-02-23 17:55:21 +00005363
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005364/**
5365 * xmlXPathReleaseObject:
5366 * @obj: the xmlXPathObjectPtr to free or to cache
5367 *
5368 * Depending on the state of the cache this frees the given
5369 * XPath object or stores it in the cache.
5370 */
5371static void
5372xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5373{
5374#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5375 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5376 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5377
5378#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5379
5380 if (obj == NULL)
5381 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005382 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005383 xmlXPathFreeObject(obj);
5384 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005385 xmlXPathContextCachePtr cache =
5386 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005387
5388 switch (obj->type) {
5389 case XPATH_NODESET:
5390 case XPATH_XSLT_TREE:
5391 if (obj->nodesetval != NULL) {
5392 if (obj->boolval) {
5393 /*
5394 * It looks like the @boolval is used for
5395 * evaluation if this an XSLT Result Tree Fragment.
5396 * TODO: Check if this assumption is correct.
5397 */
5398 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5399 xmlXPathFreeValueTree(obj->nodesetval);
5400 obj->nodesetval = NULL;
5401 } else if ((obj->nodesetval->nodeMax <= 40) &&
5402 (XP_CACHE_WANTS(cache->nodesetObjs,
5403 cache->maxNodeset)))
5404 {
5405 XP_CACHE_ADD(cache->nodesetObjs, obj);
5406 goto obj_cached;
5407 } else {
5408 xmlXPathFreeNodeSet(obj->nodesetval);
5409 obj->nodesetval = NULL;
5410 }
5411 }
5412 break;
5413 case XPATH_STRING:
5414 if (obj->stringval != NULL)
5415 xmlFree(obj->stringval);
5416
5417 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5418 XP_CACHE_ADD(cache->stringObjs, obj);
5419 goto obj_cached;
5420 }
5421 break;
5422 case XPATH_BOOLEAN:
5423 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5424 XP_CACHE_ADD(cache->booleanObjs, obj);
5425 goto obj_cached;
5426 }
5427 break;
5428 case XPATH_NUMBER:
5429 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5430 XP_CACHE_ADD(cache->numberObjs, obj);
5431 goto obj_cached;
5432 }
5433 break;
5434#ifdef LIBXML_XPTR_ENABLED
5435 case XPATH_LOCATIONSET:
5436 if (obj->user != NULL) {
5437 xmlXPtrFreeLocationSet(obj->user);
5438 }
5439 goto free_obj;
5440#endif
5441 default:
5442 goto free_obj;
5443 }
5444
5445 /*
5446 * Fallback to adding to the misc-objects slot.
5447 */
5448 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5449 XP_CACHE_ADD(cache->miscObjs, obj);
5450 } else
5451 goto free_obj;
5452
5453obj_cached:
5454
5455#ifdef XP_DEBUG_OBJ_USAGE
5456 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5457#endif
5458
5459 if (obj->nodesetval != NULL) {
5460 xmlNodeSetPtr tmpset = obj->nodesetval;
5461
5462 /*
5463 * TODO: Due to those nasty ns-nodes, we need to traverse
5464 * the list and free the ns-nodes.
5465 * URGENT TODO: Check if it's actually slowing things down.
5466 * Maybe we shouldn't try to preserve the list.
5467 */
5468 if (tmpset->nodeNr > 1) {
5469 int i;
5470 xmlNodePtr node;
5471
5472 for (i = 0; i < tmpset->nodeNr; i++) {
5473 node = tmpset->nodeTab[i];
5474 if ((node != NULL) &&
5475 (node->type == XML_NAMESPACE_DECL))
5476 {
5477 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5478 }
5479 }
5480 } else if (tmpset->nodeNr == 1) {
5481 if ((tmpset->nodeTab[0] != NULL) &&
5482 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5483 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5484 }
5485 tmpset->nodeNr = 0;
5486 memset(obj, 0, sizeof(xmlXPathObject));
5487 obj->nodesetval = tmpset;
5488 } else
5489 memset(obj, 0, sizeof(xmlXPathObject));
5490
5491 return;
5492
5493free_obj:
5494 /*
5495 * Cache is full; free the object.
5496 */
5497 if (obj->nodesetval != NULL)
5498 xmlXPathFreeNodeSet(obj->nodesetval);
5499#ifdef XP_DEBUG_OBJ_USAGE
5500 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5501#endif
5502 xmlFree(obj);
5503 }
5504 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005505}
5506
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005507
5508/************************************************************************
5509 * *
5510 * Type Casting Routines *
5511 * *
5512 ************************************************************************/
5513
5514/**
5515 * xmlXPathCastBooleanToString:
5516 * @val: a boolean
5517 *
5518 * Converts a boolean to its string value.
5519 *
5520 * Returns a newly allocated string.
5521 */
5522xmlChar *
5523xmlXPathCastBooleanToString (int val) {
5524 xmlChar *ret;
5525 if (val)
5526 ret = xmlStrdup((const xmlChar *) "true");
5527 else
5528 ret = xmlStrdup((const xmlChar *) "false");
5529 return(ret);
5530}
5531
5532/**
5533 * xmlXPathCastNumberToString:
5534 * @val: a number
5535 *
5536 * Converts a number to its string value.
5537 *
5538 * Returns a newly allocated string.
5539 */
5540xmlChar *
5541xmlXPathCastNumberToString (double val) {
5542 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005543 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005544 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005545 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005546 break;
5547 case -1:
5548 ret = xmlStrdup((const xmlChar *) "-Infinity");
5549 break;
5550 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005551 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005552 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005553 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5554 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005555 } else {
5556 /* could be improved */
5557 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005558 xmlXPathFormatNumber(val, buf, 99);
5559 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005560 ret = xmlStrdup((const xmlChar *) buf);
5561 }
5562 }
5563 return(ret);
5564}
5565
5566/**
5567 * xmlXPathCastNodeToString:
5568 * @node: a node
5569 *
5570 * Converts a node to its string value.
5571 *
5572 * Returns a newly allocated string.
5573 */
5574xmlChar *
5575xmlXPathCastNodeToString (xmlNodePtr node) {
5576 return(xmlNodeGetContent(node));
5577}
5578
5579/**
5580 * xmlXPathCastNodeSetToString:
5581 * @ns: a node-set
5582 *
5583 * Converts a node-set to its string value.
5584 *
5585 * Returns a newly allocated string.
5586 */
5587xmlChar *
5588xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5589 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5590 return(xmlStrdup((const xmlChar *) ""));
5591
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005592 if (ns->nodeNr > 1)
5593 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005594 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5595}
5596
5597/**
5598 * xmlXPathCastToString:
5599 * @val: an XPath object
5600 *
5601 * Converts an existing object to its string() equivalent
5602 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005603 * Returns the allocated string value of the object, NULL in case of error.
5604 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005605 */
5606xmlChar *
5607xmlXPathCastToString(xmlXPathObjectPtr val) {
5608 xmlChar *ret = NULL;
5609
5610 if (val == NULL)
5611 return(xmlStrdup((const xmlChar *) ""));
5612 switch (val->type) {
5613 case XPATH_UNDEFINED:
5614#ifdef DEBUG_EXPR
5615 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5616#endif
5617 ret = xmlStrdup((const xmlChar *) "");
5618 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005619 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005620 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005621 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5622 break;
5623 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005624 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005625 case XPATH_BOOLEAN:
5626 ret = xmlXPathCastBooleanToString(val->boolval);
5627 break;
5628 case XPATH_NUMBER: {
5629 ret = xmlXPathCastNumberToString(val->floatval);
5630 break;
5631 }
5632 case XPATH_USERS:
5633 case XPATH_POINT:
5634 case XPATH_RANGE:
5635 case XPATH_LOCATIONSET:
5636 TODO
5637 ret = xmlStrdup((const xmlChar *) "");
5638 break;
5639 }
5640 return(ret);
5641}
5642
5643/**
5644 * xmlXPathConvertString:
5645 * @val: an XPath object
5646 *
5647 * Converts an existing object to its string() equivalent
5648 *
5649 * Returns the new object, the old one is freed (or the operation
5650 * is done directly on @val)
5651 */
5652xmlXPathObjectPtr
5653xmlXPathConvertString(xmlXPathObjectPtr val) {
5654 xmlChar *res = NULL;
5655
5656 if (val == NULL)
5657 return(xmlXPathNewCString(""));
5658
5659 switch (val->type) {
5660 case XPATH_UNDEFINED:
5661#ifdef DEBUG_EXPR
5662 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5663#endif
5664 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005665 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005666 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005667 res = xmlXPathCastNodeSetToString(val->nodesetval);
5668 break;
5669 case XPATH_STRING:
5670 return(val);
5671 case XPATH_BOOLEAN:
5672 res = xmlXPathCastBooleanToString(val->boolval);
5673 break;
5674 case XPATH_NUMBER:
5675 res = xmlXPathCastNumberToString(val->floatval);
5676 break;
5677 case XPATH_USERS:
5678 case XPATH_POINT:
5679 case XPATH_RANGE:
5680 case XPATH_LOCATIONSET:
5681 TODO;
5682 break;
5683 }
5684 xmlXPathFreeObject(val);
5685 if (res == NULL)
5686 return(xmlXPathNewCString(""));
5687 return(xmlXPathWrapString(res));
5688}
5689
5690/**
5691 * xmlXPathCastBooleanToNumber:
5692 * @val: a boolean
5693 *
5694 * Converts a boolean to its number value
5695 *
5696 * Returns the number value
5697 */
5698double
5699xmlXPathCastBooleanToNumber(int val) {
5700 if (val)
5701 return(1.0);
5702 return(0.0);
5703}
5704
5705/**
5706 * xmlXPathCastStringToNumber:
5707 * @val: a string
5708 *
5709 * Converts a string to its number value
5710 *
5711 * Returns the number value
5712 */
5713double
5714xmlXPathCastStringToNumber(const xmlChar * val) {
5715 return(xmlXPathStringEvalNumber(val));
5716}
5717
5718/**
5719 * xmlXPathCastNodeToNumber:
5720 * @node: a node
5721 *
5722 * Converts a node to its number value
5723 *
5724 * Returns the number value
5725 */
5726double
5727xmlXPathCastNodeToNumber (xmlNodePtr node) {
5728 xmlChar *strval;
5729 double ret;
5730
5731 if (node == NULL)
5732 return(xmlXPathNAN);
5733 strval = xmlXPathCastNodeToString(node);
5734 if (strval == NULL)
5735 return(xmlXPathNAN);
5736 ret = xmlXPathCastStringToNumber(strval);
5737 xmlFree(strval);
5738
5739 return(ret);
5740}
5741
5742/**
5743 * xmlXPathCastNodeSetToNumber:
5744 * @ns: a node-set
5745 *
5746 * Converts a node-set to its number value
5747 *
5748 * Returns the number value
5749 */
5750double
5751xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5752 xmlChar *str;
5753 double ret;
5754
5755 if (ns == NULL)
5756 return(xmlXPathNAN);
5757 str = xmlXPathCastNodeSetToString(ns);
5758 ret = xmlXPathCastStringToNumber(str);
5759 xmlFree(str);
5760 return(ret);
5761}
5762
5763/**
5764 * xmlXPathCastToNumber:
5765 * @val: an XPath object
5766 *
5767 * Converts an XPath object to its number value
5768 *
5769 * Returns the number value
5770 */
5771double
5772xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5773 double ret = 0.0;
5774
5775 if (val == NULL)
5776 return(xmlXPathNAN);
5777 switch (val->type) {
5778 case XPATH_UNDEFINED:
5779#ifdef DEGUB_EXPR
5780 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5781#endif
5782 ret = xmlXPathNAN;
5783 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005784 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005785 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005786 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5787 break;
5788 case XPATH_STRING:
5789 ret = xmlXPathCastStringToNumber(val->stringval);
5790 break;
5791 case XPATH_NUMBER:
5792 ret = val->floatval;
5793 break;
5794 case XPATH_BOOLEAN:
5795 ret = xmlXPathCastBooleanToNumber(val->boolval);
5796 break;
5797 case XPATH_USERS:
5798 case XPATH_POINT:
5799 case XPATH_RANGE:
5800 case XPATH_LOCATIONSET:
5801 TODO;
5802 ret = xmlXPathNAN;
5803 break;
5804 }
5805 return(ret);
5806}
5807
5808/**
5809 * xmlXPathConvertNumber:
5810 * @val: an XPath object
5811 *
5812 * Converts an existing object to its number() equivalent
5813 *
5814 * Returns the new object, the old one is freed (or the operation
5815 * is done directly on @val)
5816 */
5817xmlXPathObjectPtr
5818xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5819 xmlXPathObjectPtr ret;
5820
5821 if (val == NULL)
5822 return(xmlXPathNewFloat(0.0));
5823 if (val->type == XPATH_NUMBER)
5824 return(val);
5825 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5826 xmlXPathFreeObject(val);
5827 return(ret);
5828}
5829
5830/**
5831 * xmlXPathCastNumberToBoolean:
5832 * @val: a number
5833 *
5834 * Converts a number to its boolean value
5835 *
5836 * Returns the boolean value
5837 */
5838int
5839xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005840 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005841 return(0);
5842 return(1);
5843}
5844
5845/**
5846 * xmlXPathCastStringToBoolean:
5847 * @val: a string
5848 *
5849 * Converts a string to its boolean value
5850 *
5851 * Returns the boolean value
5852 */
5853int
5854xmlXPathCastStringToBoolean (const xmlChar *val) {
5855 if ((val == NULL) || (xmlStrlen(val) == 0))
5856 return(0);
5857 return(1);
5858}
5859
5860/**
5861 * xmlXPathCastNodeSetToBoolean:
5862 * @ns: a node-set
5863 *
5864 * Converts a node-set to its boolean value
5865 *
5866 * Returns the boolean value
5867 */
5868int
5869xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5870 if ((ns == NULL) || (ns->nodeNr == 0))
5871 return(0);
5872 return(1);
5873}
5874
5875/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005876 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005877 * @val: an XPath object
5878 *
5879 * Converts an XPath object to its boolean value
5880 *
5881 * Returns the boolean value
5882 */
5883int
5884xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5885 int ret = 0;
5886
5887 if (val == NULL)
5888 return(0);
5889 switch (val->type) {
5890 case XPATH_UNDEFINED:
5891#ifdef DEBUG_EXPR
5892 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5893#endif
5894 ret = 0;
5895 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005896 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005897 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005898 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5899 break;
5900 case XPATH_STRING:
5901 ret = xmlXPathCastStringToBoolean(val->stringval);
5902 break;
5903 case XPATH_NUMBER:
5904 ret = xmlXPathCastNumberToBoolean(val->floatval);
5905 break;
5906 case XPATH_BOOLEAN:
5907 ret = val->boolval;
5908 break;
5909 case XPATH_USERS:
5910 case XPATH_POINT:
5911 case XPATH_RANGE:
5912 case XPATH_LOCATIONSET:
5913 TODO;
5914 ret = 0;
5915 break;
5916 }
5917 return(ret);
5918}
5919
5920
5921/**
5922 * xmlXPathConvertBoolean:
5923 * @val: an XPath object
5924 *
5925 * Converts an existing object to its boolean() equivalent
5926 *
5927 * Returns the new object, the old one is freed (or the operation
5928 * is done directly on @val)
5929 */
5930xmlXPathObjectPtr
5931xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5932 xmlXPathObjectPtr ret;
5933
5934 if (val == NULL)
5935 return(xmlXPathNewBoolean(0));
5936 if (val->type == XPATH_BOOLEAN)
5937 return(val);
5938 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5939 xmlXPathFreeObject(val);
5940 return(ret);
5941}
5942
Owen Taylor3473f882001-02-23 17:55:21 +00005943/************************************************************************
5944 * *
5945 * Routines to handle XPath contexts *
5946 * *
5947 ************************************************************************/
5948
5949/**
5950 * xmlXPathNewContext:
5951 * @doc: the XML document
5952 *
5953 * Create a new xmlXPathContext
5954 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005955 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005956 */
5957xmlXPathContextPtr
5958xmlXPathNewContext(xmlDocPtr doc) {
5959 xmlXPathContextPtr ret;
5960
5961 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5962 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005963 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005964 return(NULL);
5965 }
5966 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5967 ret->doc = doc;
5968 ret->node = NULL;
5969
5970 ret->varHash = NULL;
5971
5972 ret->nb_types = 0;
5973 ret->max_types = 0;
5974 ret->types = NULL;
5975
5976 ret->funcHash = xmlHashCreate(0);
5977
5978 ret->nb_axis = 0;
5979 ret->max_axis = 0;
5980 ret->axis = NULL;
5981
5982 ret->nsHash = NULL;
5983 ret->user = NULL;
5984
5985 ret->contextSize = -1;
5986 ret->proximityPosition = -1;
5987
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005988#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005989 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005990 xmlXPathFreeContext(ret);
5991 return(NULL);
5992 }
5993#endif
5994
5995 xmlXPathRegisterAllFunctions(ret);
5996
Owen Taylor3473f882001-02-23 17:55:21 +00005997 return(ret);
5998}
5999
6000/**
6001 * xmlXPathFreeContext:
6002 * @ctxt: the context to free
6003 *
6004 * Free up an xmlXPathContext
6005 */
6006void
6007xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006008 if (ctxt == NULL) return;
6009
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006010 if (ctxt->cache != NULL)
6011 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006012 xmlXPathRegisteredNsCleanup(ctxt);
6013 xmlXPathRegisteredFuncsCleanup(ctxt);
6014 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006015 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006016 xmlFree(ctxt);
6017}
6018
6019/************************************************************************
6020 * *
6021 * Routines to handle XPath parser contexts *
6022 * *
6023 ************************************************************************/
6024
6025#define CHECK_CTXT(ctxt) \
6026 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006027 __xmlRaiseError(NULL, NULL, NULL, \
6028 NULL, NULL, XML_FROM_XPATH, \
6029 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6030 __FILE__, __LINE__, \
6031 NULL, NULL, NULL, 0, 0, \
6032 "NULL context pointer\n"); \
6033 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006034 } \
6035
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006036#define CHECK_CTXT_NEG(ctxt) \
6037 if (ctxt == NULL) { \
6038 __xmlRaiseError(NULL, NULL, NULL, \
6039 NULL, NULL, XML_FROM_XPATH, \
6040 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6041 __FILE__, __LINE__, \
6042 NULL, NULL, NULL, 0, 0, \
6043 "NULL context pointer\n"); \
6044 return(-1); \
6045 } \
6046
Owen Taylor3473f882001-02-23 17:55:21 +00006047
6048#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006049 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6050 (ctxt->doc->children == NULL)) { \
6051 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006052 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006053 }
Owen Taylor3473f882001-02-23 17:55:21 +00006054
6055
6056/**
6057 * xmlXPathNewParserContext:
6058 * @str: the XPath expression
6059 * @ctxt: the XPath context
6060 *
6061 * Create a new xmlXPathParserContext
6062 *
6063 * Returns the xmlXPathParserContext just allocated.
6064 */
6065xmlXPathParserContextPtr
6066xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6067 xmlXPathParserContextPtr ret;
6068
6069 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6070 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006071 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006072 return(NULL);
6073 }
6074 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6075 ret->cur = ret->base = str;
6076 ret->context = ctxt;
6077
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006078 ret->comp = xmlXPathNewCompExpr();
6079 if (ret->comp == NULL) {
6080 xmlFree(ret->valueTab);
6081 xmlFree(ret);
6082 return(NULL);
6083 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006084 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6085 ret->comp->dict = ctxt->dict;
6086 xmlDictReference(ret->comp->dict);
6087 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006088
6089 return(ret);
6090}
6091
6092/**
6093 * xmlXPathCompParserContext:
6094 * @comp: the XPath compiled expression
6095 * @ctxt: the XPath context
6096 *
6097 * Create a new xmlXPathParserContext when processing a compiled expression
6098 *
6099 * Returns the xmlXPathParserContext just allocated.
6100 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006101static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006102xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6103 xmlXPathParserContextPtr ret;
6104
6105 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6106 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006107 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006108 return(NULL);
6109 }
6110 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6111
Owen Taylor3473f882001-02-23 17:55:21 +00006112 /* Allocate the value stack */
6113 ret->valueTab = (xmlXPathObjectPtr *)
6114 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006115 if (ret->valueTab == NULL) {
6116 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006117 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006118 return(NULL);
6119 }
Owen Taylor3473f882001-02-23 17:55:21 +00006120 ret->valueNr = 0;
6121 ret->valueMax = 10;
6122 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006123
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006124 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006125 ret->comp = comp;
6126
Owen Taylor3473f882001-02-23 17:55:21 +00006127 return(ret);
6128}
6129
6130/**
6131 * xmlXPathFreeParserContext:
6132 * @ctxt: the context to free
6133 *
6134 * Free up an xmlXPathParserContext
6135 */
6136void
6137xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6138 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006139 xmlFree(ctxt->valueTab);
6140 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006141 if (ctxt->comp != NULL) {
6142#ifdef XPATH_STREAMING
6143 if (ctxt->comp->stream != NULL) {
6144 xmlFreePatternList(ctxt->comp->stream);
6145 ctxt->comp->stream = NULL;
6146 }
6147#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006148 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006149 }
Owen Taylor3473f882001-02-23 17:55:21 +00006150 xmlFree(ctxt);
6151}
6152
6153/************************************************************************
6154 * *
6155 * The implicit core function library *
6156 * *
6157 ************************************************************************/
6158
Owen Taylor3473f882001-02-23 17:55:21 +00006159/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006160 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006161 * @node: a node pointer
6162 *
6163 * Function computing the beginning of the string value of the node,
6164 * used to speed up comparisons
6165 *
6166 * Returns an int usable as a hash
6167 */
6168static unsigned int
6169xmlXPathNodeValHash(xmlNodePtr node) {
6170 int len = 2;
6171 const xmlChar * string = NULL;
6172 xmlNodePtr tmp = NULL;
6173 unsigned int ret = 0;
6174
6175 if (node == NULL)
6176 return(0);
6177
Daniel Veillard9adc0462003-03-24 18:39:54 +00006178 if (node->type == XML_DOCUMENT_NODE) {
6179 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6180 if (tmp == NULL)
6181 node = node->children;
6182 else
6183 node = tmp;
6184
6185 if (node == NULL)
6186 return(0);
6187 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006188
6189 switch (node->type) {
6190 case XML_COMMENT_NODE:
6191 case XML_PI_NODE:
6192 case XML_CDATA_SECTION_NODE:
6193 case XML_TEXT_NODE:
6194 string = node->content;
6195 if (string == NULL)
6196 return(0);
6197 if (string[0] == 0)
6198 return(0);
6199 return(((unsigned int) string[0]) +
6200 (((unsigned int) string[1]) << 8));
6201 case XML_NAMESPACE_DECL:
6202 string = ((xmlNsPtr)node)->href;
6203 if (string == NULL)
6204 return(0);
6205 if (string[0] == 0)
6206 return(0);
6207 return(((unsigned int) string[0]) +
6208 (((unsigned int) string[1]) << 8));
6209 case XML_ATTRIBUTE_NODE:
6210 tmp = ((xmlAttrPtr) node)->children;
6211 break;
6212 case XML_ELEMENT_NODE:
6213 tmp = node->children;
6214 break;
6215 default:
6216 return(0);
6217 }
6218 while (tmp != NULL) {
6219 switch (tmp->type) {
6220 case XML_COMMENT_NODE:
6221 case XML_PI_NODE:
6222 case XML_CDATA_SECTION_NODE:
6223 case XML_TEXT_NODE:
6224 string = tmp->content;
6225 break;
6226 case XML_NAMESPACE_DECL:
6227 string = ((xmlNsPtr)tmp)->href;
6228 break;
6229 default:
6230 break;
6231 }
6232 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006233 if (len == 1) {
6234 return(ret + (((unsigned int) string[0]) << 8));
6235 }
6236 if (string[1] == 0) {
6237 len = 1;
6238 ret = (unsigned int) string[0];
6239 } else {
6240 return(((unsigned int) string[0]) +
6241 (((unsigned int) string[1]) << 8));
6242 }
6243 }
6244 /*
6245 * Skip to next node
6246 */
6247 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6248 if (tmp->children->type != XML_ENTITY_DECL) {
6249 tmp = tmp->children;
6250 continue;
6251 }
6252 }
6253 if (tmp == node)
6254 break;
6255
6256 if (tmp->next != NULL) {
6257 tmp = tmp->next;
6258 continue;
6259 }
6260
6261 do {
6262 tmp = tmp->parent;
6263 if (tmp == NULL)
6264 break;
6265 if (tmp == node) {
6266 tmp = NULL;
6267 break;
6268 }
6269 if (tmp->next != NULL) {
6270 tmp = tmp->next;
6271 break;
6272 }
6273 } while (tmp != NULL);
6274 }
6275 return(ret);
6276}
6277
6278/**
6279 * xmlXPathStringHash:
6280 * @string: a string
6281 *
6282 * Function computing the beginning of the string value of the node,
6283 * used to speed up comparisons
6284 *
6285 * Returns an int usable as a hash
6286 */
6287static unsigned int
6288xmlXPathStringHash(const xmlChar * string) {
6289 if (string == NULL)
6290 return((unsigned int) 0);
6291 if (string[0] == 0)
6292 return(0);
6293 return(((unsigned int) string[0]) +
6294 (((unsigned int) string[1]) << 8));
6295}
6296
6297/**
Owen Taylor3473f882001-02-23 17:55:21 +00006298 * xmlXPathCompareNodeSetFloat:
6299 * @ctxt: the XPath Parser context
6300 * @inf: less than (1) or greater than (0)
6301 * @strict: is the comparison strict
6302 * @arg: the node set
6303 * @f: the value
6304 *
6305 * Implement the compare operation between a nodeset and a number
6306 * @ns < @val (1, 1, ...
6307 * @ns <= @val (1, 0, ...
6308 * @ns > @val (0, 1, ...
6309 * @ns >= @val (0, 0, ...
6310 *
6311 * If one object to be compared is a node-set and the other is a number,
6312 * then the comparison will be true if and only if there is a node in the
6313 * node-set such that the result of performing the comparison on the number
6314 * to be compared and on the result of converting the string-value of that
6315 * node to a number using the number function is true.
6316 *
6317 * Returns 0 or 1 depending on the results of the test.
6318 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006319static int
Owen Taylor3473f882001-02-23 17:55:21 +00006320xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6321 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6322 int i, ret = 0;
6323 xmlNodeSetPtr ns;
6324 xmlChar *str2;
6325
6326 if ((f == NULL) || (arg == NULL) ||
6327 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006328 xmlXPathReleaseObject(ctxt->context, arg);
6329 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006330 return(0);
6331 }
6332 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006333 if (ns != NULL) {
6334 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006335 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006336 if (str2 != NULL) {
6337 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006338 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006339 xmlFree(str2);
6340 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006341 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006342 ret = xmlXPathCompareValues(ctxt, inf, strict);
6343 if (ret)
6344 break;
6345 }
6346 }
Owen Taylor3473f882001-02-23 17:55:21 +00006347 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006348 xmlXPathReleaseObject(ctxt->context, arg);
6349 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006350 return(ret);
6351}
6352
6353/**
6354 * xmlXPathCompareNodeSetString:
6355 * @ctxt: the XPath Parser context
6356 * @inf: less than (1) or greater than (0)
6357 * @strict: is the comparison strict
6358 * @arg: the node set
6359 * @s: the value
6360 *
6361 * Implement the compare operation between a nodeset and a string
6362 * @ns < @val (1, 1, ...
6363 * @ns <= @val (1, 0, ...
6364 * @ns > @val (0, 1, ...
6365 * @ns >= @val (0, 0, ...
6366 *
6367 * If one object to be compared is a node-set and the other is a string,
6368 * then the comparison will be true if and only if there is a node in
6369 * the node-set such that the result of performing the comparison on the
6370 * string-value of the node and the other string is true.
6371 *
6372 * Returns 0 or 1 depending on the results of the test.
6373 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006374static int
Owen Taylor3473f882001-02-23 17:55:21 +00006375xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6376 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6377 int i, ret = 0;
6378 xmlNodeSetPtr ns;
6379 xmlChar *str2;
6380
6381 if ((s == NULL) || (arg == NULL) ||
6382 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006383 xmlXPathReleaseObject(ctxt->context, arg);
6384 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006385 return(0);
6386 }
6387 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006388 if (ns != NULL) {
6389 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006390 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006391 if (str2 != NULL) {
6392 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006393 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006394 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006395 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006396 ret = xmlXPathCompareValues(ctxt, inf, strict);
6397 if (ret)
6398 break;
6399 }
6400 }
Owen Taylor3473f882001-02-23 17:55:21 +00006401 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006402 xmlXPathReleaseObject(ctxt->context, arg);
6403 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006404 return(ret);
6405}
6406
6407/**
6408 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006409 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006410 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006411 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006412 * @arg2: the second node set object
6413 *
6414 * Implement the compare operation on nodesets:
6415 *
6416 * If both objects to be compared are node-sets, then the comparison
6417 * will be true if and only if there is a node in the first node-set
6418 * and a node in the second node-set such that the result of performing
6419 * the comparison on the string-values of the two nodes is true.
6420 * ....
6421 * When neither object to be compared is a node-set and the operator
6422 * is <=, <, >= or >, then the objects are compared by converting both
6423 * objects to numbers and comparing the numbers according to IEEE 754.
6424 * ....
6425 * The number function converts its argument to a number as follows:
6426 * - a string that consists of optional whitespace followed by an
6427 * optional minus sign followed by a Number followed by whitespace
6428 * is converted to the IEEE 754 number that is nearest (according
6429 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6430 * represented by the string; any other string is converted to NaN
6431 *
6432 * Conclusion all nodes need to be converted first to their string value
6433 * and then the comparison must be done when possible
6434 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006435static int
6436xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006437 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6438 int i, j, init = 0;
6439 double val1;
6440 double *values2;
6441 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006442 xmlNodeSetPtr ns1;
6443 xmlNodeSetPtr ns2;
6444
6445 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006446 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6447 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006448 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006449 }
Owen Taylor3473f882001-02-23 17:55:21 +00006450 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006451 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6452 xmlXPathFreeObject(arg1);
6453 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006454 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006455 }
Owen Taylor3473f882001-02-23 17:55:21 +00006456
6457 ns1 = arg1->nodesetval;
6458 ns2 = arg2->nodesetval;
6459
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006460 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006461 xmlXPathFreeObject(arg1);
6462 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006463 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006464 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006465 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006466 xmlXPathFreeObject(arg1);
6467 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006468 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006469 }
Owen Taylor3473f882001-02-23 17:55:21 +00006470
6471 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6472 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006473 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006474 xmlXPathFreeObject(arg1);
6475 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006476 return(0);
6477 }
6478 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006479 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006480 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006481 continue;
6482 for (j = 0;j < ns2->nodeNr;j++) {
6483 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006484 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006485 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006486 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006487 continue;
6488 if (inf && strict)
6489 ret = (val1 < values2[j]);
6490 else if (inf && !strict)
6491 ret = (val1 <= values2[j]);
6492 else if (!inf && strict)
6493 ret = (val1 > values2[j]);
6494 else if (!inf && !strict)
6495 ret = (val1 >= values2[j]);
6496 if (ret)
6497 break;
6498 }
6499 if (ret)
6500 break;
6501 init = 1;
6502 }
6503 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006504 xmlXPathFreeObject(arg1);
6505 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006506 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006507}
6508
6509/**
6510 * xmlXPathCompareNodeSetValue:
6511 * @ctxt: the XPath Parser context
6512 * @inf: less than (1) or greater than (0)
6513 * @strict: is the comparison strict
6514 * @arg: the node set
6515 * @val: the value
6516 *
6517 * Implement the compare operation between a nodeset and a value
6518 * @ns < @val (1, 1, ...
6519 * @ns <= @val (1, 0, ...
6520 * @ns > @val (0, 1, ...
6521 * @ns >= @val (0, 0, ...
6522 *
6523 * If one object to be compared is a node-set and the other is a boolean,
6524 * then the comparison will be true if and only if the result of performing
6525 * the comparison on the boolean and on the result of converting
6526 * the node-set to a boolean using the boolean function is true.
6527 *
6528 * Returns 0 or 1 depending on the results of the test.
6529 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006530static int
Owen Taylor3473f882001-02-23 17:55:21 +00006531xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6532 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6533 if ((val == NULL) || (arg == NULL) ||
6534 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6535 return(0);
6536
6537 switch(val->type) {
6538 case XPATH_NUMBER:
6539 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6540 case XPATH_NODESET:
6541 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006542 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006543 case XPATH_STRING:
6544 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6545 case XPATH_BOOLEAN:
6546 valuePush(ctxt, arg);
6547 xmlXPathBooleanFunction(ctxt, 1);
6548 valuePush(ctxt, val);
6549 return(xmlXPathCompareValues(ctxt, inf, strict));
6550 default:
6551 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006552 }
6553 return(0);
6554}
6555
6556/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006557 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006558 * @arg: the nodeset object argument
6559 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006560 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006561 *
6562 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6563 * If one object to be compared is a node-set and the other is a string,
6564 * then the comparison will be true if and only if there is a node in
6565 * the node-set such that the result of performing the comparison on the
6566 * string-value of the node and the other string is true.
6567 *
6568 * Returns 0 or 1 depending on the results of the test.
6569 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006570static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006571xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006572{
Owen Taylor3473f882001-02-23 17:55:21 +00006573 int i;
6574 xmlNodeSetPtr ns;
6575 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006576 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006577
6578 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006579 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6580 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006581 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006582 /*
6583 * A NULL nodeset compared with a string is always false
6584 * (since there is no node equal, and no node not equal)
6585 */
6586 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006587 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006588 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006589 for (i = 0; i < ns->nodeNr; i++) {
6590 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6591 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6592 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6593 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006594 if (neq)
6595 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006596 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006597 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6598 if (neq)
6599 continue;
6600 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006601 } else if (neq) {
6602 if (str2 != NULL)
6603 xmlFree(str2);
6604 return (1);
6605 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006606 if (str2 != NULL)
6607 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006608 } else if (neq)
6609 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006610 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006611 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006612}
6613
6614/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006615 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006616 * @arg: the nodeset object argument
6617 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006618 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006619 *
6620 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6621 * If one object to be compared is a node-set and the other is a number,
6622 * then the comparison will be true if and only if there is a node in
6623 * the node-set such that the result of performing the comparison on the
6624 * number to be compared and on the result of converting the string-value
6625 * of that node to a number using the number function is true.
6626 *
6627 * Returns 0 or 1 depending on the results of the test.
6628 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006629static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006630xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6631 xmlXPathObjectPtr arg, double f, int neq) {
6632 int i, ret=0;
6633 xmlNodeSetPtr ns;
6634 xmlChar *str2;
6635 xmlXPathObjectPtr val;
6636 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006637
6638 if ((arg == NULL) ||
6639 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6640 return(0);
6641
William M. Brack0c022ad2002-07-12 00:56:01 +00006642 ns = arg->nodesetval;
6643 if (ns != NULL) {
6644 for (i=0;i<ns->nodeNr;i++) {
6645 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6646 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006647 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006648 xmlFree(str2);
6649 xmlXPathNumberFunction(ctxt, 1);
6650 val = valuePop(ctxt);
6651 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006652 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006653 if (!xmlXPathIsNaN(v)) {
6654 if ((!neq) && (v==f)) {
6655 ret = 1;
6656 break;
6657 } else if ((neq) && (v!=f)) {
6658 ret = 1;
6659 break;
6660 }
William M. Brack32f0f712005-07-14 07:00:33 +00006661 } else { /* NaN is unequal to any value */
6662 if (neq)
6663 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006664 }
6665 }
6666 }
6667 }
6668
6669 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006670}
6671
6672
6673/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006674 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006675 * @arg1: first nodeset object argument
6676 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006677 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006678 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006679 * Implement the equal / not equal operation on XPath nodesets:
6680 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006681 * If both objects to be compared are node-sets, then the comparison
6682 * will be true if and only if there is a node in the first node-set and
6683 * a node in the second node-set such that the result of performing the
6684 * comparison on the string-values of the two nodes is true.
6685 *
6686 * (needless to say, this is a costly operation)
6687 *
6688 * Returns 0 or 1 depending on the results of the test.
6689 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006690static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006691xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006692 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006693 unsigned int *hashs1;
6694 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006695 xmlChar **values1;
6696 xmlChar **values2;
6697 int ret = 0;
6698 xmlNodeSetPtr ns1;
6699 xmlNodeSetPtr ns2;
6700
6701 if ((arg1 == NULL) ||
6702 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6703 return(0);
6704 if ((arg2 == NULL) ||
6705 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6706 return(0);
6707
6708 ns1 = arg1->nodesetval;
6709 ns2 = arg2->nodesetval;
6710
Daniel Veillard911f49a2001-04-07 15:39:35 +00006711 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006712 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006713 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006714 return(0);
6715
6716 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006717 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006718 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006719 if (neq == 0)
6720 for (i = 0;i < ns1->nodeNr;i++)
6721 for (j = 0;j < ns2->nodeNr;j++)
6722 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6723 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006724
6725 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006726 if (values1 == NULL) {
6727 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006728 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006729 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006730 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6731 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006732 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006733 xmlFree(values1);
6734 return(0);
6735 }
Owen Taylor3473f882001-02-23 17:55:21 +00006736 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6737 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6738 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006739 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006740 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006741 xmlFree(values1);
6742 return(0);
6743 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006744 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6745 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006746 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006747 xmlFree(hashs1);
6748 xmlFree(values1);
6749 xmlFree(values2);
6750 return(0);
6751 }
Owen Taylor3473f882001-02-23 17:55:21 +00006752 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6753 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006754 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006755 for (j = 0;j < ns2->nodeNr;j++) {
6756 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006757 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006758 if (hashs1[i] != hashs2[j]) {
6759 if (neq) {
6760 ret = 1;
6761 break;
6762 }
6763 }
6764 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006765 if (values1[i] == NULL)
6766 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6767 if (values2[j] == NULL)
6768 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006769 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006770 if (ret)
6771 break;
6772 }
Owen Taylor3473f882001-02-23 17:55:21 +00006773 }
6774 if (ret)
6775 break;
6776 }
6777 for (i = 0;i < ns1->nodeNr;i++)
6778 if (values1[i] != NULL)
6779 xmlFree(values1[i]);
6780 for (j = 0;j < ns2->nodeNr;j++)
6781 if (values2[j] != NULL)
6782 xmlFree(values2[j]);
6783 xmlFree(values1);
6784 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006785 xmlFree(hashs1);
6786 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006787 return(ret);
6788}
6789
William M. Brack0c022ad2002-07-12 00:56:01 +00006790static int
6791xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6792 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006793 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006794 /*
6795 *At this point we are assured neither arg1 nor arg2
6796 *is a nodeset, so we can just pick the appropriate routine.
6797 */
Owen Taylor3473f882001-02-23 17:55:21 +00006798 switch (arg1->type) {
6799 case XPATH_UNDEFINED:
6800#ifdef DEBUG_EXPR
6801 xmlGenericError(xmlGenericErrorContext,
6802 "Equal: undefined\n");
6803#endif
6804 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006805 case XPATH_BOOLEAN:
6806 switch (arg2->type) {
6807 case XPATH_UNDEFINED:
6808#ifdef DEBUG_EXPR
6809 xmlGenericError(xmlGenericErrorContext,
6810 "Equal: undefined\n");
6811#endif
6812 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006813 case XPATH_BOOLEAN:
6814#ifdef DEBUG_EXPR
6815 xmlGenericError(xmlGenericErrorContext,
6816 "Equal: %d boolean %d \n",
6817 arg1->boolval, arg2->boolval);
6818#endif
6819 ret = (arg1->boolval == arg2->boolval);
6820 break;
6821 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006822 ret = (arg1->boolval ==
6823 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006824 break;
6825 case XPATH_STRING:
6826 if ((arg2->stringval == NULL) ||
6827 (arg2->stringval[0] == 0)) ret = 0;
6828 else
6829 ret = 1;
6830 ret = (arg1->boolval == ret);
6831 break;
6832 case XPATH_USERS:
6833 case XPATH_POINT:
6834 case XPATH_RANGE:
6835 case XPATH_LOCATIONSET:
6836 TODO
6837 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006838 case XPATH_NODESET:
6839 case XPATH_XSLT_TREE:
6840 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006841 }
6842 break;
6843 case XPATH_NUMBER:
6844 switch (arg2->type) {
6845 case XPATH_UNDEFINED:
6846#ifdef DEBUG_EXPR
6847 xmlGenericError(xmlGenericErrorContext,
6848 "Equal: undefined\n");
6849#endif
6850 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006851 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006852 ret = (arg2->boolval==
6853 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006854 break;
6855 case XPATH_STRING:
6856 valuePush(ctxt, arg2);
6857 xmlXPathNumberFunction(ctxt, 1);
6858 arg2 = valuePop(ctxt);
6859 /* no break on purpose */
6860 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006861 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006862 if (xmlXPathIsNaN(arg1->floatval) ||
6863 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006864 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006865 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6866 if (xmlXPathIsInf(arg2->floatval) == 1)
6867 ret = 1;
6868 else
6869 ret = 0;
6870 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6871 if (xmlXPathIsInf(arg2->floatval) == -1)
6872 ret = 1;
6873 else
6874 ret = 0;
6875 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6876 if (xmlXPathIsInf(arg1->floatval) == 1)
6877 ret = 1;
6878 else
6879 ret = 0;
6880 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6881 if (xmlXPathIsInf(arg1->floatval) == -1)
6882 ret = 1;
6883 else
6884 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006885 } else {
6886 ret = (arg1->floatval == arg2->floatval);
6887 }
Owen Taylor3473f882001-02-23 17:55:21 +00006888 break;
6889 case XPATH_USERS:
6890 case XPATH_POINT:
6891 case XPATH_RANGE:
6892 case XPATH_LOCATIONSET:
6893 TODO
6894 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006895 case XPATH_NODESET:
6896 case XPATH_XSLT_TREE:
6897 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006898 }
6899 break;
6900 case XPATH_STRING:
6901 switch (arg2->type) {
6902 case XPATH_UNDEFINED:
6903#ifdef DEBUG_EXPR
6904 xmlGenericError(xmlGenericErrorContext,
6905 "Equal: undefined\n");
6906#endif
6907 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006908 case XPATH_BOOLEAN:
6909 if ((arg1->stringval == NULL) ||
6910 (arg1->stringval[0] == 0)) ret = 0;
6911 else
6912 ret = 1;
6913 ret = (arg2->boolval == ret);
6914 break;
6915 case XPATH_STRING:
6916 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6917 break;
6918 case XPATH_NUMBER:
6919 valuePush(ctxt, arg1);
6920 xmlXPathNumberFunction(ctxt, 1);
6921 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006922 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006923 if (xmlXPathIsNaN(arg1->floatval) ||
6924 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006925 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006926 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6927 if (xmlXPathIsInf(arg2->floatval) == 1)
6928 ret = 1;
6929 else
6930 ret = 0;
6931 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6932 if (xmlXPathIsInf(arg2->floatval) == -1)
6933 ret = 1;
6934 else
6935 ret = 0;
6936 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6937 if (xmlXPathIsInf(arg1->floatval) == 1)
6938 ret = 1;
6939 else
6940 ret = 0;
6941 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6942 if (xmlXPathIsInf(arg1->floatval) == -1)
6943 ret = 1;
6944 else
6945 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006946 } else {
6947 ret = (arg1->floatval == arg2->floatval);
6948 }
Owen Taylor3473f882001-02-23 17:55:21 +00006949 break;
6950 case XPATH_USERS:
6951 case XPATH_POINT:
6952 case XPATH_RANGE:
6953 case XPATH_LOCATIONSET:
6954 TODO
6955 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006956 case XPATH_NODESET:
6957 case XPATH_XSLT_TREE:
6958 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006959 }
6960 break;
6961 case XPATH_USERS:
6962 case XPATH_POINT:
6963 case XPATH_RANGE:
6964 case XPATH_LOCATIONSET:
6965 TODO
6966 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006967 case XPATH_NODESET:
6968 case XPATH_XSLT_TREE:
6969 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006970 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006971 xmlXPathReleaseObject(ctxt->context, arg1);
6972 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006973 return(ret);
6974}
6975
William M. Brack0c022ad2002-07-12 00:56:01 +00006976/**
6977 * xmlXPathEqualValues:
6978 * @ctxt: the XPath Parser context
6979 *
6980 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6981 *
6982 * Returns 0 or 1 depending on the results of the test.
6983 */
6984int
6985xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6986 xmlXPathObjectPtr arg1, arg2, argtmp;
6987 int ret = 0;
6988
Daniel Veillard6128c012004-11-08 17:16:15 +00006989 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006990 arg2 = valuePop(ctxt);
6991 arg1 = valuePop(ctxt);
6992 if ((arg1 == NULL) || (arg2 == NULL)) {
6993 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006994 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006995 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006996 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006997 XP_ERROR0(XPATH_INVALID_OPERAND);
6998 }
6999
7000 if (arg1 == arg2) {
7001#ifdef DEBUG_EXPR
7002 xmlGenericError(xmlGenericErrorContext,
7003 "Equal: by pointer\n");
7004#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007005 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007006 return(1);
7007 }
7008
7009 /*
7010 *If either argument is a nodeset, it's a 'special case'
7011 */
7012 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7013 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7014 /*
7015 *Hack it to assure arg1 is the nodeset
7016 */
7017 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7018 argtmp = arg2;
7019 arg2 = arg1;
7020 arg1 = argtmp;
7021 }
7022 switch (arg2->type) {
7023 case XPATH_UNDEFINED:
7024#ifdef DEBUG_EXPR
7025 xmlGenericError(xmlGenericErrorContext,
7026 "Equal: undefined\n");
7027#endif
7028 break;
7029 case XPATH_NODESET:
7030 case XPATH_XSLT_TREE:
7031 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7032 break;
7033 case XPATH_BOOLEAN:
7034 if ((arg1->nodesetval == NULL) ||
7035 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7036 else
7037 ret = 1;
7038 ret = (ret == arg2->boolval);
7039 break;
7040 case XPATH_NUMBER:
7041 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7042 break;
7043 case XPATH_STRING:
7044 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7045 break;
7046 case XPATH_USERS:
7047 case XPATH_POINT:
7048 case XPATH_RANGE:
7049 case XPATH_LOCATIONSET:
7050 TODO
7051 break;
7052 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007053 xmlXPathReleaseObject(ctxt->context, arg1);
7054 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007055 return(ret);
7056 }
7057
7058 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7059}
7060
7061/**
7062 * xmlXPathNotEqualValues:
7063 * @ctxt: the XPath Parser context
7064 *
7065 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7066 *
7067 * Returns 0 or 1 depending on the results of the test.
7068 */
7069int
7070xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7071 xmlXPathObjectPtr arg1, arg2, argtmp;
7072 int ret = 0;
7073
Daniel Veillard6128c012004-11-08 17:16:15 +00007074 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007075 arg2 = valuePop(ctxt);
7076 arg1 = valuePop(ctxt);
7077 if ((arg1 == NULL) || (arg2 == NULL)) {
7078 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007079 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007080 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007081 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007082 XP_ERROR0(XPATH_INVALID_OPERAND);
7083 }
7084
7085 if (arg1 == arg2) {
7086#ifdef DEBUG_EXPR
7087 xmlGenericError(xmlGenericErrorContext,
7088 "NotEqual: by pointer\n");
7089#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007090 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007091 return(0);
7092 }
7093
7094 /*
7095 *If either argument is a nodeset, it's a 'special case'
7096 */
7097 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7098 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7099 /*
7100 *Hack it to assure arg1 is the nodeset
7101 */
7102 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7103 argtmp = arg2;
7104 arg2 = arg1;
7105 arg1 = argtmp;
7106 }
7107 switch (arg2->type) {
7108 case XPATH_UNDEFINED:
7109#ifdef DEBUG_EXPR
7110 xmlGenericError(xmlGenericErrorContext,
7111 "NotEqual: undefined\n");
7112#endif
7113 break;
7114 case XPATH_NODESET:
7115 case XPATH_XSLT_TREE:
7116 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7117 break;
7118 case XPATH_BOOLEAN:
7119 if ((arg1->nodesetval == NULL) ||
7120 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7121 else
7122 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007123 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007124 break;
7125 case XPATH_NUMBER:
7126 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7127 break;
7128 case XPATH_STRING:
7129 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7130 break;
7131 case XPATH_USERS:
7132 case XPATH_POINT:
7133 case XPATH_RANGE:
7134 case XPATH_LOCATIONSET:
7135 TODO
7136 break;
7137 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007138 xmlXPathReleaseObject(ctxt->context, arg1);
7139 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007140 return(ret);
7141 }
7142
7143 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7144}
Owen Taylor3473f882001-02-23 17:55:21 +00007145
7146/**
7147 * xmlXPathCompareValues:
7148 * @ctxt: the XPath Parser context
7149 * @inf: less than (1) or greater than (0)
7150 * @strict: is the comparison strict
7151 *
7152 * Implement the compare operation on XPath objects:
7153 * @arg1 < @arg2 (1, 1, ...
7154 * @arg1 <= @arg2 (1, 0, ...
7155 * @arg1 > @arg2 (0, 1, ...
7156 * @arg1 >= @arg2 (0, 0, ...
7157 *
7158 * When neither object to be compared is a node-set and the operator is
7159 * <=, <, >=, >, then the objects are compared by converted both objects
7160 * to numbers and comparing the numbers according to IEEE 754. The <
7161 * comparison will be true if and only if the first number is less than the
7162 * second number. The <= comparison will be true if and only if the first
7163 * number is less than or equal to the second number. The > comparison
7164 * will be true if and only if the first number is greater than the second
7165 * number. The >= comparison will be true if and only if the first number
7166 * is greater than or equal to the second number.
7167 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007168 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007169 */
7170int
7171xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007172 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007173 xmlXPathObjectPtr arg1, arg2;
7174
Daniel Veillard6128c012004-11-08 17:16:15 +00007175 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007176 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007177 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007178 if ((arg1 == NULL) || (arg2 == NULL)) {
7179 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007180 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007181 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007182 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007183 XP_ERROR0(XPATH_INVALID_OPERAND);
7184 }
7185
William M. Brack0c022ad2002-07-12 00:56:01 +00007186 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7187 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007188 /*
7189 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7190 * are not freed from within this routine; they will be freed from the
7191 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7192 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007193 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7194 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007195 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007196 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007197 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007198 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7199 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007200 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007201 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7202 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007203 }
7204 }
7205 return(ret);
7206 }
7207
7208 if (arg1->type != XPATH_NUMBER) {
7209 valuePush(ctxt, arg1);
7210 xmlXPathNumberFunction(ctxt, 1);
7211 arg1 = valuePop(ctxt);
7212 }
7213 if (arg1->type != XPATH_NUMBER) {
7214 xmlXPathFreeObject(arg1);
7215 xmlXPathFreeObject(arg2);
7216 XP_ERROR0(XPATH_INVALID_OPERAND);
7217 }
7218 if (arg2->type != XPATH_NUMBER) {
7219 valuePush(ctxt, arg2);
7220 xmlXPathNumberFunction(ctxt, 1);
7221 arg2 = valuePop(ctxt);
7222 }
7223 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007224 xmlXPathReleaseObject(ctxt->context, arg1);
7225 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007226 XP_ERROR0(XPATH_INVALID_OPERAND);
7227 }
7228 /*
7229 * Add tests for infinity and nan
7230 * => feedback on 3.4 for Inf and NaN
7231 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007232 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007233 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007234 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007235 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007236 arg1i=xmlXPathIsInf(arg1->floatval);
7237 arg2i=xmlXPathIsInf(arg2->floatval);
7238 if (inf && strict) {
7239 if ((arg1i == -1 && arg2i != -1) ||
7240 (arg2i == 1 && arg1i != 1)) {
7241 ret = 1;
7242 } else if (arg1i == 0 && arg2i == 0) {
7243 ret = (arg1->floatval < arg2->floatval);
7244 } else {
7245 ret = 0;
7246 }
7247 }
7248 else if (inf && !strict) {
7249 if (arg1i == -1 || arg2i == 1) {
7250 ret = 1;
7251 } else if (arg1i == 0 && arg2i == 0) {
7252 ret = (arg1->floatval <= arg2->floatval);
7253 } else {
7254 ret = 0;
7255 }
7256 }
7257 else if (!inf && strict) {
7258 if ((arg1i == 1 && arg2i != 1) ||
7259 (arg2i == -1 && arg1i != -1)) {
7260 ret = 1;
7261 } else if (arg1i == 0 && arg2i == 0) {
7262 ret = (arg1->floatval > arg2->floatval);
7263 } else {
7264 ret = 0;
7265 }
7266 }
7267 else if (!inf && !strict) {
7268 if (arg1i == 1 || arg2i == -1) {
7269 ret = 1;
7270 } else if (arg1i == 0 && arg2i == 0) {
7271 ret = (arg1->floatval >= arg2->floatval);
7272 } else {
7273 ret = 0;
7274 }
7275 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007276 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007277 xmlXPathReleaseObject(ctxt->context, arg1);
7278 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007279 return(ret);
7280}
7281
7282/**
7283 * xmlXPathValueFlipSign:
7284 * @ctxt: the XPath Parser context
7285 *
7286 * Implement the unary - operation on an XPath object
7287 * The numeric operators convert their operands to numbers as if
7288 * by calling the number function.
7289 */
7290void
7291xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007292 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007293 CAST_TO_NUMBER;
7294 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007295 if (xmlXPathIsNaN(ctxt->value->floatval))
7296 ctxt->value->floatval=xmlXPathNAN;
7297 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7298 ctxt->value->floatval=xmlXPathNINF;
7299 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7300 ctxt->value->floatval=xmlXPathPINF;
7301 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007302 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7303 ctxt->value->floatval = xmlXPathNZERO;
7304 else
7305 ctxt->value->floatval = 0;
7306 }
7307 else
7308 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007309}
7310
7311/**
7312 * xmlXPathAddValues:
7313 * @ctxt: the XPath Parser context
7314 *
7315 * Implement the add operation on XPath objects:
7316 * The numeric operators convert their operands to numbers as if
7317 * by calling the number function.
7318 */
7319void
7320xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7321 xmlXPathObjectPtr arg;
7322 double val;
7323
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007324 arg = valuePop(ctxt);
7325 if (arg == NULL)
7326 XP_ERROR(XPATH_INVALID_OPERAND);
7327 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007328 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007329 CAST_TO_NUMBER;
7330 CHECK_TYPE(XPATH_NUMBER);
7331 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007332}
7333
7334/**
7335 * xmlXPathSubValues:
7336 * @ctxt: the XPath Parser context
7337 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007338 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007339 * The numeric operators convert their operands to numbers as if
7340 * by calling the number function.
7341 */
7342void
7343xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7344 xmlXPathObjectPtr arg;
7345 double val;
7346
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007347 arg = valuePop(ctxt);
7348 if (arg == NULL)
7349 XP_ERROR(XPATH_INVALID_OPERAND);
7350 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007351 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007352 CAST_TO_NUMBER;
7353 CHECK_TYPE(XPATH_NUMBER);
7354 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007355}
7356
7357/**
7358 * xmlXPathMultValues:
7359 * @ctxt: the XPath Parser context
7360 *
7361 * Implement the multiply operation on XPath objects:
7362 * The numeric operators convert their operands to numbers as if
7363 * by calling the number function.
7364 */
7365void
7366xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7367 xmlXPathObjectPtr arg;
7368 double val;
7369
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007370 arg = valuePop(ctxt);
7371 if (arg == NULL)
7372 XP_ERROR(XPATH_INVALID_OPERAND);
7373 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007374 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007375 CAST_TO_NUMBER;
7376 CHECK_TYPE(XPATH_NUMBER);
7377 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007378}
7379
7380/**
7381 * xmlXPathDivValues:
7382 * @ctxt: the XPath Parser context
7383 *
7384 * Implement the div operation on XPath objects @arg1 / @arg2:
7385 * The numeric operators convert their operands to numbers as if
7386 * by calling the number function.
7387 */
7388void
7389xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7390 xmlXPathObjectPtr arg;
7391 double val;
7392
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007393 arg = valuePop(ctxt);
7394 if (arg == NULL)
7395 XP_ERROR(XPATH_INVALID_OPERAND);
7396 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007397 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007398 CAST_TO_NUMBER;
7399 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007400 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7401 ctxt->value->floatval = xmlXPathNAN;
7402 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007403 if (ctxt->value->floatval == 0)
7404 ctxt->value->floatval = xmlXPathNAN;
7405 else if (ctxt->value->floatval > 0)
7406 ctxt->value->floatval = xmlXPathNINF;
7407 else if (ctxt->value->floatval < 0)
7408 ctxt->value->floatval = xmlXPathPINF;
7409 }
7410 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007411 if (ctxt->value->floatval == 0)
7412 ctxt->value->floatval = xmlXPathNAN;
7413 else if (ctxt->value->floatval > 0)
7414 ctxt->value->floatval = xmlXPathPINF;
7415 else if (ctxt->value->floatval < 0)
7416 ctxt->value->floatval = xmlXPathNINF;
7417 } else
7418 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007419}
7420
7421/**
7422 * xmlXPathModValues:
7423 * @ctxt: the XPath Parser context
7424 *
7425 * Implement the mod operation on XPath objects: @arg1 / @arg2
7426 * The numeric operators convert their operands to numbers as if
7427 * by calling the number function.
7428 */
7429void
7430xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7431 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007432 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007433
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007434 arg = valuePop(ctxt);
7435 if (arg == NULL)
7436 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007437 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007438 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007439 CAST_TO_NUMBER;
7440 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007441 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007442 if (arg2 == 0)
7443 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007444 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007445 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007446 }
Owen Taylor3473f882001-02-23 17:55:21 +00007447}
7448
7449/************************************************************************
7450 * *
7451 * The traversal functions *
7452 * *
7453 ************************************************************************/
7454
Owen Taylor3473f882001-02-23 17:55:21 +00007455/*
7456 * A traversal function enumerates nodes along an axis.
7457 * Initially it must be called with NULL, and it indicates
7458 * termination on the axis by returning NULL.
7459 */
7460typedef xmlNodePtr (*xmlXPathTraversalFunction)
7461 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7462
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007463/*
7464 * xmlXPathTraversalFunctionExt:
7465 * A traversal function enumerates nodes along an axis.
7466 * Initially it must be called with NULL, and it indicates
7467 * termination on the axis by returning NULL.
7468 * The context node of the traversal is specified via @contextNode.
7469 */
7470typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7471 (xmlNodePtr cur, xmlNodePtr contextNode);
7472
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007473/*
7474 * xmlXPathNodeSetMergeFunction:
7475 * Used for merging node sets in xmlXPathCollectAndTest().
7476 */
7477typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7478 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7479
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007480
Owen Taylor3473f882001-02-23 17:55:21 +00007481/**
7482 * xmlXPathNextSelf:
7483 * @ctxt: the XPath Parser context
7484 * @cur: the current node in the traversal
7485 *
7486 * Traversal function for the "self" direction
7487 * The self axis contains just the context node itself
7488 *
7489 * Returns the next element following that axis
7490 */
7491xmlNodePtr
7492xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007493 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007494 if (cur == NULL)
7495 return(ctxt->context->node);
7496 return(NULL);
7497}
7498
7499/**
7500 * xmlXPathNextChild:
7501 * @ctxt: the XPath Parser context
7502 * @cur: the current node in the traversal
7503 *
7504 * Traversal function for the "child" direction
7505 * The child axis contains the children of the context node in document order.
7506 *
7507 * Returns the next element following that axis
7508 */
7509xmlNodePtr
7510xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007511 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007512 if (cur == NULL) {
7513 if (ctxt->context->node == NULL) return(NULL);
7514 switch (ctxt->context->node->type) {
7515 case XML_ELEMENT_NODE:
7516 case XML_TEXT_NODE:
7517 case XML_CDATA_SECTION_NODE:
7518 case XML_ENTITY_REF_NODE:
7519 case XML_ENTITY_NODE:
7520 case XML_PI_NODE:
7521 case XML_COMMENT_NODE:
7522 case XML_NOTATION_NODE:
7523 case XML_DTD_NODE:
7524 return(ctxt->context->node->children);
7525 case XML_DOCUMENT_NODE:
7526 case XML_DOCUMENT_TYPE_NODE:
7527 case XML_DOCUMENT_FRAG_NODE:
7528 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007529#ifdef LIBXML_DOCB_ENABLED
7530 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007531#endif
7532 return(((xmlDocPtr) ctxt->context->node)->children);
7533 case XML_ELEMENT_DECL:
7534 case XML_ATTRIBUTE_DECL:
7535 case XML_ENTITY_DECL:
7536 case XML_ATTRIBUTE_NODE:
7537 case XML_NAMESPACE_DECL:
7538 case XML_XINCLUDE_START:
7539 case XML_XINCLUDE_END:
7540 return(NULL);
7541 }
7542 return(NULL);
7543 }
7544 if ((cur->type == XML_DOCUMENT_NODE) ||
7545 (cur->type == XML_HTML_DOCUMENT_NODE))
7546 return(NULL);
7547 return(cur->next);
7548}
7549
7550/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007551 * xmlXPathNextChildElement:
7552 * @ctxt: the XPath Parser context
7553 * @cur: the current node in the traversal
7554 *
7555 * Traversal function for the "child" direction and nodes of type element.
7556 * The child axis contains the children of the context node in document order.
7557 *
7558 * Returns the next element following that axis
7559 */
7560static xmlNodePtr
7561xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7562 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7563 if (cur == NULL) {
7564 cur = ctxt->context->node;
7565 if (cur == NULL) return(NULL);
7566 /*
7567 * Get the first element child.
7568 */
7569 switch (cur->type) {
7570 case XML_ELEMENT_NODE:
7571 case XML_DOCUMENT_FRAG_NODE:
7572 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7573 case XML_ENTITY_NODE:
7574 cur = cur->children;
7575 if (cur != NULL) {
7576 if (cur->type == XML_ELEMENT_NODE)
7577 return(cur);
7578 do {
7579 cur = cur->next;
7580 } while ((cur != NULL) &&
7581 (cur->type != XML_ELEMENT_NODE));
7582 return(cur);
7583 }
7584 return(NULL);
7585 case XML_DOCUMENT_NODE:
7586 case XML_HTML_DOCUMENT_NODE:
7587#ifdef LIBXML_DOCB_ENABLED
7588 case XML_DOCB_DOCUMENT_NODE:
7589#endif
7590 return(xmlDocGetRootElement((xmlDocPtr) cur));
7591 default:
7592 return(NULL);
7593 }
7594 return(NULL);
7595 }
7596 /*
7597 * Get the next sibling element node.
7598 */
7599 switch (cur->type) {
7600 case XML_ELEMENT_NODE:
7601 case XML_TEXT_NODE:
7602 case XML_ENTITY_REF_NODE:
7603 case XML_ENTITY_NODE:
7604 case XML_CDATA_SECTION_NODE:
7605 case XML_PI_NODE:
7606 case XML_COMMENT_NODE:
7607 case XML_XINCLUDE_END:
7608 break;
7609 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7610 default:
7611 return(NULL);
7612 }
7613 if (cur->next != NULL) {
7614 if (cur->next->type == XML_ELEMENT_NODE)
7615 return(cur->next);
7616 cur = cur->next;
7617 do {
7618 cur = cur->next;
7619 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7620 return(cur);
7621 }
7622 return(NULL);
7623}
7624
7625/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007626 * xmlXPathNextDescendantOrSelfElemParent:
7627 * @ctxt: the XPath Parser context
7628 * @cur: the current node in the traversal
7629 *
7630 * Traversal function for the "descendant-or-self" axis.
7631 * Additionally it returns only nodes which can be parents of
7632 * element nodes.
7633 *
7634 *
7635 * Returns the next element following that axis
7636 */
7637static xmlNodePtr
7638xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7639 xmlNodePtr contextNode)
7640{
7641 if (cur == NULL) {
7642 if (contextNode == NULL)
7643 return(NULL);
7644 switch (contextNode->type) {
7645 case XML_ELEMENT_NODE:
7646 case XML_XINCLUDE_START:
7647 case XML_DOCUMENT_FRAG_NODE:
7648 case XML_DOCUMENT_NODE:
7649#ifdef LIBXML_DOCB_ENABLED
7650 case XML_DOCB_DOCUMENT_NODE:
7651#endif
7652 case XML_HTML_DOCUMENT_NODE:
7653 return(contextNode);
7654 default:
7655 return(NULL);
7656 }
7657 return(NULL);
7658 } else {
7659 xmlNodePtr start = cur;
7660
7661 while (cur != NULL) {
7662 switch (cur->type) {
7663 case XML_ELEMENT_NODE:
7664 /* TODO: OK to have XInclude here? */
7665 case XML_XINCLUDE_START:
7666 case XML_DOCUMENT_FRAG_NODE:
7667 if (cur != start)
7668 return(cur);
7669 if (cur->children != NULL) {
7670 cur = cur->children;
7671 continue;
7672 }
7673 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007674 /* Not sure if we need those here. */
7675 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007676#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007677 case XML_DOCB_DOCUMENT_NODE:
7678#endif
7679 case XML_HTML_DOCUMENT_NODE:
7680 if (cur != start)
7681 return(cur);
7682 return(xmlDocGetRootElement((xmlDocPtr) cur));
7683 default:
7684 break;
7685 }
7686
7687next_sibling:
7688 if ((cur == NULL) || (cur == contextNode))
7689 return(NULL);
7690 if (cur->next != NULL) {
7691 cur = cur->next;
7692 } else {
7693 cur = cur->parent;
7694 goto next_sibling;
7695 }
7696 }
7697 }
7698 return(NULL);
7699}
7700
7701/**
Owen Taylor3473f882001-02-23 17:55:21 +00007702 * xmlXPathNextDescendant:
7703 * @ctxt: the XPath Parser context
7704 * @cur: the current node in the traversal
7705 *
7706 * Traversal function for the "descendant" direction
7707 * the descendant axis contains the descendants of the context node in document
7708 * order; a descendant is a child or a child of a child and so on.
7709 *
7710 * Returns the next element following that axis
7711 */
7712xmlNodePtr
7713xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007714 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007715 if (cur == NULL) {
7716 if (ctxt->context->node == NULL)
7717 return(NULL);
7718 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7719 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7720 return(NULL);
7721
7722 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7723 return(ctxt->context->doc->children);
7724 return(ctxt->context->node->children);
7725 }
7726
Daniel Veillard567e1b42001-08-01 15:53:47 +00007727 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007728 /*
7729 * Do not descend on entities declarations
7730 */
7731 if (cur->children->type != XML_ENTITY_DECL) {
7732 cur = cur->children;
7733 /*
7734 * Skip DTDs
7735 */
7736 if (cur->type != XML_DTD_NODE)
7737 return(cur);
7738 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007739 }
7740
7741 if (cur == ctxt->context->node) return(NULL);
7742
Daniel Veillard68e9e742002-11-16 15:35:11 +00007743 while (cur->next != NULL) {
7744 cur = cur->next;
7745 if ((cur->type != XML_ENTITY_DECL) &&
7746 (cur->type != XML_DTD_NODE))
7747 return(cur);
7748 }
Owen Taylor3473f882001-02-23 17:55:21 +00007749
7750 do {
7751 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007752 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007753 if (cur == ctxt->context->node) return(NULL);
7754 if (cur->next != NULL) {
7755 cur = cur->next;
7756 return(cur);
7757 }
7758 } while (cur != NULL);
7759 return(cur);
7760}
7761
7762/**
7763 * xmlXPathNextDescendantOrSelf:
7764 * @ctxt: the XPath Parser context
7765 * @cur: the current node in the traversal
7766 *
7767 * Traversal function for the "descendant-or-self" direction
7768 * the descendant-or-self axis contains the context node and the descendants
7769 * of the context node in document order; thus the context node is the first
7770 * node on the axis, and the first child of the context node is the second node
7771 * on the axis
7772 *
7773 * Returns the next element following that axis
7774 */
7775xmlNodePtr
7776xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007777 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007778 if (cur == NULL) {
7779 if (ctxt->context->node == NULL)
7780 return(NULL);
7781 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7782 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7783 return(NULL);
7784 return(ctxt->context->node);
7785 }
7786
7787 return(xmlXPathNextDescendant(ctxt, cur));
7788}
7789
7790/**
7791 * xmlXPathNextParent:
7792 * @ctxt: the XPath Parser context
7793 * @cur: the current node in the traversal
7794 *
7795 * Traversal function for the "parent" direction
7796 * The parent axis contains the parent of the context node, if there is one.
7797 *
7798 * Returns the next element following that axis
7799 */
7800xmlNodePtr
7801xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007802 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007803 /*
7804 * the parent of an attribute or namespace node is the element
7805 * to which the attribute or namespace node is attached
7806 * Namespace handling !!!
7807 */
7808 if (cur == NULL) {
7809 if (ctxt->context->node == NULL) return(NULL);
7810 switch (ctxt->context->node->type) {
7811 case XML_ELEMENT_NODE:
7812 case XML_TEXT_NODE:
7813 case XML_CDATA_SECTION_NODE:
7814 case XML_ENTITY_REF_NODE:
7815 case XML_ENTITY_NODE:
7816 case XML_PI_NODE:
7817 case XML_COMMENT_NODE:
7818 case XML_NOTATION_NODE:
7819 case XML_DTD_NODE:
7820 case XML_ELEMENT_DECL:
7821 case XML_ATTRIBUTE_DECL:
7822 case XML_XINCLUDE_START:
7823 case XML_XINCLUDE_END:
7824 case XML_ENTITY_DECL:
7825 if (ctxt->context->node->parent == NULL)
7826 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007827 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007828 ((ctxt->context->node->parent->name[0] == ' ') ||
7829 (xmlStrEqual(ctxt->context->node->parent->name,
7830 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007831 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007832 return(ctxt->context->node->parent);
7833 case XML_ATTRIBUTE_NODE: {
7834 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7835
7836 return(att->parent);
7837 }
7838 case XML_DOCUMENT_NODE:
7839 case XML_DOCUMENT_TYPE_NODE:
7840 case XML_DOCUMENT_FRAG_NODE:
7841 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007842#ifdef LIBXML_DOCB_ENABLED
7843 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007844#endif
7845 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007846 case XML_NAMESPACE_DECL: {
7847 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7848
7849 if ((ns->next != NULL) &&
7850 (ns->next->type != XML_NAMESPACE_DECL))
7851 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007852 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007853 }
Owen Taylor3473f882001-02-23 17:55:21 +00007854 }
7855 }
7856 return(NULL);
7857}
7858
7859/**
7860 * xmlXPathNextAncestor:
7861 * @ctxt: the XPath Parser context
7862 * @cur: the current node in the traversal
7863 *
7864 * Traversal function for the "ancestor" direction
7865 * the ancestor axis contains the ancestors of the context node; the ancestors
7866 * of the context node consist of the parent of context node and the parent's
7867 * parent and so on; the nodes are ordered in reverse document order; thus the
7868 * parent is the first node on the axis, and the parent's parent is the second
7869 * node on the axis
7870 *
7871 * Returns the next element following that axis
7872 */
7873xmlNodePtr
7874xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007875 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007876 /*
7877 * the parent of an attribute or namespace node is the element
7878 * to which the attribute or namespace node is attached
7879 * !!!!!!!!!!!!!
7880 */
7881 if (cur == NULL) {
7882 if (ctxt->context->node == NULL) return(NULL);
7883 switch (ctxt->context->node->type) {
7884 case XML_ELEMENT_NODE:
7885 case XML_TEXT_NODE:
7886 case XML_CDATA_SECTION_NODE:
7887 case XML_ENTITY_REF_NODE:
7888 case XML_ENTITY_NODE:
7889 case XML_PI_NODE:
7890 case XML_COMMENT_NODE:
7891 case XML_DTD_NODE:
7892 case XML_ELEMENT_DECL:
7893 case XML_ATTRIBUTE_DECL:
7894 case XML_ENTITY_DECL:
7895 case XML_NOTATION_NODE:
7896 case XML_XINCLUDE_START:
7897 case XML_XINCLUDE_END:
7898 if (ctxt->context->node->parent == NULL)
7899 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007900 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007901 ((ctxt->context->node->parent->name[0] == ' ') ||
7902 (xmlStrEqual(ctxt->context->node->parent->name,
7903 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007904 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007905 return(ctxt->context->node->parent);
7906 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007907 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007908
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007909 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007910 }
7911 case XML_DOCUMENT_NODE:
7912 case XML_DOCUMENT_TYPE_NODE:
7913 case XML_DOCUMENT_FRAG_NODE:
7914 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007915#ifdef LIBXML_DOCB_ENABLED
7916 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007917#endif
7918 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007919 case XML_NAMESPACE_DECL: {
7920 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7921
7922 if ((ns->next != NULL) &&
7923 (ns->next->type != XML_NAMESPACE_DECL))
7924 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007925 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007926 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007927 }
Owen Taylor3473f882001-02-23 17:55:21 +00007928 }
7929 return(NULL);
7930 }
7931 if (cur == ctxt->context->doc->children)
7932 return((xmlNodePtr) ctxt->context->doc);
7933 if (cur == (xmlNodePtr) ctxt->context->doc)
7934 return(NULL);
7935 switch (cur->type) {
7936 case XML_ELEMENT_NODE:
7937 case XML_TEXT_NODE:
7938 case XML_CDATA_SECTION_NODE:
7939 case XML_ENTITY_REF_NODE:
7940 case XML_ENTITY_NODE:
7941 case XML_PI_NODE:
7942 case XML_COMMENT_NODE:
7943 case XML_NOTATION_NODE:
7944 case XML_DTD_NODE:
7945 case XML_ELEMENT_DECL:
7946 case XML_ATTRIBUTE_DECL:
7947 case XML_ENTITY_DECL:
7948 case XML_XINCLUDE_START:
7949 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007950 if (cur->parent == NULL)
7951 return(NULL);
7952 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007953 ((cur->parent->name[0] == ' ') ||
7954 (xmlStrEqual(cur->parent->name,
7955 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007956 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007957 return(cur->parent);
7958 case XML_ATTRIBUTE_NODE: {
7959 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7960
7961 return(att->parent);
7962 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007963 case XML_NAMESPACE_DECL: {
7964 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7965
7966 if ((ns->next != NULL) &&
7967 (ns->next->type != XML_NAMESPACE_DECL))
7968 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007969 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007970 return(NULL);
7971 }
Owen Taylor3473f882001-02-23 17:55:21 +00007972 case XML_DOCUMENT_NODE:
7973 case XML_DOCUMENT_TYPE_NODE:
7974 case XML_DOCUMENT_FRAG_NODE:
7975 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007976#ifdef LIBXML_DOCB_ENABLED
7977 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007978#endif
7979 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007980 }
7981 return(NULL);
7982}
7983
7984/**
7985 * xmlXPathNextAncestorOrSelf:
7986 * @ctxt: the XPath Parser context
7987 * @cur: the current node in the traversal
7988 *
7989 * Traversal function for the "ancestor-or-self" direction
7990 * he ancestor-or-self axis contains the context node and ancestors of
7991 * the context node in reverse document order; thus the context node is
7992 * the first node on the axis, and the context node's parent the second;
7993 * parent here is defined the same as with the parent axis.
7994 *
7995 * Returns the next element following that axis
7996 */
7997xmlNodePtr
7998xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007999 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008000 if (cur == NULL)
8001 return(ctxt->context->node);
8002 return(xmlXPathNextAncestor(ctxt, cur));
8003}
8004
8005/**
8006 * xmlXPathNextFollowingSibling:
8007 * @ctxt: the XPath Parser context
8008 * @cur: the current node in the traversal
8009 *
8010 * Traversal function for the "following-sibling" direction
8011 * The following-sibling axis contains the following siblings of the context
8012 * node in document order.
8013 *
8014 * Returns the next element following that axis
8015 */
8016xmlNodePtr
8017xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008018 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008019 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8020 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8021 return(NULL);
8022 if (cur == (xmlNodePtr) ctxt->context->doc)
8023 return(NULL);
8024 if (cur == NULL)
8025 return(ctxt->context->node->next);
8026 return(cur->next);
8027}
8028
8029/**
8030 * xmlXPathNextPrecedingSibling:
8031 * @ctxt: the XPath Parser context
8032 * @cur: the current node in the traversal
8033 *
8034 * Traversal function for the "preceding-sibling" direction
8035 * The preceding-sibling axis contains the preceding siblings of the context
8036 * node in reverse document order; the first preceding sibling is first on the
8037 * axis; the sibling preceding that node is the second on the axis and so on.
8038 *
8039 * Returns the next element following that axis
8040 */
8041xmlNodePtr
8042xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008043 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008044 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8045 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8046 return(NULL);
8047 if (cur == (xmlNodePtr) ctxt->context->doc)
8048 return(NULL);
8049 if (cur == NULL)
8050 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008051 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8052 cur = cur->prev;
8053 if (cur == NULL)
8054 return(ctxt->context->node->prev);
8055 }
Owen Taylor3473f882001-02-23 17:55:21 +00008056 return(cur->prev);
8057}
8058
8059/**
8060 * xmlXPathNextFollowing:
8061 * @ctxt: the XPath Parser context
8062 * @cur: the current node in the traversal
8063 *
8064 * Traversal function for the "following" direction
8065 * The following axis contains all nodes in the same document as the context
8066 * node that are after the context node in document order, excluding any
8067 * descendants and excluding attribute nodes and namespace nodes; the nodes
8068 * are ordered in document order
8069 *
8070 * Returns the next element following that axis
8071 */
8072xmlNodePtr
8073xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008074 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008075 if (cur != NULL && cur->children != NULL)
8076 return cur->children ;
8077 if (cur == NULL) cur = ctxt->context->node;
8078 if (cur == NULL) return(NULL) ; /* ERROR */
8079 if (cur->next != NULL) return(cur->next) ;
8080 do {
8081 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008082 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008083 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8084 if (cur->next != NULL) return(cur->next);
8085 } while (cur != NULL);
8086 return(cur);
8087}
8088
8089/*
8090 * xmlXPathIsAncestor:
8091 * @ancestor: the ancestor node
8092 * @node: the current node
8093 *
8094 * Check that @ancestor is a @node's ancestor
8095 *
8096 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8097 */
8098static int
8099xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8100 if ((ancestor == NULL) || (node == NULL)) return(0);
8101 /* nodes need to be in the same document */
8102 if (ancestor->doc != node->doc) return(0);
8103 /* avoid searching if ancestor or node is the root node */
8104 if (ancestor == (xmlNodePtr) node->doc) return(1);
8105 if (node == (xmlNodePtr) ancestor->doc) return(0);
8106 while (node->parent != NULL) {
8107 if (node->parent == ancestor)
8108 return(1);
8109 node = node->parent;
8110 }
8111 return(0);
8112}
8113
8114/**
8115 * xmlXPathNextPreceding:
8116 * @ctxt: the XPath Parser context
8117 * @cur: the current node in the traversal
8118 *
8119 * Traversal function for the "preceding" direction
8120 * the preceding axis contains all nodes in the same document as the context
8121 * node that are before the context node in document order, excluding any
8122 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8123 * ordered in reverse document order
8124 *
8125 * Returns the next element following that axis
8126 */
8127xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008128xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8129{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008130 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008131 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008132 cur = ctxt->context->node;
8133 if (cur == NULL)
8134 return (NULL);
8135 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8136 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008137 do {
8138 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008139 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8140 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008141 }
8142
8143 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008144 if (cur == NULL)
8145 return (NULL);
8146 if (cur == ctxt->context->doc->children)
8147 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008148 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008149 return (cur);
8150}
8151
8152/**
8153 * xmlXPathNextPrecedingInternal:
8154 * @ctxt: the XPath Parser context
8155 * @cur: the current node in the traversal
8156 *
8157 * Traversal function for the "preceding" direction
8158 * the preceding axis contains all nodes in the same document as the context
8159 * node that are before the context node in document order, excluding any
8160 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8161 * ordered in reverse document order
8162 * This is a faster implementation but internal only since it requires a
8163 * state kept in the parser context: ctxt->ancestor.
8164 *
8165 * Returns the next element following that axis
8166 */
8167static xmlNodePtr
8168xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8169 xmlNodePtr cur)
8170{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008171 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008172 if (cur == NULL) {
8173 cur = ctxt->context->node;
8174 if (cur == NULL)
8175 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008176 if (cur->type == XML_NAMESPACE_DECL)
8177 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008178 ctxt->ancestor = cur->parent;
8179 }
8180 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8181 cur = cur->prev;
8182 while (cur->prev == NULL) {
8183 cur = cur->parent;
8184 if (cur == NULL)
8185 return (NULL);
8186 if (cur == ctxt->context->doc->children)
8187 return (NULL);
8188 if (cur != ctxt->ancestor)
8189 return (cur);
8190 ctxt->ancestor = cur->parent;
8191 }
8192 cur = cur->prev;
8193 while (cur->last != NULL)
8194 cur = cur->last;
8195 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008196}
8197
8198/**
8199 * xmlXPathNextNamespace:
8200 * @ctxt: the XPath Parser context
8201 * @cur: the current attribute in the traversal
8202 *
8203 * Traversal function for the "namespace" direction
8204 * the namespace axis contains the namespace nodes of the context node;
8205 * the order of nodes on this axis is implementation-defined; the axis will
8206 * be empty unless the context node is an element
8207 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008208 * We keep the XML namespace node at the end of the list.
8209 *
Owen Taylor3473f882001-02-23 17:55:21 +00008210 * Returns the next element following that axis
8211 */
8212xmlNodePtr
8213xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008214 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008215 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008216 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008217 if (ctxt->context->tmpNsList != NULL)
8218 xmlFree(ctxt->context->tmpNsList);
8219 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008220 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008221 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008222 if (ctxt->context->tmpNsList != NULL) {
8223 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8224 ctxt->context->tmpNsNr++;
8225 }
8226 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008227 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008228 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008229 if (ctxt->context->tmpNsNr > 0) {
8230 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8231 } else {
8232 if (ctxt->context->tmpNsList != NULL)
8233 xmlFree(ctxt->context->tmpNsList);
8234 ctxt->context->tmpNsList = NULL;
8235 return(NULL);
8236 }
Owen Taylor3473f882001-02-23 17:55:21 +00008237}
8238
8239/**
8240 * xmlXPathNextAttribute:
8241 * @ctxt: the XPath Parser context
8242 * @cur: the current attribute in the traversal
8243 *
8244 * Traversal function for the "attribute" direction
8245 * TODO: support DTD inherited default attributes
8246 *
8247 * Returns the next element following that axis
8248 */
8249xmlNodePtr
8250xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008251 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008252 if (ctxt->context->node == NULL)
8253 return(NULL);
8254 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8255 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008256 if (cur == NULL) {
8257 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8258 return(NULL);
8259 return((xmlNodePtr)ctxt->context->node->properties);
8260 }
8261 return((xmlNodePtr)cur->next);
8262}
8263
8264/************************************************************************
8265 * *
8266 * NodeTest Functions *
8267 * *
8268 ************************************************************************/
8269
Owen Taylor3473f882001-02-23 17:55:21 +00008270#define IS_FUNCTION 200
8271
Owen Taylor3473f882001-02-23 17:55:21 +00008272
8273/************************************************************************
8274 * *
8275 * Implicit tree core function library *
8276 * *
8277 ************************************************************************/
8278
8279/**
8280 * xmlXPathRoot:
8281 * @ctxt: the XPath Parser context
8282 *
8283 * Initialize the context to the root of the document
8284 */
8285void
8286xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008287 if ((ctxt == NULL) || (ctxt->context == NULL))
8288 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008289 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008290 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8291 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008292}
8293
8294/************************************************************************
8295 * *
8296 * The explicit core function library *
8297 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8298 * *
8299 ************************************************************************/
8300
8301
8302/**
8303 * xmlXPathLastFunction:
8304 * @ctxt: the XPath Parser context
8305 * @nargs: the number of arguments
8306 *
8307 * Implement the last() XPath function
8308 * number last()
8309 * The last function returns the number of nodes in the context node list.
8310 */
8311void
8312xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8313 CHECK_ARITY(0);
8314 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008315 valuePush(ctxt,
8316 xmlXPathCacheNewFloat(ctxt->context,
8317 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008318#ifdef DEBUG_EXPR
8319 xmlGenericError(xmlGenericErrorContext,
8320 "last() : %d\n", ctxt->context->contextSize);
8321#endif
8322 } else {
8323 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8324 }
8325}
8326
8327/**
8328 * xmlXPathPositionFunction:
8329 * @ctxt: the XPath Parser context
8330 * @nargs: the number of arguments
8331 *
8332 * Implement the position() XPath function
8333 * number position()
8334 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008335 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008336 * will be equal to last().
8337 */
8338void
8339xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8340 CHECK_ARITY(0);
8341 if (ctxt->context->proximityPosition >= 0) {
8342 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008343 xmlXPathCacheNewFloat(ctxt->context,
8344 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008345#ifdef DEBUG_EXPR
8346 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8347 ctxt->context->proximityPosition);
8348#endif
8349 } else {
8350 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8351 }
8352}
8353
8354/**
8355 * xmlXPathCountFunction:
8356 * @ctxt: the XPath Parser context
8357 * @nargs: the number of arguments
8358 *
8359 * Implement the count() XPath function
8360 * number count(node-set)
8361 */
8362void
8363xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8364 xmlXPathObjectPtr cur;
8365
8366 CHECK_ARITY(1);
8367 if ((ctxt->value == NULL) ||
8368 ((ctxt->value->type != XPATH_NODESET) &&
8369 (ctxt->value->type != XPATH_XSLT_TREE)))
8370 XP_ERROR(XPATH_INVALID_TYPE);
8371 cur = valuePop(ctxt);
8372
Daniel Veillard911f49a2001-04-07 15:39:35 +00008373 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008374 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008375 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008376 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8377 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008378 } else {
8379 if ((cur->nodesetval->nodeNr != 1) ||
8380 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008381 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008382 } else {
8383 xmlNodePtr tmp;
8384 int i = 0;
8385
8386 tmp = cur->nodesetval->nodeTab[0];
8387 if (tmp != NULL) {
8388 tmp = tmp->children;
8389 while (tmp != NULL) {
8390 tmp = tmp->next;
8391 i++;
8392 }
8393 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008394 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008395 }
8396 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008397 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008398}
8399
8400/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008401 * xmlXPathGetElementsByIds:
8402 * @doc: the document
8403 * @ids: a whitespace separated list of IDs
8404 *
8405 * Selects elements by their unique ID.
8406 *
8407 * Returns a node-set of selected elements.
8408 */
8409static xmlNodeSetPtr
8410xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8411 xmlNodeSetPtr ret;
8412 const xmlChar *cur = ids;
8413 xmlChar *ID;
8414 xmlAttrPtr attr;
8415 xmlNodePtr elem = NULL;
8416
Daniel Veillard7a985a12003-07-06 17:57:42 +00008417 if (ids == NULL) return(NULL);
8418
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008419 ret = xmlXPathNodeSetCreate(NULL);
8420
William M. Brack76e95df2003-10-18 16:20:14 +00008421 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008422 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008423 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008424 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008425
8426 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008427 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008428 /*
8429 * We used to check the fact that the value passed
8430 * was an NCName, but this generated much troubles for
8431 * me and Aleksey Sanin, people blatantly violated that
8432 * constaint, like Visa3D spec.
8433 * if (xmlValidateNCName(ID, 1) == 0)
8434 */
8435 attr = xmlGetID(doc, ID);
8436 if (attr != NULL) {
8437 if (attr->type == XML_ATTRIBUTE_NODE)
8438 elem = attr->parent;
8439 else if (attr->type == XML_ELEMENT_NODE)
8440 elem = (xmlNodePtr) attr;
8441 else
8442 elem = NULL;
8443 if (elem != NULL)
8444 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008445 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008446 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008447 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008448
William M. Brack76e95df2003-10-18 16:20:14 +00008449 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008450 ids = cur;
8451 }
8452 return(ret);
8453}
8454
8455/**
Owen Taylor3473f882001-02-23 17:55:21 +00008456 * xmlXPathIdFunction:
8457 * @ctxt: the XPath Parser context
8458 * @nargs: the number of arguments
8459 *
8460 * Implement the id() XPath function
8461 * node-set id(object)
8462 * The id function selects elements by their unique ID
8463 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8464 * then the result is the union of the result of applying id to the
8465 * string value of each of the nodes in the argument node-set. When the
8466 * argument to id is of any other type, the argument is converted to a
8467 * string as if by a call to the string function; the string is split
8468 * into a whitespace-separated list of tokens (whitespace is any sequence
8469 * of characters matching the production S); the result is a node-set
8470 * containing the elements in the same document as the context node that
8471 * have a unique ID equal to any of the tokens in the list.
8472 */
8473void
8474xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008475 xmlChar *tokens;
8476 xmlNodeSetPtr ret;
8477 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008478
8479 CHECK_ARITY(1);
8480 obj = valuePop(ctxt);
8481 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008482 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008483 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008484 int i;
8485
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008486 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008487
Daniel Veillard911f49a2001-04-07 15:39:35 +00008488 if (obj->nodesetval != NULL) {
8489 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008490 tokens =
8491 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8492 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8493 ret = xmlXPathNodeSetMerge(ret, ns);
8494 xmlXPathFreeNodeSet(ns);
8495 if (tokens != NULL)
8496 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008497 }
Owen Taylor3473f882001-02-23 17:55:21 +00008498 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008499 xmlXPathReleaseObject(ctxt->context, obj);
8500 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008501 return;
8502 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008503 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008504 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008505 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8506 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008507 return;
8508}
8509
8510/**
8511 * xmlXPathLocalNameFunction:
8512 * @ctxt: the XPath Parser context
8513 * @nargs: the number of arguments
8514 *
8515 * Implement the local-name() XPath function
8516 * string local-name(node-set?)
8517 * The local-name function returns a string containing the local part
8518 * of the name of the node in the argument node-set that is first in
8519 * document order. If the node-set is empty or the first node has no
8520 * name, an empty string is returned. If the argument is omitted it
8521 * defaults to the context node.
8522 */
8523void
8524xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8525 xmlXPathObjectPtr cur;
8526
Daniel Veillarda82b1822004-11-08 16:24:57 +00008527 if (ctxt == NULL) return;
8528
Owen Taylor3473f882001-02-23 17:55:21 +00008529 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008530 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8531 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008532 nargs = 1;
8533 }
8534
8535 CHECK_ARITY(1);
8536 if ((ctxt->value == NULL) ||
8537 ((ctxt->value->type != XPATH_NODESET) &&
8538 (ctxt->value->type != XPATH_XSLT_TREE)))
8539 XP_ERROR(XPATH_INVALID_TYPE);
8540 cur = valuePop(ctxt);
8541
Daniel Veillard911f49a2001-04-07 15:39:35 +00008542 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008543 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008544 } else {
8545 int i = 0; /* Should be first in document order !!!!! */
8546 switch (cur->nodesetval->nodeTab[i]->type) {
8547 case XML_ELEMENT_NODE:
8548 case XML_ATTRIBUTE_NODE:
8549 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008550 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008551 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008552 else
8553 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008554 xmlXPathCacheNewString(ctxt->context,
8555 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008556 break;
8557 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008558 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008559 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8560 break;
8561 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008562 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008563 }
8564 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008565 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008566}
8567
8568/**
8569 * xmlXPathNamespaceURIFunction:
8570 * @ctxt: the XPath Parser context
8571 * @nargs: the number of arguments
8572 *
8573 * Implement the namespace-uri() XPath function
8574 * string namespace-uri(node-set?)
8575 * The namespace-uri function returns a string containing the
8576 * namespace URI of the expanded name of the node in the argument
8577 * node-set that is first in document order. If the node-set is empty,
8578 * the first node has no name, or the expanded name has no namespace
8579 * URI, an empty string is returned. If the argument is omitted it
8580 * defaults to the context node.
8581 */
8582void
8583xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8584 xmlXPathObjectPtr cur;
8585
Daniel Veillarda82b1822004-11-08 16:24:57 +00008586 if (ctxt == NULL) return;
8587
Owen Taylor3473f882001-02-23 17:55:21 +00008588 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008589 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8590 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008591 nargs = 1;
8592 }
8593 CHECK_ARITY(1);
8594 if ((ctxt->value == NULL) ||
8595 ((ctxt->value->type != XPATH_NODESET) &&
8596 (ctxt->value->type != XPATH_XSLT_TREE)))
8597 XP_ERROR(XPATH_INVALID_TYPE);
8598 cur = valuePop(ctxt);
8599
Daniel Veillard911f49a2001-04-07 15:39:35 +00008600 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008601 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008602 } else {
8603 int i = 0; /* Should be first in document order !!!!! */
8604 switch (cur->nodesetval->nodeTab[i]->type) {
8605 case XML_ELEMENT_NODE:
8606 case XML_ATTRIBUTE_NODE:
8607 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008608 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008609 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008610 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008611 cur->nodesetval->nodeTab[i]->ns->href));
8612 break;
8613 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008614 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008615 }
8616 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008617 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008618}
8619
8620/**
8621 * xmlXPathNameFunction:
8622 * @ctxt: the XPath Parser context
8623 * @nargs: the number of arguments
8624 *
8625 * Implement the name() XPath function
8626 * string name(node-set?)
8627 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008628 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008629 * order. The QName must represent the name with respect to the namespace
8630 * declarations in effect on the node whose name is being represented.
8631 * Typically, this will be the form in which the name occurred in the XML
8632 * source. This need not be the case if there are namespace declarations
8633 * in effect on the node that associate multiple prefixes with the same
8634 * namespace. However, an implementation may include information about
8635 * the original prefix in its representation of nodes; in this case, an
8636 * implementation can ensure that the returned string is always the same
8637 * as the QName used in the XML source. If the argument it omitted it
8638 * defaults to the context node.
8639 * Libxml keep the original prefix so the "real qualified name" used is
8640 * returned.
8641 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008642static void
Daniel Veillard04383752001-07-08 14:27:15 +00008643xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8644{
Owen Taylor3473f882001-02-23 17:55:21 +00008645 xmlXPathObjectPtr cur;
8646
8647 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008648 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8649 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008650 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008651 }
8652
8653 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008654 if ((ctxt->value == NULL) ||
8655 ((ctxt->value->type != XPATH_NODESET) &&
8656 (ctxt->value->type != XPATH_XSLT_TREE)))
8657 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008658 cur = valuePop(ctxt);
8659
Daniel Veillard911f49a2001-04-07 15:39:35 +00008660 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008661 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008662 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008663 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008664
Daniel Veillard04383752001-07-08 14:27:15 +00008665 switch (cur->nodesetval->nodeTab[i]->type) {
8666 case XML_ELEMENT_NODE:
8667 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008668 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008669 valuePush(ctxt,
8670 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008671 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8672 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008673 valuePush(ctxt,
8674 xmlXPathCacheNewString(ctxt->context,
8675 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008676 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008677 xmlChar *fullname;
8678
8679 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8680 cur->nodesetval->nodeTab[i]->ns->prefix,
8681 NULL, 0);
8682 if (fullname == cur->nodesetval->nodeTab[i]->name)
8683 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8684 if (fullname == NULL) {
8685 XP_ERROR(XPATH_MEMORY_ERROR);
8686 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008687 valuePush(ctxt, xmlXPathCacheWrapString(
8688 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008689 }
8690 break;
8691 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008692 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8693 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008694 xmlXPathLocalNameFunction(ctxt, 1);
8695 }
Owen Taylor3473f882001-02-23 17:55:21 +00008696 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008697 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008698}
8699
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008700
8701/**
Owen Taylor3473f882001-02-23 17:55:21 +00008702 * xmlXPathStringFunction:
8703 * @ctxt: the XPath Parser context
8704 * @nargs: the number of arguments
8705 *
8706 * Implement the string() XPath function
8707 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008708 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008709 * - A node-set is converted to a string by returning the value of
8710 * the node in the node-set that is first in document order.
8711 * If the node-set is empty, an empty string is returned.
8712 * - A number is converted to a string as follows
8713 * + NaN is converted to the string NaN
8714 * + positive zero is converted to the string 0
8715 * + negative zero is converted to the string 0
8716 * + positive infinity is converted to the string Infinity
8717 * + negative infinity is converted to the string -Infinity
8718 * + if the number is an integer, the number is represented in
8719 * decimal form as a Number with no decimal point and no leading
8720 * zeros, preceded by a minus sign (-) if the number is negative
8721 * + otherwise, the number is represented in decimal form as a
8722 * Number including a decimal point with at least one digit
8723 * before the decimal point and at least one digit after the
8724 * decimal point, preceded by a minus sign (-) if the number
8725 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008726 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008727 * before the decimal point; beyond the one required digit
8728 * after the decimal point there must be as many, but only as
8729 * many, more digits as are needed to uniquely distinguish the
8730 * number from all other IEEE 754 numeric values.
8731 * - The boolean false value is converted to the string false.
8732 * The boolean true value is converted to the string true.
8733 *
8734 * If the argument is omitted, it defaults to a node-set with the
8735 * context node as its only member.
8736 */
8737void
8738xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8739 xmlXPathObjectPtr cur;
8740
Daniel Veillarda82b1822004-11-08 16:24:57 +00008741 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008742 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008743 valuePush(ctxt,
8744 xmlXPathCacheWrapString(ctxt->context,
8745 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008746 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008747 }
8748
8749 CHECK_ARITY(1);
8750 cur = valuePop(ctxt);
8751 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008752 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008753}
8754
8755/**
8756 * xmlXPathStringLengthFunction:
8757 * @ctxt: the XPath Parser context
8758 * @nargs: the number of arguments
8759 *
8760 * Implement the string-length() XPath function
8761 * number string-length(string?)
8762 * The string-length returns the number of characters in the string
8763 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8764 * the context node converted to a string, in other words the value
8765 * of the context node.
8766 */
8767void
8768xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8769 xmlXPathObjectPtr cur;
8770
8771 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008772 if ((ctxt == NULL) || (ctxt->context == NULL))
8773 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008774 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008775 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008776 } else {
8777 xmlChar *content;
8778
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008779 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008780 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8781 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008782 xmlFree(content);
8783 }
8784 return;
8785 }
8786 CHECK_ARITY(1);
8787 CAST_TO_STRING;
8788 CHECK_TYPE(XPATH_STRING);
8789 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8791 xmlUTF8Strlen(cur->stringval)));
8792 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008793}
8794
8795/**
8796 * xmlXPathConcatFunction:
8797 * @ctxt: the XPath Parser context
8798 * @nargs: the number of arguments
8799 *
8800 * Implement the concat() XPath function
8801 * string concat(string, string, string*)
8802 * The concat function returns the concatenation of its arguments.
8803 */
8804void
8805xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8806 xmlXPathObjectPtr cur, newobj;
8807 xmlChar *tmp;
8808
Daniel Veillarda82b1822004-11-08 16:24:57 +00008809 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008810 if (nargs < 2) {
8811 CHECK_ARITY(2);
8812 }
8813
8814 CAST_TO_STRING;
8815 cur = valuePop(ctxt);
8816 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008817 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008818 return;
8819 }
8820 nargs--;
8821
8822 while (nargs > 0) {
8823 CAST_TO_STRING;
8824 newobj = valuePop(ctxt);
8825 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008826 xmlXPathReleaseObject(ctxt->context, newobj);
8827 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008828 XP_ERROR(XPATH_INVALID_TYPE);
8829 }
8830 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8831 newobj->stringval = cur->stringval;
8832 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008833 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008834 nargs--;
8835 }
8836 valuePush(ctxt, cur);
8837}
8838
8839/**
8840 * xmlXPathContainsFunction:
8841 * @ctxt: the XPath Parser context
8842 * @nargs: the number of arguments
8843 *
8844 * Implement the contains() XPath function
8845 * boolean contains(string, string)
8846 * The contains function returns true if the first argument string
8847 * contains the second argument string, and otherwise returns false.
8848 */
8849void
8850xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8851 xmlXPathObjectPtr hay, needle;
8852
8853 CHECK_ARITY(2);
8854 CAST_TO_STRING;
8855 CHECK_TYPE(XPATH_STRING);
8856 needle = valuePop(ctxt);
8857 CAST_TO_STRING;
8858 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008859
Owen Taylor3473f882001-02-23 17:55:21 +00008860 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008861 xmlXPathReleaseObject(ctxt->context, hay);
8862 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008863 XP_ERROR(XPATH_INVALID_TYPE);
8864 }
8865 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008866 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008867 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008868 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8869 xmlXPathReleaseObject(ctxt->context, hay);
8870 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008871}
8872
8873/**
8874 * xmlXPathStartsWithFunction:
8875 * @ctxt: the XPath Parser context
8876 * @nargs: the number of arguments
8877 *
8878 * Implement the starts-with() XPath function
8879 * boolean starts-with(string, string)
8880 * The starts-with function returns true if the first argument string
8881 * starts with the second argument string, and otherwise returns false.
8882 */
8883void
8884xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8885 xmlXPathObjectPtr hay, needle;
8886 int n;
8887
8888 CHECK_ARITY(2);
8889 CAST_TO_STRING;
8890 CHECK_TYPE(XPATH_STRING);
8891 needle = valuePop(ctxt);
8892 CAST_TO_STRING;
8893 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008894
Owen Taylor3473f882001-02-23 17:55:21 +00008895 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008896 xmlXPathReleaseObject(ctxt->context, hay);
8897 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008898 XP_ERROR(XPATH_INVALID_TYPE);
8899 }
8900 n = xmlStrlen(needle->stringval);
8901 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008902 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008903 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008904 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8905 xmlXPathReleaseObject(ctxt->context, hay);
8906 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008907}
8908
8909/**
8910 * xmlXPathSubstringFunction:
8911 * @ctxt: the XPath Parser context
8912 * @nargs: the number of arguments
8913 *
8914 * Implement the substring() XPath function
8915 * string substring(string, number, number?)
8916 * The substring function returns the substring of the first argument
8917 * starting at the position specified in the second argument with
8918 * length specified in the third argument. For example,
8919 * substring("12345",2,3) returns "234". If the third argument is not
8920 * specified, it returns the substring starting at the position specified
8921 * in the second argument and continuing to the end of the string. For
8922 * example, substring("12345",2) returns "2345". More precisely, each
8923 * character in the string (see [3.6 Strings]) is considered to have a
8924 * numeric position: the position of the first character is 1, the position
8925 * of the second character is 2 and so on. The returned substring contains
8926 * those characters for which the position of the character is greater than
8927 * or equal to the second argument and, if the third argument is specified,
8928 * less than the sum of the second and third arguments; the comparisons
8929 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8930 * - substring("12345", 1.5, 2.6) returns "234"
8931 * - substring("12345", 0, 3) returns "12"
8932 * - substring("12345", 0 div 0, 3) returns ""
8933 * - substring("12345", 1, 0 div 0) returns ""
8934 * - substring("12345", -42, 1 div 0) returns "12345"
8935 * - substring("12345", -1 div 0, 1 div 0) returns ""
8936 */
8937void
8938xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008940 double le=0, in;
8941 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008942 xmlChar *ret;
8943
Owen Taylor3473f882001-02-23 17:55:21 +00008944 if (nargs < 2) {
8945 CHECK_ARITY(2);
8946 }
8947 if (nargs > 3) {
8948 CHECK_ARITY(3);
8949 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008950 /*
8951 * take care of possible last (position) argument
8952 */
Owen Taylor3473f882001-02-23 17:55:21 +00008953 if (nargs == 3) {
8954 CAST_TO_NUMBER;
8955 CHECK_TYPE(XPATH_NUMBER);
8956 len = valuePop(ctxt);
8957 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008958 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008959 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008960
Owen Taylor3473f882001-02-23 17:55:21 +00008961 CAST_TO_NUMBER;
8962 CHECK_TYPE(XPATH_NUMBER);
8963 start = valuePop(ctxt);
8964 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008965 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008966 CAST_TO_STRING;
8967 CHECK_TYPE(XPATH_STRING);
8968 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008969 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008970
Daniel Veillard97ac1312001-05-30 19:14:17 +00008971 /*
8972 * If last pos not present, calculate last position
8973 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008974 if (nargs != 3) {
8975 le = (double)m;
8976 if (in < 1.0)
8977 in = 1.0;
8978 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008979
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008980 /* Need to check for the special cases where either
8981 * the index is NaN, the length is NaN, or both
8982 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008983 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008984 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008985 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008986 * To meet the requirements of the spec, the arguments
8987 * must be converted to integer format before
8988 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008989 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008990 * First we go to integer form, rounding up
8991 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008992 */
8993 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008994 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008995
Daniel Veillard9e412302002-06-10 15:59:44 +00008996 if (xmlXPathIsInf(le) == 1) {
8997 l = m;
8998 if (i < 1)
8999 i = 1;
9000 }
9001 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9002 l = 0;
9003 else {
9004 l = (int) le;
9005 if (((double)l)+0.5 <= le) l++;
9006 }
9007
9008 /* Now we normalize inidices */
9009 i -= 1;
9010 l += i;
9011 if (i < 0)
9012 i = 0;
9013 if (l > m)
9014 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009015
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009016 /* number of chars to copy */
9017 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009018
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009019 ret = xmlUTF8Strsub(str->stringval, i, l);
9020 }
9021 else {
9022 ret = NULL;
9023 }
Owen Taylor3473f882001-02-23 17:55:21 +00009024 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009025 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009026 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009027 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009028 xmlFree(ret);
9029 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009030 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009031}
9032
9033/**
9034 * xmlXPathSubstringBeforeFunction:
9035 * @ctxt: the XPath Parser context
9036 * @nargs: the number of arguments
9037 *
9038 * Implement the substring-before() XPath function
9039 * string substring-before(string, string)
9040 * The substring-before function returns the substring of the first
9041 * argument string that precedes the first occurrence of the second
9042 * argument string in the first argument string, or the empty string
9043 * if the first argument string does not contain the second argument
9044 * string. For example, substring-before("1999/04/01","/") returns 1999.
9045 */
9046void
9047xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9048 xmlXPathObjectPtr str;
9049 xmlXPathObjectPtr find;
9050 xmlBufferPtr target;
9051 const xmlChar *point;
9052 int offset;
9053
9054 CHECK_ARITY(2);
9055 CAST_TO_STRING;
9056 find = valuePop(ctxt);
9057 CAST_TO_STRING;
9058 str = valuePop(ctxt);
9059
9060 target = xmlBufferCreate();
9061 if (target) {
9062 point = xmlStrstr(str->stringval, find->stringval);
9063 if (point) {
9064 offset = (int)(point - str->stringval);
9065 xmlBufferAdd(target, str->stringval, offset);
9066 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009067 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9068 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009069 xmlBufferFree(target);
9070 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009071 xmlXPathReleaseObject(ctxt->context, str);
9072 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009073}
9074
9075/**
9076 * xmlXPathSubstringAfterFunction:
9077 * @ctxt: the XPath Parser context
9078 * @nargs: the number of arguments
9079 *
9080 * Implement the substring-after() XPath function
9081 * string substring-after(string, string)
9082 * The substring-after function returns the substring of the first
9083 * argument string that follows the first occurrence of the second
9084 * argument string in the first argument string, or the empty stringi
9085 * if the first argument string does not contain the second argument
9086 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9087 * and substring-after("1999/04/01","19") returns 99/04/01.
9088 */
9089void
9090xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9091 xmlXPathObjectPtr str;
9092 xmlXPathObjectPtr find;
9093 xmlBufferPtr target;
9094 const xmlChar *point;
9095 int offset;
9096
9097 CHECK_ARITY(2);
9098 CAST_TO_STRING;
9099 find = valuePop(ctxt);
9100 CAST_TO_STRING;
9101 str = valuePop(ctxt);
9102
9103 target = xmlBufferCreate();
9104 if (target) {
9105 point = xmlStrstr(str->stringval, find->stringval);
9106 if (point) {
9107 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9108 xmlBufferAdd(target, &str->stringval[offset],
9109 xmlStrlen(str->stringval) - offset);
9110 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009111 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9112 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009113 xmlBufferFree(target);
9114 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009115 xmlXPathReleaseObject(ctxt->context, str);
9116 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009117}
9118
9119/**
9120 * xmlXPathNormalizeFunction:
9121 * @ctxt: the XPath Parser context
9122 * @nargs: the number of arguments
9123 *
9124 * Implement the normalize-space() XPath function
9125 * string normalize-space(string?)
9126 * The normalize-space function returns the argument string with white
9127 * space normalized by stripping leading and trailing whitespace
9128 * and replacing sequences of whitespace characters by a single
9129 * space. Whitespace characters are the same allowed by the S production
9130 * in XML. If the argument is omitted, it defaults to the context
9131 * node converted to a string, in other words the value of the context node.
9132 */
9133void
9134xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9135 xmlXPathObjectPtr obj = NULL;
9136 xmlChar *source = NULL;
9137 xmlBufferPtr target;
9138 xmlChar blank;
9139
Daniel Veillarda82b1822004-11-08 16:24:57 +00009140 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009141 if (nargs == 0) {
9142 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009143 valuePush(ctxt,
9144 xmlXPathCacheWrapString(ctxt->context,
9145 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009146 nargs = 1;
9147 }
9148
9149 CHECK_ARITY(1);
9150 CAST_TO_STRING;
9151 CHECK_TYPE(XPATH_STRING);
9152 obj = valuePop(ctxt);
9153 source = obj->stringval;
9154
9155 target = xmlBufferCreate();
9156 if (target && source) {
9157
9158 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009159 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009160 source++;
9161
9162 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9163 blank = 0;
9164 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009165 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009166 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009167 } else {
9168 if (blank) {
9169 xmlBufferAdd(target, &blank, 1);
9170 blank = 0;
9171 }
9172 xmlBufferAdd(target, source, 1);
9173 }
9174 source++;
9175 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009176 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9177 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009178 xmlBufferFree(target);
9179 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009180 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009181}
9182
9183/**
9184 * xmlXPathTranslateFunction:
9185 * @ctxt: the XPath Parser context
9186 * @nargs: the number of arguments
9187 *
9188 * Implement the translate() XPath function
9189 * string translate(string, string, string)
9190 * The translate function returns the first argument string with
9191 * occurrences of characters in the second argument string replaced
9192 * by the character at the corresponding position in the third argument
9193 * string. For example, translate("bar","abc","ABC") returns the string
9194 * BAr. If there is a character in the second argument string with no
9195 * character at a corresponding position in the third argument string
9196 * (because the second argument string is longer than the third argument
9197 * string), then occurrences of that character in the first argument
9198 * string are removed. For example, translate("--aaa--","abc-","ABC")
9199 * returns "AAA". If a character occurs more than once in second
9200 * argument string, then the first occurrence determines the replacement
9201 * character. If the third argument string is longer than the second
9202 * argument string, then excess characters are ignored.
9203 */
9204void
9205xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009206 xmlXPathObjectPtr str;
9207 xmlXPathObjectPtr from;
9208 xmlXPathObjectPtr to;
9209 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009210 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009211 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009212 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009213 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009214
Daniel Veillarde043ee12001-04-16 14:08:07 +00009215 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009216
Daniel Veillarde043ee12001-04-16 14:08:07 +00009217 CAST_TO_STRING;
9218 to = valuePop(ctxt);
9219 CAST_TO_STRING;
9220 from = valuePop(ctxt);
9221 CAST_TO_STRING;
9222 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009223
Daniel Veillarde043ee12001-04-16 14:08:07 +00009224 target = xmlBufferCreate();
9225 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009226 max = xmlUTF8Strlen(to->stringval);
9227 for (cptr = str->stringval; (ch=*cptr); ) {
9228 offset = xmlUTF8Strloc(from->stringval, cptr);
9229 if (offset >= 0) {
9230 if (offset < max) {
9231 point = xmlUTF8Strpos(to->stringval, offset);
9232 if (point)
9233 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9234 }
9235 } else
9236 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9237
9238 /* Step to next character in input */
9239 cptr++;
9240 if ( ch & 0x80 ) {
9241 /* if not simple ascii, verify proper format */
9242 if ( (ch & 0xc0) != 0xc0 ) {
9243 xmlGenericError(xmlGenericErrorContext,
9244 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9245 break;
9246 }
9247 /* then skip over remaining bytes for this char */
9248 while ( (ch <<= 1) & 0x80 )
9249 if ( (*cptr++ & 0xc0) != 0x80 ) {
9250 xmlGenericError(xmlGenericErrorContext,
9251 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9252 break;
9253 }
9254 if (ch & 0x80) /* must have had error encountered */
9255 break;
9256 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009257 }
Owen Taylor3473f882001-02-23 17:55:21 +00009258 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009259 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9260 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009261 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009262 xmlXPathReleaseObject(ctxt->context, str);
9263 xmlXPathReleaseObject(ctxt->context, from);
9264 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009265}
9266
9267/**
9268 * xmlXPathBooleanFunction:
9269 * @ctxt: the XPath Parser context
9270 * @nargs: the number of arguments
9271 *
9272 * Implement the boolean() XPath function
9273 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009274 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009275 * - a number is true if and only if it is neither positive or
9276 * negative zero nor NaN
9277 * - a node-set is true if and only if it is non-empty
9278 * - a string is true if and only if its length is non-zero
9279 */
9280void
9281xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9282 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009283
9284 CHECK_ARITY(1);
9285 cur = valuePop(ctxt);
9286 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009287 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009288 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009289}
9290
9291/**
9292 * xmlXPathNotFunction:
9293 * @ctxt: the XPath Parser context
9294 * @nargs: the number of arguments
9295 *
9296 * Implement the not() XPath function
9297 * boolean not(boolean)
9298 * The not function returns true if its argument is false,
9299 * and false otherwise.
9300 */
9301void
9302xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9303 CHECK_ARITY(1);
9304 CAST_TO_BOOLEAN;
9305 CHECK_TYPE(XPATH_BOOLEAN);
9306 ctxt->value->boolval = ! ctxt->value->boolval;
9307}
9308
9309/**
9310 * xmlXPathTrueFunction:
9311 * @ctxt: the XPath Parser context
9312 * @nargs: the number of arguments
9313 *
9314 * Implement the true() XPath function
9315 * boolean true()
9316 */
9317void
9318xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9319 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009320 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009321}
9322
9323/**
9324 * xmlXPathFalseFunction:
9325 * @ctxt: the XPath Parser context
9326 * @nargs: the number of arguments
9327 *
9328 * Implement the false() XPath function
9329 * boolean false()
9330 */
9331void
9332xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9333 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009334 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009335}
9336
9337/**
9338 * xmlXPathLangFunction:
9339 * @ctxt: the XPath Parser context
9340 * @nargs: the number of arguments
9341 *
9342 * Implement the lang() XPath function
9343 * boolean lang(string)
9344 * The lang function returns true or false depending on whether the
9345 * language of the context node as specified by xml:lang attributes
9346 * is the same as or is a sublanguage of the language specified by
9347 * the argument string. The language of the context node is determined
9348 * by the value of the xml:lang attribute on the context node, or, if
9349 * the context node has no xml:lang attribute, by the value of the
9350 * xml:lang attribute on the nearest ancestor of the context node that
9351 * has an xml:lang attribute. If there is no such attribute, then lang
9352 * returns false. If there is such an attribute, then lang returns
9353 * true if the attribute value is equal to the argument ignoring case,
9354 * or if there is some suffix starting with - such that the attribute
9355 * value is equal to the argument ignoring that suffix of the attribute
9356 * value and ignoring case.
9357 */
9358void
9359xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009360 xmlXPathObjectPtr val = NULL;
9361 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009362 const xmlChar *lang;
9363 int ret = 0;
9364 int i;
9365
9366 CHECK_ARITY(1);
9367 CAST_TO_STRING;
9368 CHECK_TYPE(XPATH_STRING);
9369 val = valuePop(ctxt);
9370 lang = val->stringval;
9371 theLang = xmlNodeGetLang(ctxt->context->node);
9372 if ((theLang != NULL) && (lang != NULL)) {
9373 for (i = 0;lang[i] != 0;i++)
9374 if (toupper(lang[i]) != toupper(theLang[i]))
9375 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009376 if ((theLang[i] == 0) || (theLang[i] == '-'))
9377 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009378 }
9379not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009380 if (theLang != NULL)
9381 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009382
9383 xmlXPathReleaseObject(ctxt->context, val);
9384 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009385}
9386
9387/**
9388 * xmlXPathNumberFunction:
9389 * @ctxt: the XPath Parser context
9390 * @nargs: the number of arguments
9391 *
9392 * Implement the number() XPath function
9393 * number number(object?)
9394 */
9395void
9396xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9397 xmlXPathObjectPtr cur;
9398 double res;
9399
Daniel Veillarda82b1822004-11-08 16:24:57 +00009400 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009401 if (nargs == 0) {
9402 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009403 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009404 } else {
9405 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9406
9407 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009408 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009409 xmlFree(content);
9410 }
9411 return;
9412 }
9413
9414 CHECK_ARITY(1);
9415 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009416 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009417}
9418
9419/**
9420 * xmlXPathSumFunction:
9421 * @ctxt: the XPath Parser context
9422 * @nargs: the number of arguments
9423 *
9424 * Implement the sum() XPath function
9425 * number sum(node-set)
9426 * The sum function returns the sum of the values of the nodes in
9427 * the argument node-set.
9428 */
9429void
9430xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9431 xmlXPathObjectPtr cur;
9432 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009433 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009434
9435 CHECK_ARITY(1);
9436 if ((ctxt->value == NULL) ||
9437 ((ctxt->value->type != XPATH_NODESET) &&
9438 (ctxt->value->type != XPATH_XSLT_TREE)))
9439 XP_ERROR(XPATH_INVALID_TYPE);
9440 cur = valuePop(ctxt);
9441
William M. Brack08171912003-12-29 02:52:11 +00009442 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009443 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9444 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009445 }
9446 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009447 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9448 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009449}
9450
William M. Brack3d426662005-04-19 14:40:28 +00009451/*
9452 * To assure working code on multiple platforms, we want to only depend
9453 * upon the characteristic truncation of converting a floating point value
9454 * to an integer. Unfortunately, because of the different storage sizes
9455 * of our internal floating point value (double) and integer (int), we
9456 * can't directly convert (see bug 301162). This macro is a messy
9457 * 'workaround'
9458 */
9459#define XTRUNC(f, v) \
9460 f = fmod((v), INT_MAX); \
9461 f = (v) - (f) + (double)((int)(f));
9462
Owen Taylor3473f882001-02-23 17:55:21 +00009463/**
9464 * xmlXPathFloorFunction:
9465 * @ctxt: the XPath Parser context
9466 * @nargs: the number of arguments
9467 *
9468 * Implement the floor() XPath function
9469 * number floor(number)
9470 * The floor function returns the largest (closest to positive infinity)
9471 * number that is not greater than the argument and that is an integer.
9472 */
9473void
9474xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009475 double f;
9476
Owen Taylor3473f882001-02-23 17:55:21 +00009477 CHECK_ARITY(1);
9478 CAST_TO_NUMBER;
9479 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009480
William M. Brack3d426662005-04-19 14:40:28 +00009481 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009482 if (f != ctxt->value->floatval) {
9483 if (ctxt->value->floatval > 0)
9484 ctxt->value->floatval = f;
9485 else
9486 ctxt->value->floatval = f - 1;
9487 }
Owen Taylor3473f882001-02-23 17:55:21 +00009488}
9489
9490/**
9491 * xmlXPathCeilingFunction:
9492 * @ctxt: the XPath Parser context
9493 * @nargs: the number of arguments
9494 *
9495 * Implement the ceiling() XPath function
9496 * number ceiling(number)
9497 * The ceiling function returns the smallest (closest to negative infinity)
9498 * number that is not less than the argument and that is an integer.
9499 */
9500void
9501xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9502 double f;
9503
9504 CHECK_ARITY(1);
9505 CAST_TO_NUMBER;
9506 CHECK_TYPE(XPATH_NUMBER);
9507
9508#if 0
9509 ctxt->value->floatval = ceil(ctxt->value->floatval);
9510#else
William M. Brack3d426662005-04-19 14:40:28 +00009511 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009512 if (f != ctxt->value->floatval) {
9513 if (ctxt->value->floatval > 0)
9514 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009515 else {
9516 if (ctxt->value->floatval < 0 && f == 0)
9517 ctxt->value->floatval = xmlXPathNZERO;
9518 else
9519 ctxt->value->floatval = f;
9520 }
9521
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009522 }
Owen Taylor3473f882001-02-23 17:55:21 +00009523#endif
9524}
9525
9526/**
9527 * xmlXPathRoundFunction:
9528 * @ctxt: the XPath Parser context
9529 * @nargs: the number of arguments
9530 *
9531 * Implement the round() XPath function
9532 * number round(number)
9533 * The round function returns the number that is closest to the
9534 * argument and that is an integer. If there are two such numbers,
9535 * then the one that is even is returned.
9536 */
9537void
9538xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9539 double f;
9540
9541 CHECK_ARITY(1);
9542 CAST_TO_NUMBER;
9543 CHECK_TYPE(XPATH_NUMBER);
9544
Daniel Veillardcda96922001-08-21 10:56:31 +00009545 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9546 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9547 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009548 (ctxt->value->floatval == 0.0))
9549 return;
9550
William M. Brack3d426662005-04-19 14:40:28 +00009551 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009552 if (ctxt->value->floatval < 0) {
9553 if (ctxt->value->floatval < f - 0.5)
9554 ctxt->value->floatval = f - 1;
9555 else
9556 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009557 if (ctxt->value->floatval == 0)
9558 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009559 } else {
9560 if (ctxt->value->floatval < f + 0.5)
9561 ctxt->value->floatval = f;
9562 else
9563 ctxt->value->floatval = f + 1;
9564 }
Owen Taylor3473f882001-02-23 17:55:21 +00009565}
9566
9567/************************************************************************
9568 * *
9569 * The Parser *
9570 * *
9571 ************************************************************************/
9572
9573/*
William M. Brack08171912003-12-29 02:52:11 +00009574 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009575 * implementation.
9576 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009577static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009578static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009579static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009580static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009581static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9582 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009583
9584/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009585 * xmlXPathCurrentChar:
9586 * @ctxt: the XPath parser context
9587 * @cur: pointer to the beginning of the char
9588 * @len: pointer to the length of the char read
9589 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009590 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009591 * bytes in the input buffer.
9592 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009593 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009594 */
9595
9596static int
9597xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9598 unsigned char c;
9599 unsigned int val;
9600 const xmlChar *cur;
9601
9602 if (ctxt == NULL)
9603 return(0);
9604 cur = ctxt->cur;
9605
9606 /*
9607 * We are supposed to handle UTF8, check it's valid
9608 * From rfc2044: encoding of the Unicode values on UTF-8:
9609 *
9610 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9611 * 0000 0000-0000 007F 0xxxxxxx
9612 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9613 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9614 *
9615 * Check for the 0x110000 limit too
9616 */
9617 c = *cur;
9618 if (c & 0x80) {
9619 if ((cur[1] & 0xc0) != 0x80)
9620 goto encoding_error;
9621 if ((c & 0xe0) == 0xe0) {
9622
9623 if ((cur[2] & 0xc0) != 0x80)
9624 goto encoding_error;
9625 if ((c & 0xf0) == 0xf0) {
9626 if (((c & 0xf8) != 0xf0) ||
9627 ((cur[3] & 0xc0) != 0x80))
9628 goto encoding_error;
9629 /* 4-byte code */
9630 *len = 4;
9631 val = (cur[0] & 0x7) << 18;
9632 val |= (cur[1] & 0x3f) << 12;
9633 val |= (cur[2] & 0x3f) << 6;
9634 val |= cur[3] & 0x3f;
9635 } else {
9636 /* 3-byte code */
9637 *len = 3;
9638 val = (cur[0] & 0xf) << 12;
9639 val |= (cur[1] & 0x3f) << 6;
9640 val |= cur[2] & 0x3f;
9641 }
9642 } else {
9643 /* 2-byte code */
9644 *len = 2;
9645 val = (cur[0] & 0x1f) << 6;
9646 val |= cur[1] & 0x3f;
9647 }
9648 if (!IS_CHAR(val)) {
9649 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9650 }
9651 return(val);
9652 } else {
9653 /* 1-byte code */
9654 *len = 1;
9655 return((int) *cur);
9656 }
9657encoding_error:
9658 /*
William M. Brack08171912003-12-29 02:52:11 +00009659 * If we detect an UTF8 error that probably means that the
9660 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009661 * declaration header. Report the error and switch the encoding
9662 * to ISO-Latin-1 (if you don't like this policy, just declare the
9663 * encoding !)
9664 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009665 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009666 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009667}
9668
9669/**
Owen Taylor3473f882001-02-23 17:55:21 +00009670 * xmlXPathParseNCName:
9671 * @ctxt: the XPath Parser context
9672 *
9673 * parse an XML namespace non qualified name.
9674 *
9675 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9676 *
9677 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9678 * CombiningChar | Extender
9679 *
9680 * Returns the namespace name or NULL
9681 */
9682
9683xmlChar *
9684xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009685 const xmlChar *in;
9686 xmlChar *ret;
9687 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009688
Daniel Veillarda82b1822004-11-08 16:24:57 +00009689 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009690 /*
9691 * Accelerator for simple ASCII names
9692 */
9693 in = ctxt->cur;
9694 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9695 ((*in >= 0x41) && (*in <= 0x5A)) ||
9696 (*in == '_')) {
9697 in++;
9698 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9699 ((*in >= 0x41) && (*in <= 0x5A)) ||
9700 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009701 (*in == '_') || (*in == '.') ||
9702 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009703 in++;
9704 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9705 (*in == '[') || (*in == ']') || (*in == ':') ||
9706 (*in == '@') || (*in == '*')) {
9707 count = in - ctxt->cur;
9708 if (count == 0)
9709 return(NULL);
9710 ret = xmlStrndup(ctxt->cur, count);
9711 ctxt->cur = in;
9712 return(ret);
9713 }
9714 }
9715 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009716}
9717
Daniel Veillard2156a562001-04-28 12:24:34 +00009718
Owen Taylor3473f882001-02-23 17:55:21 +00009719/**
9720 * xmlXPathParseQName:
9721 * @ctxt: the XPath Parser context
9722 * @prefix: a xmlChar **
9723 *
9724 * parse an XML qualified name
9725 *
9726 * [NS 5] QName ::= (Prefix ':')? LocalPart
9727 *
9728 * [NS 6] Prefix ::= NCName
9729 *
9730 * [NS 7] LocalPart ::= NCName
9731 *
9732 * Returns the function returns the local part, and prefix is updated
9733 * to get the Prefix if any.
9734 */
9735
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009736static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009737xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9738 xmlChar *ret = NULL;
9739
9740 *prefix = NULL;
9741 ret = xmlXPathParseNCName(ctxt);
9742 if (CUR == ':') {
9743 *prefix = ret;
9744 NEXT;
9745 ret = xmlXPathParseNCName(ctxt);
9746 }
9747 return(ret);
9748}
9749
9750/**
9751 * xmlXPathParseName:
9752 * @ctxt: the XPath Parser context
9753 *
9754 * parse an XML name
9755 *
9756 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9757 * CombiningChar | Extender
9758 *
9759 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9760 *
9761 * Returns the namespace name or NULL
9762 */
9763
9764xmlChar *
9765xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009766 const xmlChar *in;
9767 xmlChar *ret;
9768 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009769
Daniel Veillarda82b1822004-11-08 16:24:57 +00009770 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009771 /*
9772 * Accelerator for simple ASCII names
9773 */
9774 in = ctxt->cur;
9775 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9776 ((*in >= 0x41) && (*in <= 0x5A)) ||
9777 (*in == '_') || (*in == ':')) {
9778 in++;
9779 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9780 ((*in >= 0x41) && (*in <= 0x5A)) ||
9781 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009782 (*in == '_') || (*in == '-') ||
9783 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009784 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009785 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009786 count = in - ctxt->cur;
9787 ret = xmlStrndup(ctxt->cur, count);
9788 ctxt->cur = in;
9789 return(ret);
9790 }
9791 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009792 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009793}
9794
Daniel Veillard61d80a22001-04-27 17:13:01 +00009795static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009796xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009797 xmlChar buf[XML_MAX_NAMELEN + 5];
9798 int len = 0, l;
9799 int c;
9800
9801 /*
9802 * Handler for more complex cases
9803 */
9804 c = CUR_CHAR(l);
9805 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009806 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9807 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009808 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009809 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009810 return(NULL);
9811 }
9812
9813 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9814 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9815 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009816 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009817 (IS_COMBINING(c)) ||
9818 (IS_EXTENDER(c)))) {
9819 COPY_BUF(l,buf,len,c);
9820 NEXTL(l);
9821 c = CUR_CHAR(l);
9822 if (len >= XML_MAX_NAMELEN) {
9823 /*
9824 * Okay someone managed to make a huge name, so he's ready to pay
9825 * for the processing speed.
9826 */
9827 xmlChar *buffer;
9828 int max = len * 2;
9829
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009830 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009831 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009832 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009833 }
9834 memcpy(buffer, buf, len);
9835 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9836 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009837 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009838 (IS_COMBINING(c)) ||
9839 (IS_EXTENDER(c))) {
9840 if (len + 10 > max) {
9841 max *= 2;
9842 buffer = (xmlChar *) xmlRealloc(buffer,
9843 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 }
9848 COPY_BUF(l,buffer,len,c);
9849 NEXTL(l);
9850 c = CUR_CHAR(l);
9851 }
9852 buffer[len] = 0;
9853 return(buffer);
9854 }
9855 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009856 if (len == 0)
9857 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009858 return(xmlStrndup(buf, len));
9859}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009860
9861#define MAX_FRAC 20
9862
William M. Brack372a4452004-02-17 13:09:23 +00009863/*
9864 * These are used as divisors for the fractional part of a number.
9865 * Since the table includes 1.0 (representing '0' fractional digits),
9866 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9867 */
9868static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009869 1.0, 10.0, 100.0, 1000.0, 10000.0,
9870 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9871 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9872 100000000000000.0,
9873 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009874 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009875};
9876
Owen Taylor3473f882001-02-23 17:55:21 +00009877/**
9878 * xmlXPathStringEvalNumber:
9879 * @str: A string to scan
9880 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009881 * [30a] Float ::= Number ('e' Digits?)?
9882 *
Owen Taylor3473f882001-02-23 17:55:21 +00009883 * [30] Number ::= Digits ('.' Digits?)?
9884 * | '.' Digits
9885 * [31] Digits ::= [0-9]+
9886 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009887 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009888 * In complement of the Number expression, this function also handles
9889 * negative values : '-' Number.
9890 *
9891 * Returns the double value.
9892 */
9893double
9894xmlXPathStringEvalNumber(const xmlChar *str) {
9895 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009896 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009897 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009898 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009899 int exponent = 0;
9900 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009901#ifdef __GNUC__
9902 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009903 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009904#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009905 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009906 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009907 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9908 return(xmlXPathNAN);
9909 }
9910 if (*cur == '-') {
9911 isneg = 1;
9912 cur++;
9913 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009914
9915#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009916 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009917 * tmp/temp is a workaround against a gcc compiler bug
9918 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009919 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009920 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009921 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009922 ret = ret * 10;
9923 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009924 ok = 1;
9925 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009926 temp = (double) tmp;
9927 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009928 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009929#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009930 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009931 while ((*cur >= '0') && (*cur <= '9')) {
9932 ret = ret * 10 + (*cur - '0');
9933 ok = 1;
9934 cur++;
9935 }
9936#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009937
Owen Taylor3473f882001-02-23 17:55:21 +00009938 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009939 int v, frac = 0;
9940 double fraction = 0;
9941
Owen Taylor3473f882001-02-23 17:55:21 +00009942 cur++;
9943 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9944 return(xmlXPathNAN);
9945 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009946 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9947 v = (*cur - '0');
9948 fraction = fraction * 10 + v;
9949 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009950 cur++;
9951 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009952 fraction /= my_pow10[frac];
9953 ret = ret + fraction;
9954 while ((*cur >= '0') && (*cur <= '9'))
9955 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009956 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009957 if ((*cur == 'e') || (*cur == 'E')) {
9958 cur++;
9959 if (*cur == '-') {
9960 is_exponent_negative = 1;
9961 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009962 } else if (*cur == '+') {
9963 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009964 }
9965 while ((*cur >= '0') && (*cur <= '9')) {
9966 exponent = exponent * 10 + (*cur - '0');
9967 cur++;
9968 }
9969 }
William M. Brack76e95df2003-10-18 16:20:14 +00009970 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009971 if (*cur != 0) return(xmlXPathNAN);
9972 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009973 if (is_exponent_negative) exponent = -exponent;
9974 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009975 return(ret);
9976}
9977
9978/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009979 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009980 * @ctxt: the XPath Parser context
9981 *
9982 * [30] Number ::= Digits ('.' Digits?)?
9983 * | '.' Digits
9984 * [31] Digits ::= [0-9]+
9985 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009986 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009987 *
9988 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009989static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009990xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9991{
Owen Taylor3473f882001-02-23 17:55:21 +00009992 double ret = 0.0;
9993 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009994 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009995 int exponent = 0;
9996 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009997#ifdef __GNUC__
9998 unsigned long tmp = 0;
9999 double temp;
10000#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010001
10002 CHECK_ERROR;
10003 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10004 XP_ERROR(XPATH_NUMBER_ERROR);
10005 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010006#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010007 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010008 * tmp/temp is a workaround against a gcc compiler bug
10009 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010010 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010011 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010012 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010013 ret = ret * 10;
10014 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010015 ok = 1;
10016 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010017 temp = (double) tmp;
10018 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010019 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010020#else
10021 ret = 0;
10022 while ((CUR >= '0') && (CUR <= '9')) {
10023 ret = ret * 10 + (CUR - '0');
10024 ok = 1;
10025 NEXT;
10026 }
10027#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010028 if (CUR == '.') {
10029 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010030 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10031 XP_ERROR(XPATH_NUMBER_ERROR);
10032 }
10033 while ((CUR >= '0') && (CUR <= '9')) {
10034 mult /= 10;
10035 ret = ret + (CUR - '0') * mult;
10036 NEXT;
10037 }
Owen Taylor3473f882001-02-23 17:55:21 +000010038 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010039 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010040 NEXT;
10041 if (CUR == '-') {
10042 is_exponent_negative = 1;
10043 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010044 } else if (CUR == '+') {
10045 NEXT;
10046 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010047 while ((CUR >= '0') && (CUR <= '9')) {
10048 exponent = exponent * 10 + (CUR - '0');
10049 NEXT;
10050 }
10051 if (is_exponent_negative)
10052 exponent = -exponent;
10053 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010054 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010055 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010056 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010057}
10058
10059/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010060 * xmlXPathParseLiteral:
10061 * @ctxt: the XPath Parser context
10062 *
10063 * Parse a Literal
10064 *
10065 * [29] Literal ::= '"' [^"]* '"'
10066 * | "'" [^']* "'"
10067 *
10068 * Returns the value found or NULL in case of error
10069 */
10070static xmlChar *
10071xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10072 const xmlChar *q;
10073 xmlChar *ret = NULL;
10074
10075 if (CUR == '"') {
10076 NEXT;
10077 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010078 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010079 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010080 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010081 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010082 } else {
10083 ret = xmlStrndup(q, CUR_PTR - q);
10084 NEXT;
10085 }
10086 } else if (CUR == '\'') {
10087 NEXT;
10088 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010089 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010090 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010091 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010092 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010093 } else {
10094 ret = xmlStrndup(q, CUR_PTR - q);
10095 NEXT;
10096 }
10097 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010098 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010099 }
10100 return(ret);
10101}
10102
10103/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010104 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010105 * @ctxt: the XPath Parser context
10106 *
10107 * Parse a Literal and push it on the stack.
10108 *
10109 * [29] Literal ::= '"' [^"]* '"'
10110 * | "'" [^']* "'"
10111 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010112 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010113 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010114static void
10115xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010116 const xmlChar *q;
10117 xmlChar *ret = NULL;
10118
10119 if (CUR == '"') {
10120 NEXT;
10121 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010122 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010123 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010124 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010125 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10126 } else {
10127 ret = xmlStrndup(q, CUR_PTR - q);
10128 NEXT;
10129 }
10130 } else if (CUR == '\'') {
10131 NEXT;
10132 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010133 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010134 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010135 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010136 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10137 } else {
10138 ret = xmlStrndup(q, CUR_PTR - q);
10139 NEXT;
10140 }
10141 } else {
10142 XP_ERROR(XPATH_START_LITERAL_ERROR);
10143 }
10144 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010145 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010146 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010147 xmlFree(ret);
10148}
10149
10150/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010151 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010152 * @ctxt: the XPath Parser context
10153 *
10154 * Parse a VariableReference, evaluate it and push it on the stack.
10155 *
10156 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010157 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010158 * of any of the types that are possible for the value of an expression,
10159 * and may also be of additional types not specified here.
10160 *
10161 * Early evaluation is possible since:
10162 * The variable bindings [...] used to evaluate a subexpression are
10163 * always the same as those used to evaluate the containing expression.
10164 *
10165 * [36] VariableReference ::= '$' QName
10166 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010167static void
10168xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010169 xmlChar *name;
10170 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010171
10172 SKIP_BLANKS;
10173 if (CUR != '$') {
10174 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10175 }
10176 NEXT;
10177 name = xmlXPathParseQName(ctxt, &prefix);
10178 if (name == NULL) {
10179 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10180 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010181 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010182 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10183 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010184 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010185 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10186 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10187 }
Owen Taylor3473f882001-02-23 17:55:21 +000010188}
10189
10190/**
10191 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010192 * @name: a name string
10193 *
10194 * Is the name given a NodeType one.
10195 *
10196 * [38] NodeType ::= 'comment'
10197 * | 'text'
10198 * | 'processing-instruction'
10199 * | 'node'
10200 *
10201 * Returns 1 if true 0 otherwise
10202 */
10203int
10204xmlXPathIsNodeType(const xmlChar *name) {
10205 if (name == NULL)
10206 return(0);
10207
Daniel Veillard1971ee22002-01-31 20:29:19 +000010208 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010209 return(1);
10210 if (xmlStrEqual(name, BAD_CAST "text"))
10211 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010212 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010213 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010214 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010215 return(1);
10216 return(0);
10217}
10218
10219/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010220 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010221 * @ctxt: the XPath Parser context
10222 *
10223 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10224 * [17] Argument ::= Expr
10225 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010226 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010227 * pushed on the stack
10228 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010229static void
10230xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010231 xmlChar *name;
10232 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010233 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010234 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010235
10236 name = xmlXPathParseQName(ctxt, &prefix);
10237 if (name == NULL) {
10238 XP_ERROR(XPATH_EXPR_ERROR);
10239 }
10240 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010241#ifdef DEBUG_EXPR
10242 if (prefix == NULL)
10243 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10244 name);
10245 else
10246 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10247 prefix, name);
10248#endif
10249
Owen Taylor3473f882001-02-23 17:55:21 +000010250 if (CUR != '(') {
10251 XP_ERROR(XPATH_EXPR_ERROR);
10252 }
10253 NEXT;
10254 SKIP_BLANKS;
10255
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010256 /*
10257 * Optimization for count(): we don't need the node-set to be sorted.
10258 */
10259 if ((prefix == NULL) && (name[0] == 'c') &&
10260 xmlStrEqual(name, BAD_CAST "count"))
10261 {
10262 sort = 0;
10263 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010264 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010265 if (CUR != ')') {
10266 while (CUR != 0) {
10267 int op1 = ctxt->comp->last;
10268 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010269 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010270 CHECK_ERROR;
10271 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10272 nbargs++;
10273 if (CUR == ')') break;
10274 if (CUR != ',') {
10275 XP_ERROR(XPATH_EXPR_ERROR);
10276 }
10277 NEXT;
10278 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010279 }
Owen Taylor3473f882001-02-23 17:55:21 +000010280 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010281 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10282 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010283 NEXT;
10284 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010285}
10286
10287/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010288 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010289 * @ctxt: the XPath Parser context
10290 *
10291 * [15] PrimaryExpr ::= VariableReference
10292 * | '(' Expr ')'
10293 * | Literal
10294 * | Number
10295 * | FunctionCall
10296 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010297 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010298 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010299static void
10300xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010301 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010302 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010303 else if (CUR == '(') {
10304 NEXT;
10305 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010306 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010307 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010308 if (CUR != ')') {
10309 XP_ERROR(XPATH_EXPR_ERROR);
10310 }
10311 NEXT;
10312 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010313 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010314 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010315 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010317 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010318 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010319 }
10320 SKIP_BLANKS;
10321}
10322
10323/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010324 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010325 * @ctxt: the XPath Parser context
10326 *
10327 * [20] FilterExpr ::= PrimaryExpr
10328 * | FilterExpr Predicate
10329 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010330 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010331 * Square brackets are used to filter expressions in the same way that
10332 * they are used in location paths. It is an error if the expression to
10333 * be filtered does not evaluate to a node-set. The context node list
10334 * used for evaluating the expression in square brackets is the node-set
10335 * to be filtered listed in document order.
10336 */
10337
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010338static void
10339xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10340 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010341 CHECK_ERROR;
10342 SKIP_BLANKS;
10343
10344 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010345 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010346 SKIP_BLANKS;
10347 }
10348
10349
10350}
10351
10352/**
10353 * xmlXPathScanName:
10354 * @ctxt: the XPath Parser context
10355 *
10356 * Trickery: parse an XML name but without consuming the input flow
10357 * Needed to avoid insanity in the parser state.
10358 *
10359 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10360 * CombiningChar | Extender
10361 *
10362 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10363 *
10364 * [6] Names ::= Name (S Name)*
10365 *
10366 * Returns the Name parsed or NULL
10367 */
10368
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010369static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010370xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010371 int len = 0, l;
10372 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010373 const xmlChar *cur;
10374 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010375
Daniel Veillard03226812004-11-01 14:55:21 +000010376 cur = ctxt->cur;
10377
10378 c = CUR_CHAR(l);
10379 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10380 (!IS_LETTER(c) && (c != '_') &&
10381 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010382 return(NULL);
10383 }
10384
Daniel Veillard03226812004-11-01 14:55:21 +000010385 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10386 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10387 (c == '.') || (c == '-') ||
10388 (c == '_') || (c == ':') ||
10389 (IS_COMBINING(c)) ||
10390 (IS_EXTENDER(c)))) {
10391 len += l;
10392 NEXTL(l);
10393 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010394 }
Daniel Veillard03226812004-11-01 14:55:21 +000010395 ret = xmlStrndup(cur, ctxt->cur - cur);
10396 ctxt->cur = cur;
10397 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010398}
10399
10400/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010401 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010402 * @ctxt: the XPath Parser context
10403 *
10404 * [19] PathExpr ::= LocationPath
10405 * | FilterExpr
10406 * | FilterExpr '/' RelativeLocationPath
10407 * | FilterExpr '//' RelativeLocationPath
10408 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010409 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010410 * The / operator and // operators combine an arbitrary expression
10411 * and a relative location path. It is an error if the expression
10412 * does not evaluate to a node-set.
10413 * The / operator does composition in the same way as when / is
10414 * used in a location path. As in location paths, // is short for
10415 * /descendant-or-self::node()/.
10416 */
10417
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010418static void
10419xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010420 int lc = 1; /* Should we branch to LocationPath ? */
10421 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10422
10423 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010424 if ((CUR == '$') || (CUR == '(') ||
10425 (IS_ASCII_DIGIT(CUR)) ||
10426 (CUR == '\'') || (CUR == '"') ||
10427 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010428 lc = 0;
10429 } else if (CUR == '*') {
10430 /* relative or absolute location path */
10431 lc = 1;
10432 } else if (CUR == '/') {
10433 /* relative or absolute location path */
10434 lc = 1;
10435 } else if (CUR == '@') {
10436 /* relative abbreviated attribute location path */
10437 lc = 1;
10438 } else if (CUR == '.') {
10439 /* relative abbreviated attribute location path */
10440 lc = 1;
10441 } else {
10442 /*
10443 * Problem is finding if we have a name here whether it's:
10444 * - a nodetype
10445 * - a function call in which case it's followed by '('
10446 * - an axis in which case it's followed by ':'
10447 * - a element name
10448 * We do an a priori analysis here rather than having to
10449 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010450 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010451 * read/write/debug.
10452 */
10453 SKIP_BLANKS;
10454 name = xmlXPathScanName(ctxt);
10455 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10456#ifdef DEBUG_STEP
10457 xmlGenericError(xmlGenericErrorContext,
10458 "PathExpr: Axis\n");
10459#endif
10460 lc = 1;
10461 xmlFree(name);
10462 } else if (name != NULL) {
10463 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010464
10465
10466 while (NXT(len) != 0) {
10467 if (NXT(len) == '/') {
10468 /* element name */
10469#ifdef DEBUG_STEP
10470 xmlGenericError(xmlGenericErrorContext,
10471 "PathExpr: AbbrRelLocation\n");
10472#endif
10473 lc = 1;
10474 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010475 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010476 /* ignore blanks */
10477 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010478 } else if (NXT(len) == ':') {
10479#ifdef DEBUG_STEP
10480 xmlGenericError(xmlGenericErrorContext,
10481 "PathExpr: AbbrRelLocation\n");
10482#endif
10483 lc = 1;
10484 break;
10485 } else if ((NXT(len) == '(')) {
10486 /* Note Type or Function */
10487 if (xmlXPathIsNodeType(name)) {
10488#ifdef DEBUG_STEP
10489 xmlGenericError(xmlGenericErrorContext,
10490 "PathExpr: Type search\n");
10491#endif
10492 lc = 1;
10493 } else {
10494#ifdef DEBUG_STEP
10495 xmlGenericError(xmlGenericErrorContext,
10496 "PathExpr: function call\n");
10497#endif
10498 lc = 0;
10499 }
10500 break;
10501 } else if ((NXT(len) == '[')) {
10502 /* element name */
10503#ifdef DEBUG_STEP
10504 xmlGenericError(xmlGenericErrorContext,
10505 "PathExpr: AbbrRelLocation\n");
10506#endif
10507 lc = 1;
10508 break;
10509 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10510 (NXT(len) == '=')) {
10511 lc = 1;
10512 break;
10513 } else {
10514 lc = 1;
10515 break;
10516 }
10517 len++;
10518 }
10519 if (NXT(len) == 0) {
10520#ifdef DEBUG_STEP
10521 xmlGenericError(xmlGenericErrorContext,
10522 "PathExpr: AbbrRelLocation\n");
10523#endif
10524 /* element name */
10525 lc = 1;
10526 }
10527 xmlFree(name);
10528 } else {
William M. Brack08171912003-12-29 02:52:11 +000010529 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010530 XP_ERROR(XPATH_EXPR_ERROR);
10531 }
10532 }
10533
10534 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010535 if (CUR == '/') {
10536 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10537 } else {
10538 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010539 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010540 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010541 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010542 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010543 CHECK_ERROR;
10544 if ((CUR == '/') && (NXT(1) == '/')) {
10545 SKIP(2);
10546 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010547
10548 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10549 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10550 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10551
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010552 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010553 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010554 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010555 }
10556 }
10557 SKIP_BLANKS;
10558}
10559
10560/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010561 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010562 * @ctxt: the XPath Parser context
10563 *
10564 * [18] UnionExpr ::= PathExpr
10565 * | UnionExpr '|' PathExpr
10566 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010567 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010568 */
10569
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010570static void
10571xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10572 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010573 CHECK_ERROR;
10574 SKIP_BLANKS;
10575 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010576 int op1 = ctxt->comp->last;
10577 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010578
10579 NEXT;
10580 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010581 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010582
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010583 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10584
Owen Taylor3473f882001-02-23 17:55:21 +000010585 SKIP_BLANKS;
10586 }
Owen Taylor3473f882001-02-23 17:55:21 +000010587}
10588
10589/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010590 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010591 * @ctxt: the XPath Parser context
10592 *
10593 * [27] UnaryExpr ::= UnionExpr
10594 * | '-' UnaryExpr
10595 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010596 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010597 */
10598
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010599static void
10600xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010601 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010602 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010603
10604 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010605 while (CUR == '-') {
10606 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010607 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010608 NEXT;
10609 SKIP_BLANKS;
10610 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010611
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010612 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010613 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010614 if (found) {
10615 if (minus)
10616 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10617 else
10618 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010619 }
10620}
10621
10622/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010623 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010624 * @ctxt: the XPath Parser context
10625 *
10626 * [26] MultiplicativeExpr ::= UnaryExpr
10627 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10628 * | MultiplicativeExpr 'div' UnaryExpr
10629 * | MultiplicativeExpr 'mod' UnaryExpr
10630 * [34] MultiplyOperator ::= '*'
10631 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010632 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010633 */
10634
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010635static void
10636xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10637 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010638 CHECK_ERROR;
10639 SKIP_BLANKS;
10640 while ((CUR == '*') ||
10641 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10642 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10643 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010644 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010645
10646 if (CUR == '*') {
10647 op = 0;
10648 NEXT;
10649 } else if (CUR == 'd') {
10650 op = 1;
10651 SKIP(3);
10652 } else if (CUR == 'm') {
10653 op = 2;
10654 SKIP(3);
10655 }
10656 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010657 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010658 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010659 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010660 SKIP_BLANKS;
10661 }
10662}
10663
10664/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010665 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010666 * @ctxt: the XPath Parser context
10667 *
10668 * [25] AdditiveExpr ::= MultiplicativeExpr
10669 * | AdditiveExpr '+' MultiplicativeExpr
10670 * | AdditiveExpr '-' MultiplicativeExpr
10671 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010672 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010673 */
10674
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010675static void
10676xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010677
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010678 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010679 CHECK_ERROR;
10680 SKIP_BLANKS;
10681 while ((CUR == '+') || (CUR == '-')) {
10682 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010684
10685 if (CUR == '+') plus = 1;
10686 else plus = 0;
10687 NEXT;
10688 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010689 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010690 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010691 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010692 SKIP_BLANKS;
10693 }
10694}
10695
10696/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010697 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010698 * @ctxt: the XPath Parser context
10699 *
10700 * [24] RelationalExpr ::= AdditiveExpr
10701 * | RelationalExpr '<' AdditiveExpr
10702 * | RelationalExpr '>' AdditiveExpr
10703 * | RelationalExpr '<=' AdditiveExpr
10704 * | RelationalExpr '>=' AdditiveExpr
10705 *
10706 * A <= B > C is allowed ? Answer from James, yes with
10707 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10708 * which is basically what got implemented.
10709 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010710 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010711 * on the stack
10712 */
10713
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010714static void
10715xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10716 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010717 CHECK_ERROR;
10718 SKIP_BLANKS;
10719 while ((CUR == '<') ||
10720 (CUR == '>') ||
10721 ((CUR == '<') && (NXT(1) == '=')) ||
10722 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010723 int inf, strict;
10724 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010725
10726 if (CUR == '<') inf = 1;
10727 else inf = 0;
10728 if (NXT(1) == '=') strict = 0;
10729 else strict = 1;
10730 NEXT;
10731 if (!strict) NEXT;
10732 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010733 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010734 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010735 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010736 SKIP_BLANKS;
10737 }
10738}
10739
10740/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010741 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010742 * @ctxt: the XPath Parser context
10743 *
10744 * [23] EqualityExpr ::= RelationalExpr
10745 * | EqualityExpr '=' RelationalExpr
10746 * | EqualityExpr '!=' RelationalExpr
10747 *
10748 * A != B != C is allowed ? Answer from James, yes with
10749 * (RelationalExpr = RelationalExpr) = RelationalExpr
10750 * (RelationalExpr != RelationalExpr) != RelationalExpr
10751 * which is basically what got implemented.
10752 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010753 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010754 *
10755 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010756static void
10757xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10758 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010759 CHECK_ERROR;
10760 SKIP_BLANKS;
10761 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010762 int eq;
10763 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010764
10765 if (CUR == '=') eq = 1;
10766 else eq = 0;
10767 NEXT;
10768 if (!eq) NEXT;
10769 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010770 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010771 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010772 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010773 SKIP_BLANKS;
10774 }
10775}
10776
10777/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010778 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010779 * @ctxt: the XPath Parser context
10780 *
10781 * [22] AndExpr ::= EqualityExpr
10782 * | AndExpr 'and' EqualityExpr
10783 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010784 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010785 *
10786 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010787static void
10788xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10789 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010790 CHECK_ERROR;
10791 SKIP_BLANKS;
10792 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010793 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010794 SKIP(3);
10795 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010796 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010797 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010798 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010799 SKIP_BLANKS;
10800 }
10801}
10802
10803/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010804 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010805 * @ctxt: the XPath Parser context
10806 *
10807 * [14] Expr ::= OrExpr
10808 * [21] OrExpr ::= AndExpr
10809 * | OrExpr 'or' AndExpr
10810 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010812 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010813static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010814xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010815 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010816 CHECK_ERROR;
10817 SKIP_BLANKS;
10818 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010819 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010820 SKIP(2);
10821 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010822 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010823 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010824 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10825 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010826 SKIP_BLANKS;
10827 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010828 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010829 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010830 /*
10831 * This is the main place to eliminate sorting for
10832 * operations which don't require a sorted node-set.
10833 * E.g. count().
10834 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010835 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10836 }
Owen Taylor3473f882001-02-23 17:55:21 +000010837}
10838
10839/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010840 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010841 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010842 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010843 *
10844 * [8] Predicate ::= '[' PredicateExpr ']'
10845 * [9] PredicateExpr ::= Expr
10846 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010847 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010848 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010849static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010850xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010851 int op1 = ctxt->comp->last;
10852
10853 SKIP_BLANKS;
10854 if (CUR != '[') {
10855 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10856 }
10857 NEXT;
10858 SKIP_BLANKS;
10859
10860 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010861 /*
10862 * This call to xmlXPathCompileExpr() will deactivate sorting
10863 * of the predicate result.
10864 * TODO: Sorting is still activated for filters, since I'm not
10865 * sure if needed. Normally sorting should not be needed, since
10866 * a filter can only diminish the number of items in a sequence,
10867 * but won't change its order; so if the initial sequence is sorted,
10868 * subsequent sorting is not needed.
10869 */
10870 if (! filter)
10871 xmlXPathCompileExpr(ctxt, 0);
10872 else
10873 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010874 CHECK_ERROR;
10875
10876 if (CUR != ']') {
10877 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10878 }
10879
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010880 if (filter)
10881 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10882 else
10883 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010884
10885 NEXT;
10886 SKIP_BLANKS;
10887}
10888
10889/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010890 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010891 * @ctxt: the XPath Parser context
10892 * @test: pointer to a xmlXPathTestVal
10893 * @type: pointer to a xmlXPathTypeVal
10894 * @prefix: placeholder for a possible name prefix
10895 *
10896 * [7] NodeTest ::= NameTest
10897 * | NodeType '(' ')'
10898 * | 'processing-instruction' '(' Literal ')'
10899 *
10900 * [37] NameTest ::= '*'
10901 * | NCName ':' '*'
10902 * | QName
10903 * [38] NodeType ::= 'comment'
10904 * | 'text'
10905 * | 'processing-instruction'
10906 * | 'node'
10907 *
William M. Brack08171912003-12-29 02:52:11 +000010908 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010909 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010910static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010911xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10912 xmlXPathTypeVal *type, const xmlChar **prefix,
10913 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010914 int blanks;
10915
10916 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10917 STRANGE;
10918 return(NULL);
10919 }
William M. Brack78637da2003-07-31 14:47:38 +000010920 *type = (xmlXPathTypeVal) 0;
10921 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010922 *prefix = NULL;
10923 SKIP_BLANKS;
10924
10925 if ((name == NULL) && (CUR == '*')) {
10926 /*
10927 * All elements
10928 */
10929 NEXT;
10930 *test = NODE_TEST_ALL;
10931 return(NULL);
10932 }
10933
10934 if (name == NULL)
10935 name = xmlXPathParseNCName(ctxt);
10936 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010937 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010938 }
10939
William M. Brack76e95df2003-10-18 16:20:14 +000010940 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010941 SKIP_BLANKS;
10942 if (CUR == '(') {
10943 NEXT;
10944 /*
10945 * NodeType or PI search
10946 */
10947 if (xmlStrEqual(name, BAD_CAST "comment"))
10948 *type = NODE_TYPE_COMMENT;
10949 else if (xmlStrEqual(name, BAD_CAST "node"))
10950 *type = NODE_TYPE_NODE;
10951 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10952 *type = NODE_TYPE_PI;
10953 else if (xmlStrEqual(name, BAD_CAST "text"))
10954 *type = NODE_TYPE_TEXT;
10955 else {
10956 if (name != NULL)
10957 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010958 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010959 }
10960
10961 *test = NODE_TEST_TYPE;
10962
10963 SKIP_BLANKS;
10964 if (*type == NODE_TYPE_PI) {
10965 /*
10966 * Specific case: search a PI by name.
10967 */
Owen Taylor3473f882001-02-23 17:55:21 +000010968 if (name != NULL)
10969 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010970 name = NULL;
10971 if (CUR != ')') {
10972 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010973 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010974 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010975 SKIP_BLANKS;
10976 }
Owen Taylor3473f882001-02-23 17:55:21 +000010977 }
10978 if (CUR != ')') {
10979 if (name != NULL)
10980 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010981 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010982 }
10983 NEXT;
10984 return(name);
10985 }
10986 *test = NODE_TEST_NAME;
10987 if ((!blanks) && (CUR == ':')) {
10988 NEXT;
10989
10990 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010991 * Since currently the parser context don't have a
10992 * namespace list associated:
10993 * The namespace name for this prefix can be computed
10994 * only at evaluation time. The compilation is done
10995 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010996 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010997#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010998 *prefix = xmlXPathNsLookup(ctxt->context, name);
10999 if (name != NULL)
11000 xmlFree(name);
11001 if (*prefix == NULL) {
11002 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11003 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011004#else
11005 *prefix = name;
11006#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011007
11008 if (CUR == '*') {
11009 /*
11010 * All elements
11011 */
11012 NEXT;
11013 *test = NODE_TEST_ALL;
11014 return(NULL);
11015 }
11016
11017 name = xmlXPathParseNCName(ctxt);
11018 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011019 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011020 }
11021 }
11022 return(name);
11023}
11024
11025/**
11026 * xmlXPathIsAxisName:
11027 * @name: a preparsed name token
11028 *
11029 * [6] AxisName ::= 'ancestor'
11030 * | 'ancestor-or-self'
11031 * | 'attribute'
11032 * | 'child'
11033 * | 'descendant'
11034 * | 'descendant-or-self'
11035 * | 'following'
11036 * | 'following-sibling'
11037 * | 'namespace'
11038 * | 'parent'
11039 * | 'preceding'
11040 * | 'preceding-sibling'
11041 * | 'self'
11042 *
11043 * Returns the axis or 0
11044 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011045static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011046xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011047 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011048 switch (name[0]) {
11049 case 'a':
11050 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11051 ret = AXIS_ANCESTOR;
11052 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11053 ret = AXIS_ANCESTOR_OR_SELF;
11054 if (xmlStrEqual(name, BAD_CAST "attribute"))
11055 ret = AXIS_ATTRIBUTE;
11056 break;
11057 case 'c':
11058 if (xmlStrEqual(name, BAD_CAST "child"))
11059 ret = AXIS_CHILD;
11060 break;
11061 case 'd':
11062 if (xmlStrEqual(name, BAD_CAST "descendant"))
11063 ret = AXIS_DESCENDANT;
11064 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11065 ret = AXIS_DESCENDANT_OR_SELF;
11066 break;
11067 case 'f':
11068 if (xmlStrEqual(name, BAD_CAST "following"))
11069 ret = AXIS_FOLLOWING;
11070 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11071 ret = AXIS_FOLLOWING_SIBLING;
11072 break;
11073 case 'n':
11074 if (xmlStrEqual(name, BAD_CAST "namespace"))
11075 ret = AXIS_NAMESPACE;
11076 break;
11077 case 'p':
11078 if (xmlStrEqual(name, BAD_CAST "parent"))
11079 ret = AXIS_PARENT;
11080 if (xmlStrEqual(name, BAD_CAST "preceding"))
11081 ret = AXIS_PRECEDING;
11082 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11083 ret = AXIS_PRECEDING_SIBLING;
11084 break;
11085 case 's':
11086 if (xmlStrEqual(name, BAD_CAST "self"))
11087 ret = AXIS_SELF;
11088 break;
11089 }
11090 return(ret);
11091}
11092
11093/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011094 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011095 * @ctxt: the XPath Parser context
11096 *
11097 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11098 * | AbbreviatedStep
11099 *
11100 * [12] AbbreviatedStep ::= '.' | '..'
11101 *
11102 * [5] AxisSpecifier ::= AxisName '::'
11103 * | AbbreviatedAxisSpecifier
11104 *
11105 * [13] AbbreviatedAxisSpecifier ::= '@'?
11106 *
11107 * Modified for XPtr range support as:
11108 *
11109 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11110 * | AbbreviatedStep
11111 * | 'range-to' '(' Expr ')' Predicate*
11112 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011113 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011114 * A location step of . is short for self::node(). This is
11115 * particularly useful in conjunction with //. For example, the
11116 * location path .//para is short for
11117 * self::node()/descendant-or-self::node()/child::para
11118 * and so will select all para descendant elements of the context
11119 * node.
11120 * Similarly, a location step of .. is short for parent::node().
11121 * For example, ../title is short for parent::node()/child::title
11122 * and so will select the title children of the parent of the context
11123 * node.
11124 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011125static void
11126xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011127#ifdef LIBXML_XPTR_ENABLED
11128 int rangeto = 0;
11129 int op2 = -1;
11130#endif
11131
Owen Taylor3473f882001-02-23 17:55:21 +000011132 SKIP_BLANKS;
11133 if ((CUR == '.') && (NXT(1) == '.')) {
11134 SKIP(2);
11135 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011136 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11137 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011138 } else if (CUR == '.') {
11139 NEXT;
11140 SKIP_BLANKS;
11141 } else {
11142 xmlChar *name = NULL;
11143 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011144 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011145 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011146 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011147 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011148
11149 /*
11150 * The modification needed for XPointer change to the production
11151 */
11152#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011153 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011154 name = xmlXPathParseNCName(ctxt);
11155 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011156 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011157 xmlFree(name);
11158 SKIP_BLANKS;
11159 if (CUR != '(') {
11160 XP_ERROR(XPATH_EXPR_ERROR);
11161 }
11162 NEXT;
11163 SKIP_BLANKS;
11164
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011165 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011166 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011167 CHECK_ERROR;
11168
11169 SKIP_BLANKS;
11170 if (CUR != ')') {
11171 XP_ERROR(XPATH_EXPR_ERROR);
11172 }
11173 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011174 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011175 goto eval_predicates;
11176 }
11177 }
11178#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011179 if (CUR == '*') {
11180 axis = AXIS_CHILD;
11181 } else {
11182 if (name == NULL)
11183 name = xmlXPathParseNCName(ctxt);
11184 if (name != NULL) {
11185 axis = xmlXPathIsAxisName(name);
11186 if (axis != 0) {
11187 SKIP_BLANKS;
11188 if ((CUR == ':') && (NXT(1) == ':')) {
11189 SKIP(2);
11190 xmlFree(name);
11191 name = NULL;
11192 } else {
11193 /* an element name can conflict with an axis one :-\ */
11194 axis = AXIS_CHILD;
11195 }
Owen Taylor3473f882001-02-23 17:55:21 +000011196 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011197 axis = AXIS_CHILD;
11198 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011199 } else if (CUR == '@') {
11200 NEXT;
11201 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011202 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011203 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011204 }
Owen Taylor3473f882001-02-23 17:55:21 +000011205 }
11206
11207 CHECK_ERROR;
11208
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011209 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011210 if (test == 0)
11211 return;
11212
Daniel Veillarded6c5492005-07-23 15:00:22 +000011213 if ((prefix != NULL) && (ctxt->context != NULL) &&
11214 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11215 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11216 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11217 }
11218 }
Owen Taylor3473f882001-02-23 17:55:21 +000011219#ifdef DEBUG_STEP
11220 xmlGenericError(xmlGenericErrorContext,
11221 "Basis : computing new set\n");
11222#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011223
Owen Taylor3473f882001-02-23 17:55:21 +000011224#ifdef DEBUG_STEP
11225 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011226 if (ctxt->value == NULL)
11227 xmlGenericError(xmlGenericErrorContext, "no value\n");
11228 else if (ctxt->value->nodesetval == NULL)
11229 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11230 else
11231 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011232#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011233
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011234#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011235eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011236#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011237 op1 = ctxt->comp->last;
11238 ctxt->comp->last = -1;
11239
Owen Taylor3473f882001-02-23 17:55:21 +000011240 SKIP_BLANKS;
11241 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011242 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011243 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011244
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011245#ifdef LIBXML_XPTR_ENABLED
11246 if (rangeto) {
11247 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11248 } else
11249#endif
11250 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11251 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011252
Owen Taylor3473f882001-02-23 17:55:21 +000011253 }
11254#ifdef DEBUG_STEP
11255 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011256 if (ctxt->value == NULL)
11257 xmlGenericError(xmlGenericErrorContext, "no value\n");
11258 else if (ctxt->value->nodesetval == NULL)
11259 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11260 else
11261 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11262 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011263#endif
11264}
11265
11266/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011267 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011268 * @ctxt: the XPath Parser context
11269 *
11270 * [3] RelativeLocationPath ::= Step
11271 * | RelativeLocationPath '/' Step
11272 * | AbbreviatedRelativeLocationPath
11273 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11274 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011275 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011276 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011277static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011278xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011279(xmlXPathParserContextPtr ctxt) {
11280 SKIP_BLANKS;
11281 if ((CUR == '/') && (NXT(1) == '/')) {
11282 SKIP(2);
11283 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011284 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11285 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011286 } else if (CUR == '/') {
11287 NEXT;
11288 SKIP_BLANKS;
11289 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011290 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011291 SKIP_BLANKS;
11292 while (CUR == '/') {
11293 if ((CUR == '/') && (NXT(1) == '/')) {
11294 SKIP(2);
11295 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011296 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011297 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011298 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011299 } else if (CUR == '/') {
11300 NEXT;
11301 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011302 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011303 }
11304 SKIP_BLANKS;
11305 }
11306}
11307
11308/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011309 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011310 * @ctxt: the XPath Parser context
11311 *
11312 * [1] LocationPath ::= RelativeLocationPath
11313 * | AbsoluteLocationPath
11314 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11315 * | AbbreviatedAbsoluteLocationPath
11316 * [10] AbbreviatedAbsoluteLocationPath ::=
11317 * '//' RelativeLocationPath
11318 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011319 * Compile a location path
11320 *
Owen Taylor3473f882001-02-23 17:55:21 +000011321 * // is short for /descendant-or-self::node()/. For example,
11322 * //para is short for /descendant-or-self::node()/child::para and
11323 * so will select any para element in the document (even a para element
11324 * that is a document element will be selected by //para since the
11325 * document element node is a child of the root node); div//para is
11326 * short for div/descendant-or-self::node()/child::para and so will
11327 * select all para descendants of div children.
11328 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011329static void
11330xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011331 SKIP_BLANKS;
11332 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011333 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011334 } else {
11335 while (CUR == '/') {
11336 if ((CUR == '/') && (NXT(1) == '/')) {
11337 SKIP(2);
11338 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011339 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11340 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011341 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011342 } else if (CUR == '/') {
11343 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011344 SKIP_BLANKS;
11345 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011346 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011347 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011348 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011349 }
11350 }
11351 }
11352}
11353
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011354/************************************************************************
11355 * *
11356 * XPath precompiled expression evaluation *
11357 * *
11358 ************************************************************************/
11359
Daniel Veillardf06307e2001-07-03 10:35:50 +000011360static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011361xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11362
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011363#ifdef DEBUG_STEP
11364static void
11365xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11366 xmlXPathTestVal test,
11367 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011368{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011369 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011370 switch (axis) {
11371 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011372 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011373 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011374 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011375 xmlGenericError(xmlGenericErrorContext,
11376 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011377 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011378 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011379 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011380 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011381 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011382 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011384 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011385 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011386 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011387 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011388 xmlGenericError(xmlGenericErrorContext,
11389 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011391 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011392 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011394 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011395 xmlGenericError(xmlGenericErrorContext,
11396 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011397 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011398 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011399 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011400 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011401 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011402 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011403 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011404 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011405 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011406 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011407 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011408 xmlGenericError(xmlGenericErrorContext,
11409 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011411 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011412 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011413 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011414 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011415 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011416 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011417 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011418 case NODE_TEST_NONE:
11419 xmlGenericError(xmlGenericErrorContext,
11420 " searching for none !!!\n");
11421 break;
11422 case NODE_TEST_TYPE:
11423 xmlGenericError(xmlGenericErrorContext,
11424 " searching for type %d\n", type);
11425 break;
11426 case NODE_TEST_PI:
11427 xmlGenericError(xmlGenericErrorContext,
11428 " searching for PI !!!\n");
11429 break;
11430 case NODE_TEST_ALL:
11431 xmlGenericError(xmlGenericErrorContext,
11432 " searching for *\n");
11433 break;
11434 case NODE_TEST_NS:
11435 xmlGenericError(xmlGenericErrorContext,
11436 " searching for namespace %s\n",
11437 prefix);
11438 break;
11439 case NODE_TEST_NAME:
11440 xmlGenericError(xmlGenericErrorContext,
11441 " searching for name %s\n", name);
11442 if (prefix != NULL)
11443 xmlGenericError(xmlGenericErrorContext,
11444 " with namespace %s\n", prefix);
11445 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011446 }
11447 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011448}
11449#endif /* DEBUG_STEP */
11450
11451static int
11452xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11453 xmlXPathStepOpPtr op,
11454 xmlNodeSetPtr set,
11455 int contextSize,
11456 int hasNsNodes)
11457{
11458 if (op->ch1 != -1) {
11459 xmlXPathCompExprPtr comp = ctxt->comp;
11460 /*
11461 * Process inner predicates first.
11462 */
11463 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11464 /*
11465 * TODO: raise an internal error.
11466 */
11467 }
11468 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11469 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11470 CHECK_ERROR0;
11471 if (contextSize <= 0)
11472 return(0);
11473 }
11474 if (op->ch2 != -1) {
11475 xmlXPathContextPtr xpctxt = ctxt->context;
11476 xmlNodePtr contextNode, oldContextNode;
11477 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011478 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011479 xmlXPathStepOpPtr exprOp;
11480 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11481
11482#ifdef LIBXML_XPTR_ENABLED
11483 /*
11484 * URGENT TODO: Check the following:
11485 * We don't expect location sets if evaluating prediates, right?
11486 * Only filters should expect location sets, right?
11487 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011488#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011489 /*
11490 * SPEC XPath 1.0:
11491 * "For each node in the node-set to be filtered, the
11492 * PredicateExpr is evaluated with that node as the
11493 * context node, with the number of nodes in the
11494 * node-set as the context size, and with the proximity
11495 * position of the node in the node-set with respect to
11496 * the axis as the context position;"
11497 * @oldset is the node-set" to be filtered.
11498 *
11499 * SPEC XPath 1.0:
11500 * "only predicates change the context position and
11501 * context size (see [2.4 Predicates])."
11502 * Example:
11503 * node-set context pos
11504 * nA 1
11505 * nB 2
11506 * nC 3
11507 * After applying predicate [position() > 1] :
11508 * node-set context pos
11509 * nB 1
11510 * nC 2
11511 */
11512 oldContextNode = xpctxt->node;
11513 oldContextDoc = xpctxt->doc;
11514 /*
11515 * Get the expression of this predicate.
11516 */
11517 exprOp = &ctxt->comp->steps[op->ch2];
11518 newContextSize = 0;
11519 for (i = 0; i < set->nodeNr; i++) {
11520 if (set->nodeTab[i] == NULL)
11521 continue;
11522
11523 contextNode = set->nodeTab[i];
11524 xpctxt->node = contextNode;
11525 xpctxt->contextSize = contextSize;
11526 xpctxt->proximityPosition = ++contextPos;
11527
11528 /*
11529 * Also set the xpath document in case things like
11530 * key() are evaluated in the predicate.
11531 */
11532 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11533 (contextNode->doc != NULL))
11534 xpctxt->doc = contextNode->doc;
11535 /*
11536 * Evaluate the predicate expression with 1 context node
11537 * at a time; this node is packaged into a node set; this
11538 * node set is handed over to the evaluation mechanism.
11539 */
11540 if (contextObj == NULL)
11541 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11542 else
11543 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11544 contextNode);
11545
11546 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011547
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011548 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011549
William M. Brack0bcec062007-02-14 02:15:19 +000011550 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11551 xmlXPathNodeSetClear(set, hasNsNodes);
11552 newContextSize = 0;
11553 goto evaluation_exit;
11554 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011555
11556 if (res != 0) {
11557 newContextSize++;
11558 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011559 /*
11560 * Remove the entry from the initial node set.
11561 */
11562 set->nodeTab[i] = NULL;
11563 if (contextNode->type == XML_NAMESPACE_DECL)
11564 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011565 }
11566 if (ctxt->value == contextObj) {
11567 /*
11568 * Don't free the temporary XPath object holding the
11569 * context node, in order to avoid massive recreation
11570 * inside this loop.
11571 */
11572 valuePop(ctxt);
11573 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11574 } else {
11575 /*
11576 * TODO: The object was lost in the evaluation machinery.
11577 * Can this happen? Maybe in internal-error cases.
11578 */
11579 contextObj = NULL;
11580 }
11581 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011582
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011583 if (contextObj != NULL) {
11584 if (ctxt->value == contextObj)
11585 valuePop(ctxt);
11586 xmlXPathReleaseObject(xpctxt, contextObj);
11587 }
William M. Brack0bcec062007-02-14 02:15:19 +000011588evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011589 if (exprRes != NULL)
11590 xmlXPathReleaseObject(ctxt->context, exprRes);
11591 /*
11592 * Reset/invalidate the context.
11593 */
11594 xpctxt->node = oldContextNode;
11595 xpctxt->doc = oldContextDoc;
11596 xpctxt->contextSize = -1;
11597 xpctxt->proximityPosition = -1;
11598 return(newContextSize);
11599 }
11600 return(contextSize);
11601}
11602
11603static int
11604xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11605 xmlXPathStepOpPtr op,
11606 xmlNodeSetPtr set,
11607 int contextSize,
11608 int minPos,
11609 int maxPos,
11610 int hasNsNodes)
11611{
11612 if (op->ch1 != -1) {
11613 xmlXPathCompExprPtr comp = ctxt->comp;
11614 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11615 /*
11616 * TODO: raise an internal error.
11617 */
11618 }
11619 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11620 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11621 CHECK_ERROR0;
11622 if (contextSize <= 0)
11623 return(0);
11624 }
11625 /*
11626 * Check if the node set contains a sufficient number of nodes for
11627 * the requested range.
11628 */
11629 if (contextSize < minPos) {
11630 xmlXPathNodeSetClear(set, hasNsNodes);
11631 return(0);
11632 }
11633 if (op->ch2 == -1) {
11634 /*
11635 * TODO: Can this ever happen?
11636 */
11637 return (contextSize);
11638 } else {
11639 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011640 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011641 xmlXPathStepOpPtr exprOp;
11642 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11643 xmlNodePtr oldContextNode, contextNode = NULL;
11644 xmlXPathContextPtr xpctxt = ctxt->context;
11645
11646#ifdef LIBXML_XPTR_ENABLED
11647 /*
11648 * URGENT TODO: Check the following:
11649 * We don't expect location sets if evaluating prediates, right?
11650 * Only filters should expect location sets, right?
11651 */
11652#endif /* LIBXML_XPTR_ENABLED */
11653
11654 /*
11655 * Save old context.
11656 */
11657 oldContextNode = xpctxt->node;
11658 oldContextDoc = xpctxt->doc;
11659 /*
11660 * Get the expression of this predicate.
11661 */
11662 exprOp = &ctxt->comp->steps[op->ch2];
11663 for (i = 0; i < set->nodeNr; i++) {
11664 if (set->nodeTab[i] == NULL)
11665 continue;
11666
11667 contextNode = set->nodeTab[i];
11668 xpctxt->node = contextNode;
11669 xpctxt->contextSize = contextSize;
11670 xpctxt->proximityPosition = ++contextPos;
11671
11672 /*
11673 * Initialize the new set.
11674 * Also set the xpath document in case things like
11675 * key() evaluation are attempted on the predicate
11676 */
11677 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11678 (contextNode->doc != NULL))
11679 xpctxt->doc = contextNode->doc;
11680 /*
11681 * Evaluate the predicate expression with 1 context node
11682 * at a time; this node is packaged into a node set; this
11683 * node set is handed over to the evaluation mechanism.
11684 */
11685 if (contextObj == NULL)
11686 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11687 else
11688 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11689 contextNode);
11690
11691 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011692 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011693
11694 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011695 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011696
11697 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011698 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011699
11700 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011701 /*
11702 * Fits in the requested range.
11703 */
11704 newContextSize++;
11705 if (minPos == maxPos) {
11706 /*
11707 * Only 1 node was requested.
11708 */
11709 if (contextNode->type == XML_NAMESPACE_DECL) {
11710 /*
11711 * As always: take care of those nasty
11712 * namespace nodes.
11713 */
11714 set->nodeTab[i] = NULL;
11715 }
11716 xmlXPathNodeSetClear(set, hasNsNodes);
11717 set->nodeNr = 1;
11718 set->nodeTab[0] = contextNode;
11719 goto evaluation_exit;
11720 }
11721 if (pos == maxPos) {
11722 /*
11723 * We are done.
11724 */
11725 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11726 goto evaluation_exit;
11727 }
11728 } else {
11729 /*
11730 * Remove the entry from the initial node set.
11731 */
11732 set->nodeTab[i] = NULL;
11733 if (contextNode->type == XML_NAMESPACE_DECL)
11734 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11735 }
11736 if (exprRes != NULL) {
11737 xmlXPathReleaseObject(ctxt->context, exprRes);
11738 exprRes = NULL;
11739 }
11740 if (ctxt->value == contextObj) {
11741 /*
11742 * Don't free the temporary XPath object holding the
11743 * context node, in order to avoid massive recreation
11744 * inside this loop.
11745 */
11746 valuePop(ctxt);
11747 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11748 } else {
11749 /*
11750 * The object was lost in the evaluation machinery.
11751 * Can this happen? Maybe in case of internal-errors.
11752 */
11753 contextObj = NULL;
11754 }
11755 }
11756 goto evaluation_exit;
11757
11758evaluation_error:
11759 xmlXPathNodeSetClear(set, hasNsNodes);
11760 newContextSize = 0;
11761
11762evaluation_exit:
11763 if (contextObj != NULL) {
11764 if (ctxt->value == contextObj)
11765 valuePop(ctxt);
11766 xmlXPathReleaseObject(xpctxt, contextObj);
11767 }
11768 if (exprRes != NULL)
11769 xmlXPathReleaseObject(ctxt->context, exprRes);
11770 /*
11771 * Reset/invalidate the context.
11772 */
11773 xpctxt->node = oldContextNode;
11774 xpctxt->doc = oldContextDoc;
11775 xpctxt->contextSize = -1;
11776 xpctxt->proximityPosition = -1;
11777 return(newContextSize);
11778 }
11779 return(contextSize);
11780}
11781
11782static int
11783xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11784 xmlXPathStepOpPtr op,
11785 int *maxPos)
11786{
11787
11788 xmlXPathStepOpPtr exprOp;
11789
11790 /*
11791 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11792 */
11793
11794 /*
11795 * If not -1, then ch1 will point to:
11796 * 1) For predicates (XPATH_OP_PREDICATE):
11797 * - an inner predicate operator
11798 * 2) For filters (XPATH_OP_FILTER):
11799 * - an inner filter operater OR
11800 * - an expression selecting the node set.
11801 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11802 */
11803 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11804 return(0);
11805
11806 if (op->ch2 != -1) {
11807 exprOp = &ctxt->comp->steps[op->ch2];
11808 } else
11809 return(0);
11810
11811 if ((exprOp != NULL) &&
11812 (exprOp->op == XPATH_OP_VALUE) &&
11813 (exprOp->value4 != NULL) &&
11814 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11815 {
11816 /*
11817 * We have a "[n]" predicate here.
11818 * TODO: Unfortunately this simplistic test here is not
11819 * able to detect a position() predicate in compound
11820 * expressions like "[@attr = 'a" and position() = 1],
11821 * and even not the usage of position() in
11822 * "[position() = 1]"; thus - obviously - a position-range,
11823 * like it "[position() < 5]", is also not detected.
11824 * Maybe we could rewrite the AST to ease the optimization.
11825 */
11826 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11827
11828 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11829 (float) *maxPos)
11830 {
11831 return(1);
11832 }
11833 }
11834 return(0);
11835}
11836
11837static int
11838xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11839 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011840 xmlNodePtr * first, xmlNodePtr * last,
11841 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011842{
11843
11844#define XP_TEST_HIT \
11845 if (hasAxisRange != 0) { \
11846 if (++pos == maxPos) { \
11847 addNode(seq, cur); \
11848 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011849 } else { \
11850 addNode(seq, cur); \
11851 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011852
11853#define XP_TEST_HIT_NS \
11854 if (hasAxisRange != 0) { \
11855 if (++pos == maxPos) { \
11856 hasNsNodes = 1; \
11857 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11858 goto axis_range_end; } \
11859 } else { \
11860 hasNsNodes = 1; \
11861 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011862 xpctxt->node, (xmlNsPtr) cur); \
11863 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011864
11865 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11866 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11867 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11868 const xmlChar *prefix = op->value4;
11869 const xmlChar *name = op->value5;
11870 const xmlChar *URI = NULL;
11871
11872#ifdef DEBUG_STEP
11873 int nbMatches = 0, prevMatches = 0;
11874#endif
11875 int total = 0, hasNsNodes = 0;
11876 /* The popped object holding the context nodes */
11877 xmlXPathObjectPtr obj;
11878 /* The set of context nodes for the node tests */
11879 xmlNodeSetPtr contextSeq;
11880 int contextIdx;
11881 xmlNodePtr contextNode;
11882 /* The context node for a compound traversal */
11883 xmlNodePtr outerContextNode;
11884 /* The final resulting node set wrt to all context nodes */
11885 xmlNodeSetPtr outSeq;
11886 /*
11887 * The temporary resulting node set wrt 1 context node.
11888 * Used to feed predicate evaluation.
11889 */
11890 xmlNodeSetPtr seq;
11891 xmlNodePtr cur;
11892 /* First predicate operator */
11893 xmlXPathStepOpPtr predOp;
11894 int maxPos; /* The requested position() (when a "[n]" predicate) */
11895 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011896 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011897
11898 xmlXPathTraversalFunction next = NULL;
11899 /* compound axis traversal */
11900 xmlXPathTraversalFunctionExt outerNext = NULL;
11901 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11902 xmlXPathNodeSetMergeFunction mergeAndClear;
11903 xmlNodePtr oldContextNode;
11904 xmlXPathContextPtr xpctxt = ctxt->context;
11905
11906
11907 CHECK_TYPE0(XPATH_NODESET);
11908 obj = valuePop(ctxt);
11909 /*
11910 * Setup namespaces.
11911 */
11912 if (prefix != NULL) {
11913 URI = xmlXPathNsLookup(xpctxt, prefix);
11914 if (URI == NULL) {
11915 xmlXPathReleaseObject(xpctxt, obj);
11916 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11917 }
11918 }
11919 /*
11920 * Setup axis.
11921 *
11922 * MAYBE FUTURE TODO: merging optimizations:
11923 * - If the nodes to be traversed wrt to the initial nodes and
11924 * the current axis cannot overlap, then we could avoid searching
11925 * for duplicates during the merge.
11926 * But the question is how/when to evaluate if they cannot overlap.
11927 * Example: if we know that for two initial nodes, the one is
11928 * not in the ancestor-or-self axis of the other, then we could safely
11929 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11930 * the descendant-or-self axis.
11931 */
11932 addNode = xmlXPathNodeSetAdd;
11933 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11934 switch (axis) {
11935 case AXIS_ANCESTOR:
11936 first = NULL;
11937 next = xmlXPathNextAncestor;
11938 break;
11939 case AXIS_ANCESTOR_OR_SELF:
11940 first = NULL;
11941 next = xmlXPathNextAncestorOrSelf;
11942 break;
11943 case AXIS_ATTRIBUTE:
11944 first = NULL;
11945 last = NULL;
11946 next = xmlXPathNextAttribute;
11947 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11948 break;
11949 case AXIS_CHILD:
11950 last = NULL;
11951 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11952 /*
11953 * This iterator will give us only nodes which can
11954 * hold element nodes.
11955 */
11956 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11957 }
11958 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11959 (type == NODE_TYPE_NODE))
11960 {
11961 /*
11962 * Optimization if an element node type is 'element'.
11963 */
11964 next = xmlXPathNextChildElement;
11965 } else
11966 next = xmlXPathNextChild;
11967 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11968 break;
11969 case AXIS_DESCENDANT:
11970 last = NULL;
11971 next = xmlXPathNextDescendant;
11972 break;
11973 case AXIS_DESCENDANT_OR_SELF:
11974 last = NULL;
11975 next = xmlXPathNextDescendantOrSelf;
11976 break;
11977 case AXIS_FOLLOWING:
11978 last = NULL;
11979 next = xmlXPathNextFollowing;
11980 break;
11981 case AXIS_FOLLOWING_SIBLING:
11982 last = NULL;
11983 next = xmlXPathNextFollowingSibling;
11984 break;
11985 case AXIS_NAMESPACE:
11986 first = NULL;
11987 last = NULL;
11988 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11989 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11990 break;
11991 case AXIS_PARENT:
11992 first = NULL;
11993 next = xmlXPathNextParent;
11994 break;
11995 case AXIS_PRECEDING:
11996 first = NULL;
11997 next = xmlXPathNextPrecedingInternal;
11998 break;
11999 case AXIS_PRECEDING_SIBLING:
12000 first = NULL;
12001 next = xmlXPathNextPrecedingSibling;
12002 break;
12003 case AXIS_SELF:
12004 first = NULL;
12005 last = NULL;
12006 next = xmlXPathNextSelf;
12007 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12008 break;
12009 }
12010
12011#ifdef DEBUG_STEP
12012 xmlXPathDebugDumpStepAxis(axis, test,
12013 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12014#endif
12015
12016 if (next == NULL) {
12017 xmlXPathReleaseObject(xpctxt, obj);
12018 return(0);
12019 }
12020 contextSeq = obj->nodesetval;
12021 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12022 xmlXPathReleaseObject(xpctxt, obj);
12023 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12024 return(0);
12025 }
12026 /*
12027 * Predicate optimization ---------------------------------------------
12028 * If this step has a last predicate, which contains a position(),
12029 * then we'll optimize (although not exactly "position()", but only
12030 * the short-hand form, i.e., "[n]".
12031 *
12032 * Example - expression "/foo[parent::bar][1]":
12033 *
12034 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12035 * ROOT -- op->ch1
12036 * PREDICATE -- op->ch2 (predOp)
12037 * PREDICATE -- predOp->ch1 = [parent::bar]
12038 * SORT
12039 * COLLECT 'parent' 'name' 'node' bar
12040 * NODE
12041 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12042 *
12043 */
12044 maxPos = 0;
12045 predOp = NULL;
12046 hasPredicateRange = 0;
12047 hasAxisRange = 0;
12048 if (op->ch2 != -1) {
12049 /*
12050 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12051 */
12052 predOp = &ctxt->comp->steps[op->ch2];
12053 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12054 if (predOp->ch1 != -1) {
12055 /*
12056 * Use the next inner predicate operator.
12057 */
12058 predOp = &ctxt->comp->steps[predOp->ch1];
12059 hasPredicateRange = 1;
12060 } else {
12061 /*
12062 * There's no other predicate than the [n] predicate.
12063 */
12064 predOp = NULL;
12065 hasAxisRange = 1;
12066 }
12067 }
12068 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012069 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012070 /*
12071 * Axis traversal -----------------------------------------------------
12072 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012073 /*
12074 * 2.3 Node Tests
12075 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012076 * - For the namespace axis, the principal node type is namespace.
12077 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012078 *
12079 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012080 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012081 * select all element children of the context node
12082 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012083 oldContextNode = xpctxt->node;
12084 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012085 outSeq = NULL;
12086 seq = NULL;
12087 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012088 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012089 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012090
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012091
12092 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12093 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012094 /*
12095 * This is a compound traversal.
12096 */
12097 if (contextNode == NULL) {
12098 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012099 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012100 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012101 outerContextNode = contextSeq->nodeTab[contextIdx++];
12102 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012103 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012104 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012105 if (contextNode == NULL)
12106 continue;
12107 /*
12108 * Set the context for the main traversal.
12109 */
12110 xpctxt->node = contextNode;
12111 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012112 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012113
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 if (seq == NULL) {
12115 seq = xmlXPathNodeSetCreate(NULL);
12116 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012117 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012118 goto error;
12119 }
12120 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012121 /*
12122 * Traverse the axis and test the nodes.
12123 */
12124 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012125 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012126 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012127 do {
12128 cur = next(ctxt, cur);
12129 if (cur == NULL)
12130 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012131
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012132 /*
12133 * QUESTION TODO: What does the "first" and "last" stuff do?
12134 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012135 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012136 if (*first == cur)
12137 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012138 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012139#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012140 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012141#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012142 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012143#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012144 {
12145 break;
12146 }
12147 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012148 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012149 if (*last == cur)
12150 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012151 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012152#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012153 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012154#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012155 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012156#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012157 {
12158 break;
12159 }
12160 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012161
12162 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012163
Daniel Veillardf06307e2001-07-03 10:35:50 +000012164#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012165 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12166#endif
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012167
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012168 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012169 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012170 total = 0;
12171 STRANGE
12172 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012173 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012174 /*
12175 * TODO: Don't we need to use
12176 * xmlXPathNodeSetAddNs() for namespace nodes here?
12177 * Surprisingly, some c14n tests fail, if we do this.
12178 */
12179 if (type == NODE_TYPE_NODE) {
12180 switch (cur->type) {
12181 case XML_DOCUMENT_NODE:
12182 case XML_HTML_DOCUMENT_NODE:
12183#ifdef LIBXML_DOCB_ENABLED
12184 case XML_DOCB_DOCUMENT_NODE:
12185#endif
12186 case XML_ELEMENT_NODE:
12187 case XML_ATTRIBUTE_NODE:
12188 case XML_PI_NODE:
12189 case XML_COMMENT_NODE:
12190 case XML_CDATA_SECTION_NODE:
12191 case XML_TEXT_NODE:
12192 case XML_NAMESPACE_DECL:
12193 XP_TEST_HIT
12194 break;
12195 default:
12196 break;
12197 }
12198 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012199 if (type == XML_NAMESPACE_DECL)
12200 XP_TEST_HIT_NS
12201 else
12202 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012203 } else if ((type == NODE_TYPE_TEXT) &&
12204 (cur->type == XML_CDATA_SECTION_NODE))
12205 {
12206 XP_TEST_HIT
12207 }
12208 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012209 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012210 if ((cur->type == XML_PI_NODE) &&
12211 ((name == NULL) || xmlStrEqual(name, cur->name)))
12212 {
12213 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012214 }
12215 break;
12216 case NODE_TEST_ALL:
12217 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012218 if (cur->type == XML_ATTRIBUTE_NODE)
12219 {
12220 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012221 }
12222 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012223 if (cur->type == XML_NAMESPACE_DECL)
12224 {
12225 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012226 }
12227 } else {
12228 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012229 if (prefix == NULL)
12230 {
12231 XP_TEST_HIT
12232
Daniel Veillardf06307e2001-07-03 10:35:50 +000012233 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012234 (xmlStrEqual(URI, cur->ns->href)))
12235 {
12236 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012237 }
12238 }
12239 }
12240 break;
12241 case NODE_TEST_NS:{
12242 TODO;
12243 break;
12244 }
12245 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012246 if (axis == AXIS_ATTRIBUTE) {
12247 if (cur->type != XML_ATTRIBUTE_NODE)
12248 break;
12249 } else if (axis == AXIS_NAMESPACE) {
12250 if (cur->type != XML_NAMESPACE_DECL)
12251 break;
12252 } else {
12253 if (cur->type != XML_ELEMENT_NODE)
12254 break;
12255 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012256 switch (cur->type) {
12257 case XML_ELEMENT_NODE:
12258 if (xmlStrEqual(name, cur->name)) {
12259 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012260 if (cur->ns == NULL)
12261 {
12262 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012263 }
12264 } else {
12265 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012266 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012267 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012268 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012269 }
12270 }
12271 }
12272 break;
12273 case XML_ATTRIBUTE_NODE:{
12274 xmlAttrPtr attr = (xmlAttrPtr) cur;
12275
12276 if (xmlStrEqual(name, attr->name)) {
12277 if (prefix == NULL) {
12278 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012279 (attr->ns->prefix == NULL))
12280 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012281 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012282 }
12283 } else {
12284 if ((attr->ns != NULL) &&
12285 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012286 attr->ns->href)))
12287 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012288 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012289 }
12290 }
12291 }
12292 break;
12293 }
12294 case XML_NAMESPACE_DECL:
12295 if (cur->type == XML_NAMESPACE_DECL) {
12296 xmlNsPtr ns = (xmlNsPtr) cur;
12297
12298 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012299 && (xmlStrEqual(ns->prefix, name)))
12300 {
12301 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012302 }
12303 }
12304 break;
12305 default:
12306 break;
12307 }
12308 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012309 } /* switch(test) */
12310 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012311
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012312 goto apply_predicates;
12313
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012314axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012315 /*
12316 * We have a "/foo[n]", and position() = n was reached.
12317 * Note that we can have as well "/foo/::parent::foo[1]", so
12318 * a duplicate-aware merge is still needed.
12319 * Merge with the result.
12320 */
12321 if (outSeq == NULL) {
12322 outSeq = seq;
12323 seq = NULL;
12324 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012325 outSeq = mergeAndClear(outSeq, seq, 0);
12326 /*
12327 * Break if only a true/false result was requested.
12328 */
12329 if (toBool)
12330 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012331 continue;
12332
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012333first_hit: /* ---------------------------------------------------------- */
12334 /*
12335 * Break if only a true/false result was requested and
12336 * no predicates existed and a node test succeeded.
12337 */
12338 if (outSeq == NULL) {
12339 outSeq = seq;
12340 seq = NULL;
12341 } else
12342 outSeq = mergeAndClear(outSeq, seq, 0);
12343 break;
12344
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012345#ifdef DEBUG_STEP
12346 if (seq != NULL)
12347 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012348#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012349
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012350apply_predicates: /* --------------------------------------------------- */
12351 /*
12352 * Apply predicates.
12353 */
12354 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12355 /*
12356 * E.g. when we have a "/foo[some expression][n]".
12357 */
12358 /*
12359 * QUESTION TODO: The old predicate evaluation took into
12360 * account location-sets.
12361 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12362 * Do we expect such a set here?
12363 * All what I learned now from the evaluation semantics
12364 * does not indicate that a location-set will be processed
12365 * here, so this looks OK.
12366 */
12367 /*
12368 * Iterate over all predicates, starting with the outermost
12369 * predicate.
12370 * TODO: Problem: we cannot execute the inner predicates first
12371 * since we cannot go back *up* the operator tree!
12372 * Options we have:
12373 * 1) Use of recursive functions (like is it currently done
12374 * via xmlXPathCompOpEval())
12375 * 2) Add a predicate evaluation information stack to the
12376 * context struct
12377 * 3) Change the way the operators are linked; we need a
12378 * "parent" field on xmlXPathStepOp
12379 *
12380 * For the moment, I'll try to solve this with a recursive
12381 * function: xmlXPathCompOpEvalPredicate().
12382 */
12383 size = seq->nodeNr;
12384 if (hasPredicateRange != 0)
12385 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12386 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12387 else
12388 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12389 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012390
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012391 if (ctxt->error != XPATH_EXPRESSION_OK) {
12392 total = 0;
12393 goto error;
12394 }
12395 /*
12396 * Add the filtered set of nodes to the result node set.
12397 */
12398 if (newSize == 0) {
12399 /*
12400 * The predicates filtered all nodes out.
12401 */
12402 xmlXPathNodeSetClear(seq, hasNsNodes);
12403 } else if (seq->nodeNr > 0) {
12404 /*
12405 * Add to result set.
12406 */
12407 if (outSeq == NULL) {
12408 if (size != newSize) {
12409 /*
12410 * We need to merge and clear here, since
12411 * the sequence will contained NULLed entries.
12412 */
12413 outSeq = mergeAndClear(NULL, seq, 1);
12414 } else {
12415 outSeq = seq;
12416 seq = NULL;
12417 }
12418 } else
12419 outSeq = mergeAndClear(outSeq, seq,
12420 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012421 /*
12422 * Break if only a true/false result was requested.
12423 */
12424 if (toBool)
12425 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012426 }
12427 } else if (seq->nodeNr > 0) {
12428 /*
12429 * Add to result set.
12430 */
12431 if (outSeq == NULL) {
12432 outSeq = seq;
12433 seq = NULL;
12434 } else {
12435 outSeq = mergeAndClear(outSeq, seq, 0);
12436 }
12437 }
12438 }
12439
12440error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012441 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012442 /*
12443 * QUESTION TODO: What does this do and why?
12444 * TODO: Do we have to do this also for the "error"
12445 * cleanup further down?
12446 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012447 ctxt->value->boolval = 1;
12448 ctxt->value->user = obj->user;
12449 obj->user = NULL;
12450 obj->boolval = 0;
12451 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012452 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012453
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012454 /*
12455 * Ensure we return at least an emtpy set.
12456 */
12457 if (outSeq == NULL) {
12458 if ((seq != NULL) && (seq->nodeNr == 0))
12459 outSeq = seq;
12460 else
12461 outSeq = xmlXPathNodeSetCreate(NULL);
12462 }
12463 if ((seq != NULL) && (seq != outSeq)) {
12464 xmlXPathFreeNodeSet(seq);
12465 }
12466 /*
12467 * Hand over the result. Better to push the set also in
12468 * case of errors.
12469 */
12470 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12471 /*
12472 * Reset the context node.
12473 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012474 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012475
12476#ifdef DEBUG_STEP
12477 xmlGenericError(xmlGenericErrorContext,
12478 "\nExamined %d nodes, found %d nodes at that step\n",
12479 total, nbMatches);
12480#endif
12481
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012482 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012483}
12484
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012485static int
12486xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12487 xmlXPathStepOpPtr op, xmlNodePtr * first);
12488
Daniel Veillardf06307e2001-07-03 10:35:50 +000012489/**
12490 * xmlXPathCompOpEvalFirst:
12491 * @ctxt: the XPath parser context with the compiled expression
12492 * @op: an XPath compiled operation
12493 * @first: the first elem found so far
12494 *
12495 * Evaluate the Precompiled XPath operation searching only the first
12496 * element in document order
12497 *
12498 * Returns the number of examined objects.
12499 */
12500static int
12501xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12502 xmlXPathStepOpPtr op, xmlNodePtr * first)
12503{
12504 int total = 0, cur;
12505 xmlXPathCompExprPtr comp;
12506 xmlXPathObjectPtr arg1, arg2;
12507
Daniel Veillard556c6682001-10-06 09:59:51 +000012508 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012509 comp = ctxt->comp;
12510 switch (op->op) {
12511 case XPATH_OP_END:
12512 return (0);
12513 case XPATH_OP_UNION:
12514 total =
12515 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12516 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012517 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012518 if ((ctxt->value != NULL)
12519 && (ctxt->value->type == XPATH_NODESET)
12520 && (ctxt->value->nodesetval != NULL)
12521 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12522 /*
12523 * limit tree traversing to first node in the result
12524 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012525 /*
12526 * OPTIMIZE TODO: This implicitely sorts
12527 * the result, even if not needed. E.g. if the argument
12528 * of the count() function, no sorting is needed.
12529 * OPTIMIZE TODO: How do we know if the node-list wasn't
12530 * aready sorted?
12531 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012532 if (ctxt->value->nodesetval->nodeNr > 1)
12533 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012534 *first = ctxt->value->nodesetval->nodeTab[0];
12535 }
12536 cur =
12537 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12538 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012539 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012540 CHECK_TYPE0(XPATH_NODESET);
12541 arg2 = valuePop(ctxt);
12542
12543 CHECK_TYPE0(XPATH_NODESET);
12544 arg1 = valuePop(ctxt);
12545
12546 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12547 arg2->nodesetval);
12548 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012549 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012550 /* optimizer */
12551 if (total > cur)
12552 xmlXPathCompSwap(op);
12553 return (total + cur);
12554 case XPATH_OP_ROOT:
12555 xmlXPathRoot(ctxt);
12556 return (0);
12557 case XPATH_OP_NODE:
12558 if (op->ch1 != -1)
12559 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012560 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012561 if (op->ch2 != -1)
12562 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012563 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012564 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12565 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012566 return (total);
12567 case XPATH_OP_RESET:
12568 if (op->ch1 != -1)
12569 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012570 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012571 if (op->ch2 != -1)
12572 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012573 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012574 ctxt->context->node = NULL;
12575 return (total);
12576 case XPATH_OP_COLLECT:{
12577 if (op->ch1 == -1)
12578 return (total);
12579
12580 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012581 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012582
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012583 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012584 return (total);
12585 }
12586 case XPATH_OP_VALUE:
12587 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012588 xmlXPathCacheObjectCopy(ctxt->context,
12589 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012590 return (0);
12591 case XPATH_OP_SORT:
12592 if (op->ch1 != -1)
12593 total +=
12594 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12595 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012596 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012597 if ((ctxt->value != NULL)
12598 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012599 && (ctxt->value->nodesetval != NULL)
12600 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012601 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12602 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012603#ifdef XP_OPTIMIZED_FILTER_FIRST
12604 case XPATH_OP_FILTER:
12605 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12606 return (total);
12607#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012608 default:
12609 return (xmlXPathCompOpEval(ctxt, op));
12610 }
12611}
12612
12613/**
12614 * xmlXPathCompOpEvalLast:
12615 * @ctxt: the XPath parser context with the compiled expression
12616 * @op: an XPath compiled operation
12617 * @last: the last elem found so far
12618 *
12619 * Evaluate the Precompiled XPath operation searching only the last
12620 * element in document order
12621 *
William M. Brack08171912003-12-29 02:52:11 +000012622 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012623 */
12624static int
12625xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12626 xmlNodePtr * last)
12627{
12628 int total = 0, cur;
12629 xmlXPathCompExprPtr comp;
12630 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012631 xmlNodePtr bak;
12632 xmlDocPtr bakd;
12633 int pp;
12634 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012635
Daniel Veillard556c6682001-10-06 09:59:51 +000012636 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012637 comp = ctxt->comp;
12638 switch (op->op) {
12639 case XPATH_OP_END:
12640 return (0);
12641 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012642 bakd = ctxt->context->doc;
12643 bak = ctxt->context->node;
12644 pp = ctxt->context->proximityPosition;
12645 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012646 total =
12647 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012648 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012649 if ((ctxt->value != NULL)
12650 && (ctxt->value->type == XPATH_NODESET)
12651 && (ctxt->value->nodesetval != NULL)
12652 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12653 /*
12654 * limit tree traversing to first node in the result
12655 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012656 if (ctxt->value->nodesetval->nodeNr > 1)
12657 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012658 *last =
12659 ctxt->value->nodesetval->nodeTab[ctxt->value->
12660 nodesetval->nodeNr -
12661 1];
12662 }
William M. Brackce4fc562004-01-22 02:47:18 +000012663 ctxt->context->doc = bakd;
12664 ctxt->context->node = bak;
12665 ctxt->context->proximityPosition = pp;
12666 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012667 cur =
12668 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012669 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012670 if ((ctxt->value != NULL)
12671 && (ctxt->value->type == XPATH_NODESET)
12672 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012673 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012674 }
12675 CHECK_TYPE0(XPATH_NODESET);
12676 arg2 = valuePop(ctxt);
12677
12678 CHECK_TYPE0(XPATH_NODESET);
12679 arg1 = valuePop(ctxt);
12680
12681 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12682 arg2->nodesetval);
12683 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012684 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 /* optimizer */
12686 if (total > cur)
12687 xmlXPathCompSwap(op);
12688 return (total + cur);
12689 case XPATH_OP_ROOT:
12690 xmlXPathRoot(ctxt);
12691 return (0);
12692 case XPATH_OP_NODE:
12693 if (op->ch1 != -1)
12694 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012695 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012696 if (op->ch2 != -1)
12697 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012698 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012699 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12700 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012701 return (total);
12702 case XPATH_OP_RESET:
12703 if (op->ch1 != -1)
12704 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012706 if (op->ch2 != -1)
12707 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 ctxt->context->node = NULL;
12710 return (total);
12711 case XPATH_OP_COLLECT:{
12712 if (op->ch1 == -1)
12713 return (0);
12714
12715 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012716 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012717
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012718 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012719 return (total);
12720 }
12721 case XPATH_OP_VALUE:
12722 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012723 xmlXPathCacheObjectCopy(ctxt->context,
12724 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012725 return (0);
12726 case XPATH_OP_SORT:
12727 if (op->ch1 != -1)
12728 total +=
12729 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12730 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012731 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012732 if ((ctxt->value != NULL)
12733 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012734 && (ctxt->value->nodesetval != NULL)
12735 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012736 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12737 return (total);
12738 default:
12739 return (xmlXPathCompOpEval(ctxt, op));
12740 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012741}
12742
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012743#ifdef XP_OPTIMIZED_FILTER_FIRST
12744static int
12745xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12746 xmlXPathStepOpPtr op, xmlNodePtr * first)
12747{
12748 int total = 0;
12749 xmlXPathCompExprPtr comp;
12750 xmlXPathObjectPtr res;
12751 xmlXPathObjectPtr obj;
12752 xmlNodeSetPtr oldset;
12753 xmlNodePtr oldnode;
12754 xmlDocPtr oldDoc;
12755 int i;
12756
12757 CHECK_ERROR0;
12758 comp = ctxt->comp;
12759 /*
12760 * Optimization for ()[last()] selection i.e. the last elem
12761 */
12762 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12763 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12764 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12765 int f = comp->steps[op->ch2].ch1;
12766
12767 if ((f != -1) &&
12768 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12769 (comp->steps[f].value5 == NULL) &&
12770 (comp->steps[f].value == 0) &&
12771 (comp->steps[f].value4 != NULL) &&
12772 (xmlStrEqual
12773 (comp->steps[f].value4, BAD_CAST "last"))) {
12774 xmlNodePtr last = NULL;
12775
12776 total +=
12777 xmlXPathCompOpEvalLast(ctxt,
12778 &comp->steps[op->ch1],
12779 &last);
12780 CHECK_ERROR0;
12781 /*
12782 * The nodeset should be in document order,
12783 * Keep only the last value
12784 */
12785 if ((ctxt->value != NULL) &&
12786 (ctxt->value->type == XPATH_NODESET) &&
12787 (ctxt->value->nodesetval != NULL) &&
12788 (ctxt->value->nodesetval->nodeTab != NULL) &&
12789 (ctxt->value->nodesetval->nodeNr > 1)) {
12790 ctxt->value->nodesetval->nodeTab[0] =
12791 ctxt->value->nodesetval->nodeTab[ctxt->
12792 value->
12793 nodesetval->
12794 nodeNr -
12795 1];
12796 ctxt->value->nodesetval->nodeNr = 1;
12797 *first = *(ctxt->value->nodesetval->nodeTab);
12798 }
12799 return (total);
12800 }
12801 }
12802
12803 if (op->ch1 != -1)
12804 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12805 CHECK_ERROR0;
12806 if (op->ch2 == -1)
12807 return (total);
12808 if (ctxt->value == NULL)
12809 return (total);
12810
12811#ifdef LIBXML_XPTR_ENABLED
12812 oldnode = ctxt->context->node;
12813 /*
12814 * Hum are we filtering the result of an XPointer expression
12815 */
12816 if (ctxt->value->type == XPATH_LOCATIONSET) {
12817 xmlXPathObjectPtr tmp = NULL;
12818 xmlLocationSetPtr newlocset = NULL;
12819 xmlLocationSetPtr oldlocset;
12820
12821 /*
12822 * Extract the old locset, and then evaluate the result of the
12823 * expression for all the element in the locset. use it to grow
12824 * up a new locset.
12825 */
12826 CHECK_TYPE0(XPATH_LOCATIONSET);
12827 obj = valuePop(ctxt);
12828 oldlocset = obj->user;
12829 ctxt->context->node = NULL;
12830
12831 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12832 ctxt->context->contextSize = 0;
12833 ctxt->context->proximityPosition = 0;
12834 if (op->ch2 != -1)
12835 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12836 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012837 if (res != NULL) {
12838 xmlXPathReleaseObject(ctxt->context, res);
12839 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012840 valuePush(ctxt, obj);
12841 CHECK_ERROR0;
12842 return (total);
12843 }
12844 newlocset = xmlXPtrLocationSetCreate(NULL);
12845
12846 for (i = 0; i < oldlocset->locNr; i++) {
12847 /*
12848 * Run the evaluation with a node list made of a
12849 * single item in the nodelocset.
12850 */
12851 ctxt->context->node = oldlocset->locTab[i]->user;
12852 ctxt->context->contextSize = oldlocset->locNr;
12853 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012854 if (tmp == NULL) {
12855 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12856 ctxt->context->node);
12857 } else {
12858 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12859 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012860 }
12861 valuePush(ctxt, tmp);
12862 if (op->ch2 != -1)
12863 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12864 if (ctxt->error != XPATH_EXPRESSION_OK) {
12865 xmlXPathFreeObject(obj);
12866 return(0);
12867 }
12868 /*
12869 * The result of the evaluation need to be tested to
12870 * decided whether the filter succeeded or not
12871 */
12872 res = valuePop(ctxt);
12873 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12874 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012875 xmlXPathCacheObjectCopy(ctxt->context,
12876 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012877 }
12878 /*
12879 * Cleanup
12880 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012881 if (res != NULL) {
12882 xmlXPathReleaseObject(ctxt->context, res);
12883 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012884 if (ctxt->value == tmp) {
12885 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012886 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012887 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012888 * REVISIT TODO: Don't create a temporary nodeset
12889 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012890 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012891 /* OLD: xmlXPathFreeObject(res); */
12892 } else
12893 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012894 ctxt->context->node = NULL;
12895 /*
12896 * Only put the first node in the result, then leave.
12897 */
12898 if (newlocset->locNr > 0) {
12899 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12900 break;
12901 }
12902 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012903 if (tmp != NULL) {
12904 xmlXPathReleaseObject(ctxt->context, tmp);
12905 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012906 /*
12907 * The result is used as the new evaluation locset.
12908 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012909 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012910 ctxt->context->node = NULL;
12911 ctxt->context->contextSize = -1;
12912 ctxt->context->proximityPosition = -1;
12913 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12914 ctxt->context->node = oldnode;
12915 return (total);
12916 }
12917#endif /* LIBXML_XPTR_ENABLED */
12918
12919 /*
12920 * Extract the old set, and then evaluate the result of the
12921 * expression for all the element in the set. use it to grow
12922 * up a new set.
12923 */
12924 CHECK_TYPE0(XPATH_NODESET);
12925 obj = valuePop(ctxt);
12926 oldset = obj->nodesetval;
12927
12928 oldnode = ctxt->context->node;
12929 oldDoc = ctxt->context->doc;
12930 ctxt->context->node = NULL;
12931
12932 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12933 ctxt->context->contextSize = 0;
12934 ctxt->context->proximityPosition = 0;
12935 /* QUESTION TODO: Why was this code commented out?
12936 if (op->ch2 != -1)
12937 total +=
12938 xmlXPathCompOpEval(ctxt,
12939 &comp->steps[op->ch2]);
12940 CHECK_ERROR0;
12941 res = valuePop(ctxt);
12942 if (res != NULL)
12943 xmlXPathFreeObject(res);
12944 */
12945 valuePush(ctxt, obj);
12946 ctxt->context->node = oldnode;
12947 CHECK_ERROR0;
12948 } else {
12949 xmlNodeSetPtr newset;
12950 xmlXPathObjectPtr tmp = NULL;
12951 /*
12952 * Initialize the new set.
12953 * Also set the xpath document in case things like
12954 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012955 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012956 newset = xmlXPathNodeSetCreate(NULL);
12957
12958 for (i = 0; i < oldset->nodeNr; i++) {
12959 /*
12960 * Run the evaluation with a node list made of
12961 * a single item in the nodeset.
12962 */
12963 ctxt->context->node = oldset->nodeTab[i];
12964 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12965 (oldset->nodeTab[i]->doc != NULL))
12966 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012967 if (tmp == NULL) {
12968 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12969 ctxt->context->node);
12970 } else {
12971 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12972 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012973 }
12974 valuePush(ctxt, tmp);
12975 ctxt->context->contextSize = oldset->nodeNr;
12976 ctxt->context->proximityPosition = i + 1;
12977 if (op->ch2 != -1)
12978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12979 if (ctxt->error != XPATH_EXPRESSION_OK) {
12980 xmlXPathFreeNodeSet(newset);
12981 xmlXPathFreeObject(obj);
12982 return(0);
12983 }
12984 /*
12985 * The result of the evaluation needs to be tested to
12986 * decide whether the filter succeeded or not
12987 */
12988 res = valuePop(ctxt);
12989 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12990 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12991 }
12992 /*
12993 * Cleanup
12994 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012995 if (res != NULL) {
12996 xmlXPathReleaseObject(ctxt->context, res);
12997 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012998 if (ctxt->value == tmp) {
12999 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013000 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013001 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013002 * in order to avoid massive recreation inside this
13003 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013004 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013005 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013006 } else
13007 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013008 ctxt->context->node = NULL;
13009 /*
13010 * Only put the first node in the result, then leave.
13011 */
13012 if (newset->nodeNr > 0) {
13013 *first = *(newset->nodeTab);
13014 break;
13015 }
13016 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013017 if (tmp != NULL) {
13018 xmlXPathReleaseObject(ctxt->context, tmp);
13019 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013020 /*
13021 * The result is used as the new evaluation set.
13022 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013023 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013024 ctxt->context->node = NULL;
13025 ctxt->context->contextSize = -1;
13026 ctxt->context->proximityPosition = -1;
13027 /* may want to move this past the '}' later */
13028 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013029 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013030 }
13031 ctxt->context->node = oldnode;
13032 return(total);
13033}
13034#endif /* XP_OPTIMIZED_FILTER_FIRST */
13035
Owen Taylor3473f882001-02-23 17:55:21 +000013036/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013037 * xmlXPathCompOpEval:
13038 * @ctxt: the XPath parser context with the compiled expression
13039 * @op: an XPath compiled operation
13040 *
13041 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013042 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013043 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013044static int
13045xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13046{
13047 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013048 int equal, ret;
13049 xmlXPathCompExprPtr comp;
13050 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013051 xmlNodePtr bak;
13052 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013053 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013054 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013055
Daniel Veillard556c6682001-10-06 09:59:51 +000013056 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013057 comp = ctxt->comp;
13058 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013059 case XPATH_OP_END:
13060 return (0);
13061 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013062 bakd = ctxt->context->doc;
13063 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013064 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013065 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013066 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013067 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013068 xmlXPathBooleanFunction(ctxt, 1);
13069 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13070 return (total);
13071 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013072 ctxt->context->doc = bakd;
13073 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013074 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013075 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013076 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013077 if (ctxt->error) {
13078 xmlXPathFreeObject(arg2);
13079 return(0);
13080 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013081 xmlXPathBooleanFunction(ctxt, 1);
13082 arg1 = valuePop(ctxt);
13083 arg1->boolval &= arg2->boolval;
13084 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013085 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013086 return (total);
13087 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013088 bakd = ctxt->context->doc;
13089 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013090 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013091 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013092 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013093 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013094 xmlXPathBooleanFunction(ctxt, 1);
13095 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13096 return (total);
13097 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013098 ctxt->context->doc = bakd;
13099 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013100 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013101 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013102 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013103 if (ctxt->error) {
13104 xmlXPathFreeObject(arg2);
13105 return(0);
13106 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013107 xmlXPathBooleanFunction(ctxt, 1);
13108 arg1 = valuePop(ctxt);
13109 arg1->boolval |= arg2->boolval;
13110 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013111 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013112 return (total);
13113 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013114 bakd = ctxt->context->doc;
13115 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013116 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013117 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013118 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013119 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013120 ctxt->context->doc = bakd;
13121 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013122 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013123 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013124 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013125 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013126 if (op->value)
13127 equal = xmlXPathEqualValues(ctxt);
13128 else
13129 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013130 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013131 return (total);
13132 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013133 bakd = ctxt->context->doc;
13134 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013135 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013136 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013137 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013138 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013139 ctxt->context->doc = bakd;
13140 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013141 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013142 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013144 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013145 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013146 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013147 return (total);
13148 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013149 bakd = ctxt->context->doc;
13150 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013151 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013152 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013153 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013154 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013155 if (op->ch2 != -1) {
13156 ctxt->context->doc = bakd;
13157 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013158 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013159 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013160 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013161 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013162 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013163 if (op->value == 0)
13164 xmlXPathSubValues(ctxt);
13165 else if (op->value == 1)
13166 xmlXPathAddValues(ctxt);
13167 else if (op->value == 2)
13168 xmlXPathValueFlipSign(ctxt);
13169 else if (op->value == 3) {
13170 CAST_TO_NUMBER;
13171 CHECK_TYPE0(XPATH_NUMBER);
13172 }
13173 return (total);
13174 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013175 bakd = ctxt->context->doc;
13176 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013177 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013178 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013179 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013180 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013181 ctxt->context->doc = bakd;
13182 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013183 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013184 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013185 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013186 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013187 if (op->value == 0)
13188 xmlXPathMultValues(ctxt);
13189 else if (op->value == 1)
13190 xmlXPathDivValues(ctxt);
13191 else if (op->value == 2)
13192 xmlXPathModValues(ctxt);
13193 return (total);
13194 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013195 bakd = ctxt->context->doc;
13196 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013197 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013198 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013199 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013200 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013201 ctxt->context->doc = bakd;
13202 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013203 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013204 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013205 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013206 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013207 CHECK_TYPE0(XPATH_NODESET);
13208 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013209
Daniel Veillardf06307e2001-07-03 10:35:50 +000013210 CHECK_TYPE0(XPATH_NODESET);
13211 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013212
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013213 if ((arg1->nodesetval == NULL) ||
13214 ((arg2->nodesetval != NULL) &&
13215 (arg2->nodesetval->nodeNr != 0)))
13216 {
13217 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13218 arg2->nodesetval);
13219 }
13220
Daniel Veillardf06307e2001-07-03 10:35:50 +000013221 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013222 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013223 return (total);
13224 case XPATH_OP_ROOT:
13225 xmlXPathRoot(ctxt);
13226 return (total);
13227 case XPATH_OP_NODE:
13228 if (op->ch1 != -1)
13229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013230 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013231 if (op->ch2 != -1)
13232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013233 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013234 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13235 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 return (total);
13237 case XPATH_OP_RESET:
13238 if (op->ch1 != -1)
13239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013240 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013241 if (op->ch2 != -1)
13242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013243 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013244 ctxt->context->node = NULL;
13245 return (total);
13246 case XPATH_OP_COLLECT:{
13247 if (op->ch1 == -1)
13248 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013249
Daniel Veillardf06307e2001-07-03 10:35:50 +000013250 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013251 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013252
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013253 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013254 return (total);
13255 }
13256 case XPATH_OP_VALUE:
13257 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013258 xmlXPathCacheObjectCopy(ctxt->context,
13259 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 return (total);
13261 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013262 xmlXPathObjectPtr val;
13263
Daniel Veillardf06307e2001-07-03 10:35:50 +000013264 if (op->ch1 != -1)
13265 total +=
13266 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013267 if (op->value5 == NULL) {
13268 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13269 if (val == NULL) {
13270 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13271 return(0);
13272 }
13273 valuePush(ctxt, val);
13274 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013275 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013276
Daniel Veillardf06307e2001-07-03 10:35:50 +000013277 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13278 if (URI == NULL) {
13279 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013280 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 op->value4, op->value5);
13282 return (total);
13283 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013284 val = xmlXPathVariableLookupNS(ctxt->context,
13285 op->value4, URI);
13286 if (val == NULL) {
13287 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13288 return(0);
13289 }
13290 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013291 }
13292 return (total);
13293 }
13294 case XPATH_OP_FUNCTION:{
13295 xmlXPathFunction func;
13296 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013297 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013298
13299 if (op->ch1 != -1)
13300 total +=
13301 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013302 if (ctxt->valueNr < op->value) {
13303 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013304 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013305 ctxt->error = XPATH_INVALID_OPERAND;
13306 return (total);
13307 }
13308 for (i = 0; i < op->value; i++)
13309 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13310 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013311 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013312 ctxt->error = XPATH_INVALID_OPERAND;
13313 return (total);
13314 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013315 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013316 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013317 else {
13318 const xmlChar *URI = NULL;
13319
13320 if (op->value5 == NULL)
13321 func =
13322 xmlXPathFunctionLookup(ctxt->context,
13323 op->value4);
13324 else {
13325 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13326 if (URI == NULL) {
13327 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013328 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013329 op->value4, op->value5);
13330 return (total);
13331 }
13332 func = xmlXPathFunctionLookupNS(ctxt->context,
13333 op->value4, URI);
13334 }
13335 if (func == NULL) {
13336 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013337 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013338 op->value4);
13339 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013340 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013341 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013342 op->cacheURI = (void *) URI;
13343 }
13344 oldFunc = ctxt->context->function;
13345 oldFuncURI = ctxt->context->functionURI;
13346 ctxt->context->function = op->value4;
13347 ctxt->context->functionURI = op->cacheURI;
13348 func(ctxt, op->value);
13349 ctxt->context->function = oldFunc;
13350 ctxt->context->functionURI = oldFuncURI;
13351 return (total);
13352 }
13353 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013354 bakd = ctxt->context->doc;
13355 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013356 pp = ctxt->context->proximityPosition;
13357 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013358 if (op->ch1 != -1)
13359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013360 ctxt->context->contextSize = cs;
13361 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013362 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013363 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013364 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013365 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013367 ctxt->context->doc = bakd;
13368 ctxt->context->node = bak;
13369 CHECK_ERROR0;
13370 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013371 return (total);
13372 case XPATH_OP_PREDICATE:
13373 case XPATH_OP_FILTER:{
13374 xmlXPathObjectPtr res;
13375 xmlXPathObjectPtr obj, tmp;
13376 xmlNodeSetPtr newset = NULL;
13377 xmlNodeSetPtr oldset;
13378 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013379 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013380 int i;
13381
13382 /*
13383 * Optimization for ()[1] selection i.e. the first elem
13384 */
13385 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013386#ifdef XP_OPTIMIZED_FILTER_FIRST
13387 /*
13388 * FILTER TODO: Can we assume that the inner processing
13389 * will result in an ordered list if we have an
13390 * XPATH_OP_FILTER?
13391 * What about an additional field or flag on
13392 * xmlXPathObject like @sorted ? This way we wouln'd need
13393 * to assume anything, so it would be more robust and
13394 * easier to optimize.
13395 */
13396 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13397 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13398#else
13399 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13400#endif
13401 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013402 xmlXPathObjectPtr val;
13403
13404 val = comp->steps[op->ch2].value4;
13405 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13406 (val->floatval == 1.0)) {
13407 xmlNodePtr first = NULL;
13408
13409 total +=
13410 xmlXPathCompOpEvalFirst(ctxt,
13411 &comp->steps[op->ch1],
13412 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013413 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013414 /*
13415 * The nodeset should be in document order,
13416 * Keep only the first value
13417 */
13418 if ((ctxt->value != NULL) &&
13419 (ctxt->value->type == XPATH_NODESET) &&
13420 (ctxt->value->nodesetval != NULL) &&
13421 (ctxt->value->nodesetval->nodeNr > 1))
13422 ctxt->value->nodesetval->nodeNr = 1;
13423 return (total);
13424 }
13425 }
13426 /*
13427 * Optimization for ()[last()] selection i.e. the last elem
13428 */
13429 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13430 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13431 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13432 int f = comp->steps[op->ch2].ch1;
13433
13434 if ((f != -1) &&
13435 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13436 (comp->steps[f].value5 == NULL) &&
13437 (comp->steps[f].value == 0) &&
13438 (comp->steps[f].value4 != NULL) &&
13439 (xmlStrEqual
13440 (comp->steps[f].value4, BAD_CAST "last"))) {
13441 xmlNodePtr last = NULL;
13442
13443 total +=
13444 xmlXPathCompOpEvalLast(ctxt,
13445 &comp->steps[op->ch1],
13446 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013447 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013448 /*
13449 * The nodeset should be in document order,
13450 * Keep only the last value
13451 */
13452 if ((ctxt->value != NULL) &&
13453 (ctxt->value->type == XPATH_NODESET) &&
13454 (ctxt->value->nodesetval != NULL) &&
13455 (ctxt->value->nodesetval->nodeTab != NULL) &&
13456 (ctxt->value->nodesetval->nodeNr > 1)) {
13457 ctxt->value->nodesetval->nodeTab[0] =
13458 ctxt->value->nodesetval->nodeTab[ctxt->
13459 value->
13460 nodesetval->
13461 nodeNr -
13462 1];
13463 ctxt->value->nodesetval->nodeNr = 1;
13464 }
13465 return (total);
13466 }
13467 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013468 /*
13469 * Process inner predicates first.
13470 * Example "index[parent::book][1]":
13471 * ...
13472 * PREDICATE <-- we are here "[1]"
13473 * PREDICATE <-- process "[parent::book]" first
13474 * SORT
13475 * COLLECT 'parent' 'name' 'node' book
13476 * NODE
13477 * ELEM Object is a number : 1
13478 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013479 if (op->ch1 != -1)
13480 total +=
13481 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013482 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013483 if (op->ch2 == -1)
13484 return (total);
13485 if (ctxt->value == NULL)
13486 return (total);
13487
13488 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013489
13490#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013491 /*
13492 * Hum are we filtering the result of an XPointer expression
13493 */
13494 if (ctxt->value->type == XPATH_LOCATIONSET) {
13495 xmlLocationSetPtr newlocset = NULL;
13496 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013497
Daniel Veillardf06307e2001-07-03 10:35:50 +000013498 /*
13499 * Extract the old locset, and then evaluate the result of the
13500 * expression for all the element in the locset. use it to grow
13501 * up a new locset.
13502 */
13503 CHECK_TYPE0(XPATH_LOCATIONSET);
13504 obj = valuePop(ctxt);
13505 oldlocset = obj->user;
13506 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013507
Daniel Veillardf06307e2001-07-03 10:35:50 +000013508 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13509 ctxt->context->contextSize = 0;
13510 ctxt->context->proximityPosition = 0;
13511 if (op->ch2 != -1)
13512 total +=
13513 xmlXPathCompOpEval(ctxt,
13514 &comp->steps[op->ch2]);
13515 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013516 if (res != NULL) {
13517 xmlXPathReleaseObject(ctxt->context, res);
13518 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013519 valuePush(ctxt, obj);
13520 CHECK_ERROR0;
13521 return (total);
13522 }
13523 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013524
Daniel Veillardf06307e2001-07-03 10:35:50 +000013525 for (i = 0; i < oldlocset->locNr; i++) {
13526 /*
13527 * Run the evaluation with a node list made of a
13528 * single item in the nodelocset.
13529 */
13530 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013531 ctxt->context->contextSize = oldlocset->locNr;
13532 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013533 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13534 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013535 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013536
Daniel Veillardf06307e2001-07-03 10:35:50 +000013537 if (op->ch2 != -1)
13538 total +=
13539 xmlXPathCompOpEval(ctxt,
13540 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013541 if (ctxt->error != XPATH_EXPRESSION_OK) {
13542 xmlXPathFreeObject(obj);
13543 return(0);
13544 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013545
Daniel Veillardf06307e2001-07-03 10:35:50 +000013546 /*
13547 * The result of the evaluation need to be tested to
13548 * decided whether the filter succeeded or not
13549 */
13550 res = valuePop(ctxt);
13551 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13552 xmlXPtrLocationSetAdd(newlocset,
13553 xmlXPathObjectCopy
13554 (oldlocset->locTab[i]));
13555 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013556
Daniel Veillardf06307e2001-07-03 10:35:50 +000013557 /*
13558 * Cleanup
13559 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013560 if (res != NULL) {
13561 xmlXPathReleaseObject(ctxt->context, res);
13562 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013563 if (ctxt->value == tmp) {
13564 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013565 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013566 }
13567
13568 ctxt->context->node = NULL;
13569 }
13570
13571 /*
13572 * The result is used as the new evaluation locset.
13573 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013574 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013575 ctxt->context->node = NULL;
13576 ctxt->context->contextSize = -1;
13577 ctxt->context->proximityPosition = -1;
13578 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13579 ctxt->context->node = oldnode;
13580 return (total);
13581 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013582#endif /* LIBXML_XPTR_ENABLED */
13583
Daniel Veillardf06307e2001-07-03 10:35:50 +000013584 /*
13585 * Extract the old set, and then evaluate the result of the
13586 * expression for all the element in the set. use it to grow
13587 * up a new set.
13588 */
13589 CHECK_TYPE0(XPATH_NODESET);
13590 obj = valuePop(ctxt);
13591 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013592
Daniel Veillardf06307e2001-07-03 10:35:50 +000013593 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013594 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013595 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013596
Daniel Veillardf06307e2001-07-03 10:35:50 +000013597 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13598 ctxt->context->contextSize = 0;
13599 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013600/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013601 if (op->ch2 != -1)
13602 total +=
13603 xmlXPathCompOpEval(ctxt,
13604 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013605 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013606 res = valuePop(ctxt);
13607 if (res != NULL)
13608 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013609*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013610 valuePush(ctxt, obj);
13611 ctxt->context->node = oldnode;
13612 CHECK_ERROR0;
13613 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013614 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013615 /*
13616 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013617 * Also set the xpath document in case things like
13618 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013619 */
13620 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013621 /*
13622 * SPEC XPath 1.0:
13623 * "For each node in the node-set to be filtered, the
13624 * PredicateExpr is evaluated with that node as the
13625 * context node, with the number of nodes in the
13626 * node-set as the context size, and with the proximity
13627 * position of the node in the node-set with respect to
13628 * the axis as the context position;"
13629 * @oldset is the node-set" to be filtered.
13630 *
13631 * SPEC XPath 1.0:
13632 * "only predicates change the context position and
13633 * context size (see [2.4 Predicates])."
13634 * Example:
13635 * node-set context pos
13636 * nA 1
13637 * nB 2
13638 * nC 3
13639 * After applying predicate [position() > 1] :
13640 * node-set context pos
13641 * nB 1
13642 * nC 2
13643 *
13644 * removed the first node in the node-set, then
13645 * the context position of the
13646 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013647 for (i = 0; i < oldset->nodeNr; i++) {
13648 /*
13649 * Run the evaluation with a node list made of
13650 * a single item in the nodeset.
13651 */
13652 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013653 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13654 (oldset->nodeTab[i]->doc != NULL))
13655 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013656 if (tmp == NULL) {
13657 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13658 ctxt->context->node);
13659 } else {
13660 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13661 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013662 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013663 valuePush(ctxt, tmp);
13664 ctxt->context->contextSize = oldset->nodeNr;
13665 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013666 /*
13667 * Evaluate the predicate against the context node.
13668 * Can/should we optimize position() predicates
13669 * here (e.g. "[1]")?
13670 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013671 if (op->ch2 != -1)
13672 total +=
13673 xmlXPathCompOpEval(ctxt,
13674 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013675 if (ctxt->error != XPATH_EXPRESSION_OK) {
13676 xmlXPathFreeNodeSet(newset);
13677 xmlXPathFreeObject(obj);
13678 return(0);
13679 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013680
Daniel Veillardf06307e2001-07-03 10:35:50 +000013681 /*
William M. Brack08171912003-12-29 02:52:11 +000013682 * The result of the evaluation needs to be tested to
13683 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013684 */
13685 /*
13686 * OPTIMIZE TODO: Can we use
13687 * xmlXPathNodeSetAdd*Unique()* instead?
13688 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013689 res = valuePop(ctxt);
13690 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13691 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13692 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013693
Daniel Veillardf06307e2001-07-03 10:35:50 +000013694 /*
13695 * Cleanup
13696 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013697 if (res != NULL) {
13698 xmlXPathReleaseObject(ctxt->context, res);
13699 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013700 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013701 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013702 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013703 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013704 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013705 * in order to avoid massive recreation inside this
13706 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013707 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013708 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013709 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013710 ctxt->context->node = NULL;
13711 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013712 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013713 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013714 /*
13715 * The result is used as the new evaluation set.
13716 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013717 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013718 ctxt->context->node = NULL;
13719 ctxt->context->contextSize = -1;
13720 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013721 /* may want to move this past the '}' later */
13722 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013723 valuePush(ctxt,
13724 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013725 }
13726 ctxt->context->node = oldnode;
13727 return (total);
13728 }
13729 case XPATH_OP_SORT:
13730 if (op->ch1 != -1)
13731 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013732 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013733 if ((ctxt->value != NULL) &&
13734 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013735 (ctxt->value->nodesetval != NULL) &&
13736 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013737 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013738 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013739 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013740 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013741#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013742 case XPATH_OP_RANGETO:{
13743 xmlXPathObjectPtr range;
13744 xmlXPathObjectPtr res, obj;
13745 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013746 xmlLocationSetPtr newlocset = NULL;
13747 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013748 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013749 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013750
Daniel Veillardf06307e2001-07-03 10:35:50 +000013751 if (op->ch1 != -1)
13752 total +=
13753 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13754 if (op->ch2 == -1)
13755 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013756
William M. Brack08171912003-12-29 02:52:11 +000013757 if (ctxt->value->type == XPATH_LOCATIONSET) {
13758 /*
13759 * Extract the old locset, and then evaluate the result of the
13760 * expression for all the element in the locset. use it to grow
13761 * up a new locset.
13762 */
13763 CHECK_TYPE0(XPATH_LOCATIONSET);
13764 obj = valuePop(ctxt);
13765 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013766
William M. Brack08171912003-12-29 02:52:11 +000013767 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013768 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013769 ctxt->context->contextSize = 0;
13770 ctxt->context->proximityPosition = 0;
13771 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13772 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013773 if (res != NULL) {
13774 xmlXPathReleaseObject(ctxt->context, res);
13775 }
William M. Brack08171912003-12-29 02:52:11 +000013776 valuePush(ctxt, obj);
13777 CHECK_ERROR0;
13778 return (total);
13779 }
13780 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013781
William M. Brack08171912003-12-29 02:52:11 +000013782 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013783 /*
William M. Brack08171912003-12-29 02:52:11 +000013784 * Run the evaluation with a node list made of a
13785 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013786 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013787 ctxt->context->node = oldlocset->locTab[i]->user;
13788 ctxt->context->contextSize = oldlocset->locNr;
13789 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013790 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13791 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013792 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013793
Daniel Veillardf06307e2001-07-03 10:35:50 +000013794 if (op->ch2 != -1)
13795 total +=
13796 xmlXPathCompOpEval(ctxt,
13797 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013798 if (ctxt->error != XPATH_EXPRESSION_OK) {
13799 xmlXPathFreeObject(obj);
13800 return(0);
13801 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013802
Daniel Veillardf06307e2001-07-03 10:35:50 +000013803 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013804 if (res->type == XPATH_LOCATIONSET) {
13805 xmlLocationSetPtr rloc =
13806 (xmlLocationSetPtr)res->user;
13807 for (j=0; j<rloc->locNr; j++) {
13808 range = xmlXPtrNewRange(
13809 oldlocset->locTab[i]->user,
13810 oldlocset->locTab[i]->index,
13811 rloc->locTab[j]->user2,
13812 rloc->locTab[j]->index2);
13813 if (range != NULL) {
13814 xmlXPtrLocationSetAdd(newlocset, range);
13815 }
13816 }
13817 } else {
13818 range = xmlXPtrNewRangeNodeObject(
13819 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13820 if (range != NULL) {
13821 xmlXPtrLocationSetAdd(newlocset,range);
13822 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013823 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013824
Daniel Veillardf06307e2001-07-03 10:35:50 +000013825 /*
13826 * Cleanup
13827 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013828 if (res != NULL) {
13829 xmlXPathReleaseObject(ctxt->context, res);
13830 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013831 if (ctxt->value == tmp) {
13832 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013833 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013834 }
13835
13836 ctxt->context->node = NULL;
13837 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013838 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013839 CHECK_TYPE0(XPATH_NODESET);
13840 obj = valuePop(ctxt);
13841 oldset = obj->nodesetval;
13842 ctxt->context->node = NULL;
13843
13844 newlocset = xmlXPtrLocationSetCreate(NULL);
13845
13846 if (oldset != NULL) {
13847 for (i = 0; i < oldset->nodeNr; i++) {
13848 /*
13849 * Run the evaluation with a node list made of a single item
13850 * in the nodeset.
13851 */
13852 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013853 /*
13854 * OPTIMIZE TODO: Avoid recreation for every iteration.
13855 */
13856 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13857 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013858 valuePush(ctxt, tmp);
13859
13860 if (op->ch2 != -1)
13861 total +=
13862 xmlXPathCompOpEval(ctxt,
13863 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013864 if (ctxt->error != XPATH_EXPRESSION_OK) {
13865 xmlXPathFreeObject(obj);
13866 return(0);
13867 }
William M. Brack08171912003-12-29 02:52:11 +000013868
William M. Brack08171912003-12-29 02:52:11 +000013869 res = valuePop(ctxt);
13870 range =
13871 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13872 res);
13873 if (range != NULL) {
13874 xmlXPtrLocationSetAdd(newlocset, range);
13875 }
13876
13877 /*
13878 * Cleanup
13879 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013880 if (res != NULL) {
13881 xmlXPathReleaseObject(ctxt->context, res);
13882 }
William M. Brack08171912003-12-29 02:52:11 +000013883 if (ctxt->value == tmp) {
13884 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013885 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013886 }
13887
13888 ctxt->context->node = NULL;
13889 }
13890 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013891 }
13892
13893 /*
13894 * The result is used as the new evaluation set.
13895 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013896 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013897 ctxt->context->node = NULL;
13898 ctxt->context->contextSize = -1;
13899 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013900 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013901 return (total);
13902 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013903#endif /* LIBXML_XPTR_ENABLED */
13904 }
13905 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013906 "XPath: unknown precompiled operation %d\n", op->op);
13907 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013908}
13909
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013910/**
13911 * xmlXPathCompOpEvalToBoolean:
13912 * @ctxt: the XPath parser context
13913 *
13914 * Evaluates if the expression evaluates to true.
13915 *
13916 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13917 */
13918static int
13919xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013920 xmlXPathStepOpPtr op,
13921 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013922{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013923 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013924
13925start:
13926 /* comp = ctxt->comp; */
13927 switch (op->op) {
13928 case XPATH_OP_END:
13929 return (0);
13930 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013931 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013932 if (isPredicate)
13933 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13934 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013935 case XPATH_OP_SORT:
13936 /*
13937 * We don't need sorting for boolean results. Skip this one.
13938 */
13939 if (op->ch1 != -1) {
13940 op = &ctxt->comp->steps[op->ch1];
13941 goto start;
13942 }
13943 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013944 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013945 if (op->ch1 == -1)
13946 return(0);
13947
13948 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13949 if (ctxt->error != XPATH_EXPRESSION_OK)
13950 return(-1);
13951
13952 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13953 if (ctxt->error != XPATH_EXPRESSION_OK)
13954 return(-1);
13955
13956 resObj = valuePop(ctxt);
13957 if (resObj == NULL)
13958 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013959 break;
13960 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013961 /*
13962 * Fallback to call xmlXPathCompOpEval().
13963 */
13964 xmlXPathCompOpEval(ctxt, op);
13965 if (ctxt->error != XPATH_EXPRESSION_OK)
13966 return(-1);
13967
13968 resObj = valuePop(ctxt);
13969 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013970 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013971 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013972 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013973
13974 if (resObj) {
13975 int res;
13976
13977 if (resObj->type == XPATH_BOOLEAN) {
13978 res = resObj->boolval;
13979 } else if (isPredicate) {
13980 /*
13981 * For predicates a result of type "number" is handled
13982 * differently:
13983 * SPEC XPath 1.0:
13984 * "If the result is a number, the result will be converted
13985 * to true if the number is equal to the context position
13986 * and will be converted to false otherwise;"
13987 */
13988 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13989 } else {
13990 res = xmlXPathCastToBoolean(resObj);
13991 }
13992 xmlXPathReleaseObject(ctxt->context, resObj);
13993 return(res);
13994 }
13995
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013996 return(0);
13997}
13998
Daniel Veillard56de87e2005-02-16 00:22:29 +000013999#ifdef XPATH_STREAMING
14000/**
14001 * xmlXPathRunStreamEval:
14002 * @ctxt: the XPath parser context with the compiled expression
14003 *
14004 * Evaluate the Precompiled Streamable XPath expression in the given context.
14005 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014006static int
14007xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14008 xmlXPathObjectPtr *resultSeq, int toBool)
14009{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014010 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014011 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014012 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014013 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014014 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014015 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014016
14017 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014018
14019 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014020 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014021 max_depth = xmlPatternMaxDepth(comp);
14022 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014023 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014024 if (max_depth == -2)
14025 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014026 min_depth = xmlPatternMinDepth(comp);
14027 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014028 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014029 from_root = xmlPatternFromRoot(comp);
14030 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014031 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014032#if 0
14033 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14034#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014035
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014036 if (! toBool) {
14037 if (resultSeq == NULL)
14038 return(-1);
14039 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14040 if (*resultSeq == NULL)
14041 return(-1);
14042 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014043
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014044 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014045 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014046 */
14047 if (min_depth == 0) {
14048 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014049 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014050 if (toBool)
14051 return(1);
14052 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14053 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014054 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014055 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014056 if (toBool)
14057 return(1);
14058 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014059 }
14060 }
14061 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014062 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014063 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014064
Daniel Veillard56de87e2005-02-16 00:22:29 +000014065 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014066 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014067 } else if (ctxt->node != NULL) {
14068 switch (ctxt->node->type) {
14069 case XML_ELEMENT_NODE:
14070 case XML_DOCUMENT_NODE:
14071 case XML_DOCUMENT_FRAG_NODE:
14072 case XML_HTML_DOCUMENT_NODE:
14073#ifdef LIBXML_DOCB_ENABLED
14074 case XML_DOCB_DOCUMENT_NODE:
14075#endif
14076 cur = ctxt->node;
14077 break;
14078 case XML_ATTRIBUTE_NODE:
14079 case XML_TEXT_NODE:
14080 case XML_CDATA_SECTION_NODE:
14081 case XML_ENTITY_REF_NODE:
14082 case XML_ENTITY_NODE:
14083 case XML_PI_NODE:
14084 case XML_COMMENT_NODE:
14085 case XML_NOTATION_NODE:
14086 case XML_DTD_NODE:
14087 case XML_DOCUMENT_TYPE_NODE:
14088 case XML_ELEMENT_DECL:
14089 case XML_ATTRIBUTE_DECL:
14090 case XML_ENTITY_DECL:
14091 case XML_NAMESPACE_DECL:
14092 case XML_XINCLUDE_START:
14093 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014094 break;
14095 }
14096 limit = cur;
14097 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014098 if (cur == NULL) {
14099 return(0);
14100 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014101
14102 patstream = xmlPatternGetStreamCtxt(comp);
14103 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014104 /*
14105 * QUESTION TODO: Is this an error?
14106 */
14107 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014108 }
14109
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014110 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014111
Daniel Veillard56de87e2005-02-16 00:22:29 +000014112 if (from_root) {
14113 ret = xmlStreamPush(patstream, NULL, NULL);
14114 if (ret < 0) {
14115 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014116 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014117 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014118 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014119 }
14120 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014121 depth = 0;
14122 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014123next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014124 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014125 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014126
14127 switch (cur->type) {
14128 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014129 case XML_TEXT_NODE:
14130 case XML_CDATA_SECTION_NODE:
14131 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014132 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014133 if (cur->type == XML_ELEMENT_NODE) {
14134 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014135 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014136 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014137 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14138 else
14139 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014140
14141 if (ret < 0) {
14142 /* NOP. */
14143 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014144 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014145 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014146 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014147 }
14148 if ((cur->children == NULL) || (depth >= max_depth)) {
14149 ret = xmlStreamPop(patstream);
14150 while (cur->next != NULL) {
14151 cur = cur->next;
14152 if ((cur->type != XML_ENTITY_DECL) &&
14153 (cur->type != XML_DTD_NODE))
14154 goto next_node;
14155 }
14156 }
14157 default:
14158 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014159 }
14160
Daniel Veillard56de87e2005-02-16 00:22:29 +000014161scan_children:
14162 if ((cur->children != NULL) && (depth < max_depth)) {
14163 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014164 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014165 */
14166 if (cur->children->type != XML_ENTITY_DECL) {
14167 cur = cur->children;
14168 depth++;
14169 /*
14170 * Skip DTDs
14171 */
14172 if (cur->type != XML_DTD_NODE)
14173 continue;
14174 }
14175 }
14176
14177 if (cur == limit)
14178 break;
14179
14180 while (cur->next != NULL) {
14181 cur = cur->next;
14182 if ((cur->type != XML_ENTITY_DECL) &&
14183 (cur->type != XML_DTD_NODE))
14184 goto next_node;
14185 }
14186
14187 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014188 cur = cur->parent;
14189 depth--;
14190 if ((cur == NULL) || (cur == limit))
14191 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014192 if (cur->type == XML_ELEMENT_NODE) {
14193 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014194 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014195 ((cur->type == XML_TEXT_NODE) ||
14196 (cur->type == XML_CDATA_SECTION_NODE) ||
14197 (cur->type == XML_COMMENT_NODE) ||
14198 (cur->type == XML_PI_NODE)))
14199 {
14200 ret = xmlStreamPop(patstream);
14201 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014202 if (cur->next != NULL) {
14203 cur = cur->next;
14204 break;
14205 }
14206 } while (cur != NULL);
14207
14208 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014209
Daniel Veillard56de87e2005-02-16 00:22:29 +000014210done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014211
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014212#if 0
14213 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014214 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014215#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014216
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014217 if (patstream)
14218 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014219 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014220
14221return_1:
14222 if (patstream)
14223 xmlFreeStreamCtxt(patstream);
14224 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014225}
14226#endif /* XPATH_STREAMING */
14227
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014228/**
14229 * xmlXPathRunEval:
14230 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014231 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014232 *
14233 * Evaluate the Precompiled XPath expression in the given context.
14234 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014235static int
14236xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14237{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014238 xmlXPathCompExprPtr comp;
14239
14240 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014241 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014242
14243 if (ctxt->valueTab == NULL) {
14244 /* Allocate the value stack */
14245 ctxt->valueTab = (xmlXPathObjectPtr *)
14246 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14247 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014248 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014249 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014250 }
14251 ctxt->valueNr = 0;
14252 ctxt->valueMax = 10;
14253 ctxt->value = NULL;
14254 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014255#ifdef XPATH_STREAMING
14256 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014257 int res;
14258
14259 if (toBool) {
14260 /*
14261 * Evaluation to boolean result.
14262 */
14263 res = xmlXPathRunStreamEval(ctxt->context,
14264 ctxt->comp->stream, NULL, 1);
14265 if (res != -1)
14266 return(res);
14267 } else {
14268 xmlXPathObjectPtr resObj = NULL;
14269
14270 /*
14271 * Evaluation to a sequence.
14272 */
14273 res = xmlXPathRunStreamEval(ctxt->context,
14274 ctxt->comp->stream, &resObj, 0);
14275
14276 if ((res != -1) && (resObj != NULL)) {
14277 valuePush(ctxt, resObj);
14278 return(0);
14279 }
14280 if (resObj != NULL)
14281 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014282 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014283 /*
14284 * QUESTION TODO: This falls back to normal XPath evaluation
14285 * if res == -1. Is this intended?
14286 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014287 }
14288#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014289 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014290 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014291 xmlGenericError(xmlGenericErrorContext,
14292 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014293 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014294 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014295 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014296 return(xmlXPathCompOpEvalToBoolean(ctxt,
14297 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014298 else
14299 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14300
14301 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014302}
14303
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014304/************************************************************************
14305 * *
14306 * Public interfaces *
14307 * *
14308 ************************************************************************/
14309
14310/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014311 * xmlXPathEvalPredicate:
14312 * @ctxt: the XPath context
14313 * @res: the Predicate Expression evaluation result
14314 *
14315 * Evaluate a predicate result for the current node.
14316 * A PredicateExpr is evaluated by evaluating the Expr and converting
14317 * the result to a boolean. If the result is a number, the result will
14318 * be converted to true if the number is equal to the position of the
14319 * context node in the context node list (as returned by the position
14320 * function) and will be converted to false otherwise; if the result
14321 * is not a number, then the result will be converted as if by a call
14322 * to the boolean function.
14323 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014324 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014325 */
14326int
14327xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014328 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014329 switch (res->type) {
14330 case XPATH_BOOLEAN:
14331 return(res->boolval);
14332 case XPATH_NUMBER:
14333 return(res->floatval == ctxt->proximityPosition);
14334 case XPATH_NODESET:
14335 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014336 if (res->nodesetval == NULL)
14337 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014338 return(res->nodesetval->nodeNr != 0);
14339 case XPATH_STRING:
14340 return((res->stringval != NULL) &&
14341 (xmlStrlen(res->stringval) != 0));
14342 default:
14343 STRANGE
14344 }
14345 return(0);
14346}
14347
14348/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014349 * xmlXPathEvaluatePredicateResult:
14350 * @ctxt: the XPath Parser context
14351 * @res: the Predicate Expression evaluation result
14352 *
14353 * Evaluate a predicate result for the current node.
14354 * A PredicateExpr is evaluated by evaluating the Expr and converting
14355 * the result to a boolean. If the result is a number, the result will
14356 * be converted to true if the number is equal to the position of the
14357 * context node in the context node list (as returned by the position
14358 * function) and will be converted to false otherwise; if the result
14359 * is not a number, then the result will be converted as if by a call
14360 * to the boolean function.
14361 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014362 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014363 */
14364int
14365xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14366 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014367 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014368 switch (res->type) {
14369 case XPATH_BOOLEAN:
14370 return(res->boolval);
14371 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014372#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014373 return((res->floatval == ctxt->context->proximityPosition) &&
14374 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014375#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014376 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014377#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014378 case XPATH_NODESET:
14379 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014380 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014381 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014382 return(res->nodesetval->nodeNr != 0);
14383 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014384 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014385#ifdef LIBXML_XPTR_ENABLED
14386 case XPATH_LOCATIONSET:{
14387 xmlLocationSetPtr ptr = res->user;
14388 if (ptr == NULL)
14389 return(0);
14390 return (ptr->locNr != 0);
14391 }
14392#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014393 default:
14394 STRANGE
14395 }
14396 return(0);
14397}
14398
Daniel Veillard56de87e2005-02-16 00:22:29 +000014399#ifdef XPATH_STREAMING
14400/**
14401 * xmlXPathTryStreamCompile:
14402 * @ctxt: an XPath context
14403 * @str: the XPath expression
14404 *
14405 * Try to compile the XPath expression as a streamable subset.
14406 *
14407 * Returns the compiled expression or NULL if failed to compile.
14408 */
14409static xmlXPathCompExprPtr
14410xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14411 /*
14412 * Optimization: use streaming patterns when the XPath expression can
14413 * be compiled to a stream lookup
14414 */
14415 xmlPatternPtr stream;
14416 xmlXPathCompExprPtr comp;
14417 xmlDictPtr dict = NULL;
14418 const xmlChar **namespaces = NULL;
14419 xmlNsPtr ns;
14420 int i, j;
14421
14422 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14423 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014424 const xmlChar *tmp;
14425
14426 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014427 * We don't try to handle expressions using the verbose axis
14428 * specifiers ("::"), just the simplied form at this point.
14429 * Additionally, if there is no list of namespaces available and
14430 * there's a ":" in the expression, indicating a prefixed QName,
14431 * then we won't try to compile either. xmlPatterncompile() needs
14432 * to have a list of namespaces at compilation time in order to
14433 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014434 */
14435 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014436 if ((tmp != NULL) &&
14437 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14438 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014439
Daniel Veillard56de87e2005-02-16 00:22:29 +000014440 if (ctxt != NULL) {
14441 dict = ctxt->dict;
14442 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014443 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014444 if (namespaces == NULL) {
14445 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14446 return(NULL);
14447 }
14448 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14449 ns = ctxt->namespaces[j];
14450 namespaces[i++] = ns->href;
14451 namespaces[i++] = ns->prefix;
14452 }
14453 namespaces[i++] = NULL;
14454 namespaces[i++] = NULL;
14455 }
14456 }
14457
William M. Brackea152c02005-06-09 18:12:28 +000014458 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14459 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014460 if (namespaces != NULL) {
14461 xmlFree((xmlChar **)namespaces);
14462 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014463 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14464 comp = xmlXPathNewCompExpr();
14465 if (comp == NULL) {
14466 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14467 return(NULL);
14468 }
14469 comp->stream = stream;
14470 comp->dict = dict;
14471 if (comp->dict)
14472 xmlDictReference(comp->dict);
14473 return(comp);
14474 }
14475 xmlFreePattern(stream);
14476 }
14477 return(NULL);
14478}
14479#endif /* XPATH_STREAMING */
14480
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014481static int
14482xmlXPathCanRewriteDosExpression(xmlChar *expr)
14483{
14484 if (expr == NULL)
14485 return(0);
14486 do {
14487 if ((*expr == '/') && (*(++expr) == '/'))
14488 return(1);
14489 } while (*expr++);
14490 return(0);
14491}
14492static void
14493xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14494{
14495 /*
14496 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14497 * internal representation.
14498 */
14499 if (op->ch1 != -1) {
14500 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14501 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14502 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14503 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14504 {
14505 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014506 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014507 */
14508 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14509
14510 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14511 (prevop->ch1 != -1) &&
14512 ((xmlXPathAxisVal) prevop->value ==
14513 AXIS_DESCENDANT_OR_SELF) &&
14514 (prevop->ch2 == -1) &&
14515 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014516 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14517 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014518 {
14519 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014520 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014521 * Eliminate it.
14522 */
14523 op->ch1 = prevop->ch1;
14524 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14525 }
14526 }
14527 if (op->ch1 != -1)
14528 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14529 }
14530 if (op->ch2 != -1)
14531 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14532}
14533
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014534/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014535 * xmlXPathCtxtCompile:
14536 * @ctxt: an XPath context
14537 * @str: the XPath expression
14538 *
14539 * Compile an XPath expression
14540 *
14541 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14542 * the caller has to free the object.
14543 */
14544xmlXPathCompExprPtr
14545xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14546 xmlXPathParserContextPtr pctxt;
14547 xmlXPathCompExprPtr comp;
14548
Daniel Veillard56de87e2005-02-16 00:22:29 +000014549#ifdef XPATH_STREAMING
14550 comp = xmlXPathTryStreamCompile(ctxt, str);
14551 if (comp != NULL)
14552 return(comp);
14553#endif
14554
Daniel Veillard4773df22004-01-23 13:15:13 +000014555 xmlXPathInit();
14556
14557 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014558 if (pctxt == NULL)
14559 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014560 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014561
14562 if( pctxt->error != XPATH_EXPRESSION_OK )
14563 {
14564 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014565 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014566 }
14567
14568 if (*pctxt->cur != 0) {
14569 /*
14570 * aleksey: in some cases this line prints *second* error message
14571 * (see bug #78858) and probably this should be fixed.
14572 * However, we are not sure that all error messages are printed
14573 * out in other places. It's not critical so we leave it as-is for now
14574 */
14575 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14576 comp = NULL;
14577 } else {
14578 comp = pctxt->comp;
14579 pctxt->comp = NULL;
14580 }
14581 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014582
Daniel Veillard4773df22004-01-23 13:15:13 +000014583 if (comp != NULL) {
14584 comp->expr = xmlStrdup(str);
14585#ifdef DEBUG_EVAL_COUNTS
14586 comp->string = xmlStrdup(str);
14587 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014588#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014589 if ((comp->expr != NULL) &&
14590 (comp->nbStep > 2) &&
14591 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014592 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14593 {
14594 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014595 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014596 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014597 return(comp);
14598}
14599
14600/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014601 * xmlXPathCompile:
14602 * @str: the XPath expression
14603 *
14604 * Compile an XPath expression
14605 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014606 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014607 * the caller has to free the object.
14608 */
14609xmlXPathCompExprPtr
14610xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014611 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014612}
14613
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014614/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014615 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014616 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014617 * @ctxt: the XPath context
14618 * @resObj: the resulting XPath object or NULL
14619 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014620 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014621 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014622 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014623 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014624 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014625 * the caller has to free the object.
14626 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014627static int
14628xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14629 xmlXPathContextPtr ctxt,
14630 xmlXPathObjectPtr *resObj,
14631 int toBool)
14632{
14633 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014634#ifndef LIBXML_THREAD_ENABLED
14635 static int reentance = 0;
14636#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014637 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014638
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014639 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014640
14641 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014642 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014643 xmlXPathInit();
14644
Daniel Veillard81463942001-10-16 12:34:39 +000014645#ifndef LIBXML_THREAD_ENABLED
14646 reentance++;
14647 if (reentance > 1)
14648 xmlXPathDisableOptimizer = 1;
14649#endif
14650
Daniel Veillardf06307e2001-07-03 10:35:50 +000014651#ifdef DEBUG_EVAL_COUNTS
14652 comp->nb++;
14653 if ((comp->string != NULL) && (comp->nb > 100)) {
14654 fprintf(stderr, "100 x %s\n", comp->string);
14655 comp->nb = 0;
14656 }
14657#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014658 pctxt = xmlXPathCompParserContext(comp, ctxt);
14659 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014660
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014661 if (resObj) {
14662 if (pctxt->value == NULL) {
14663 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014664 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014665 *resObj = NULL;
14666 } else {
14667 *resObj = valuePop(pctxt);
14668 }
Owen Taylor3473f882001-02-23 17:55:21 +000014669 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014670
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014671 /*
14672 * Pop all remaining objects from the stack.
14673 */
14674 if (pctxt->valueNr > 0) {
14675 xmlXPathObjectPtr tmp;
14676 int stack = 0;
14677
14678 do {
14679 tmp = valuePop(pctxt);
14680 if (tmp != NULL) {
14681 if (tmp != NULL)
14682 stack++;
14683 xmlXPathReleaseObject(ctxt, tmp);
14684 }
14685 } while (tmp != NULL);
14686 if ((stack != 0) &&
14687 ((toBool) || ((resObj) && (*resObj))))
14688 {
14689 xmlGenericError(xmlGenericErrorContext,
14690 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14691 stack);
14692 }
Owen Taylor3473f882001-02-23 17:55:21 +000014693 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014694
14695 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14696 xmlXPathFreeObject(*resObj);
14697 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014698 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014699 pctxt->comp = NULL;
14700 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014701#ifndef LIBXML_THREAD_ENABLED
14702 reentance--;
14703#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014704
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014705 return(res);
14706}
14707
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014708/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014709 * xmlXPathCompiledEval:
14710 * @comp: the compiled XPath expression
14711 * @ctx: the XPath context
14712 *
14713 * Evaluate the Precompiled XPath expression in the given context.
14714 *
14715 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14716 * the caller has to free the object.
14717 */
14718xmlXPathObjectPtr
14719xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14720{
14721 xmlXPathObjectPtr res = NULL;
14722
14723 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14724 return(res);
14725}
14726
14727/**
14728 * xmlXPathCompiledEvalToBoolean:
14729 * @comp: the compiled XPath expression
14730 * @ctxt: the XPath context
14731 *
14732 * Applies the XPath boolean() function on the result of the given
14733 * compiled expression.
14734 *
14735 * Returns 1 if the expression evaluated to true, 0 if to false and
14736 * -1 in API and internal errors.
14737 */
14738int
14739xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14740 xmlXPathContextPtr ctxt)
14741{
14742 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14743}
14744
14745/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014746 * xmlXPathEvalExpr:
14747 * @ctxt: the XPath Parser context
14748 *
14749 * Parse and evaluate an XPath expression in the given context,
14750 * then push the result on the context stack
14751 */
14752void
14753xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014754#ifdef XPATH_STREAMING
14755 xmlXPathCompExprPtr comp;
14756#endif
14757
Daniel Veillarda82b1822004-11-08 16:24:57 +000014758 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014759
14760#ifdef XPATH_STREAMING
14761 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14762 if (comp != NULL) {
14763 if (ctxt->comp != NULL)
14764 xmlXPathFreeCompExpr(ctxt->comp);
14765 ctxt->comp = comp;
14766 if (ctxt->cur != NULL)
14767 while (*ctxt->cur != 0) ctxt->cur++;
14768 } else
14769#endif
14770 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014771 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014772 /*
14773 * In this scenario the expression string will sit in ctxt->base.
14774 */
14775 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14776 (ctxt->comp != NULL) &&
14777 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014778 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014779 (ctxt->comp->last >= 0) &&
14780 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014781 {
14782 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014783 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014784 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014785 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014786 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014787 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014788}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014789
14790/**
14791 * xmlXPathEval:
14792 * @str: the XPath expression
14793 * @ctx: the XPath context
14794 *
14795 * Evaluate the XPath Location Path in the given context.
14796 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014797 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014798 * the caller has to free the object.
14799 */
14800xmlXPathObjectPtr
14801xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14802 xmlXPathParserContextPtr ctxt;
14803 xmlXPathObjectPtr res, tmp, init = NULL;
14804 int stack = 0;
14805
William M. Brackf13f77f2004-11-12 16:03:48 +000014806 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014807
William M. Brackf13f77f2004-11-12 16:03:48 +000014808 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014809
14810 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014811 if (ctxt == NULL)
14812 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014813 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014814
14815 if (ctxt->value == NULL) {
14816 xmlGenericError(xmlGenericErrorContext,
14817 "xmlXPathEval: evaluation failed\n");
14818 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014819 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14820#ifdef XPATH_STREAMING
14821 && (ctxt->comp->stream == NULL)
14822#endif
14823 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014824 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14825 res = NULL;
14826 } else {
14827 res = valuePop(ctxt);
14828 }
14829
14830 do {
14831 tmp = valuePop(ctxt);
14832 if (tmp != NULL) {
14833 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014834 stack++;
14835 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014836 }
14837 } while (tmp != NULL);
14838 if ((stack != 0) && (res != NULL)) {
14839 xmlGenericError(xmlGenericErrorContext,
14840 "xmlXPathEval: %d object left on the stack\n",
14841 stack);
14842 }
14843 if (ctxt->error != XPATH_EXPRESSION_OK) {
14844 xmlXPathFreeObject(res);
14845 res = NULL;
14846 }
14847
Owen Taylor3473f882001-02-23 17:55:21 +000014848 xmlXPathFreeParserContext(ctxt);
14849 return(res);
14850}
14851
14852/**
14853 * xmlXPathEvalExpression:
14854 * @str: the XPath expression
14855 * @ctxt: the XPath context
14856 *
14857 * Evaluate the XPath expression in the given context.
14858 *
14859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860 * the caller has to free the object.
14861 */
14862xmlXPathObjectPtr
14863xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14864 xmlXPathParserContextPtr pctxt;
14865 xmlXPathObjectPtr res, tmp;
14866 int stack = 0;
14867
William M. Brackf13f77f2004-11-12 16:03:48 +000014868 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014869
William M. Brackf13f77f2004-11-12 16:03:48 +000014870 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014871
14872 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014873 if (pctxt == NULL)
14874 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014875 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014876
Daniel Veillardc465ffc2006-10-17 19:39:33 +000014877 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000014878 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14879 res = NULL;
14880 } else {
14881 res = valuePop(pctxt);
14882 }
14883 do {
14884 tmp = valuePop(pctxt);
14885 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014886 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014887 stack++;
14888 }
14889 } while (tmp != NULL);
14890 if ((stack != 0) && (res != NULL)) {
14891 xmlGenericError(xmlGenericErrorContext,
14892 "xmlXPathEvalExpression: %d object left on the stack\n",
14893 stack);
14894 }
14895 xmlXPathFreeParserContext(pctxt);
14896 return(res);
14897}
14898
Daniel Veillard42766c02002-08-22 20:52:17 +000014899/************************************************************************
14900 * *
14901 * Extra functions not pertaining to the XPath spec *
14902 * *
14903 ************************************************************************/
14904/**
14905 * xmlXPathEscapeUriFunction:
14906 * @ctxt: the XPath Parser context
14907 * @nargs: the number of arguments
14908 *
14909 * Implement the escape-uri() XPath function
14910 * string escape-uri(string $str, bool $escape-reserved)
14911 *
14912 * This function applies the URI escaping rules defined in section 2 of [RFC
14913 * 2396] to the string supplied as $uri-part, which typically represents all
14914 * or part of a URI. The effect of the function is to replace any special
14915 * character in the string by an escape sequence of the form %xx%yy...,
14916 * where xxyy... is the hexadecimal representation of the octets used to
14917 * represent the character in UTF-8.
14918 *
14919 * The set of characters that are escaped depends on the setting of the
14920 * boolean argument $escape-reserved.
14921 *
14922 * If $escape-reserved is true, all characters are escaped other than lower
14923 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14924 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14925 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14926 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14927 * A-F).
14928 *
14929 * If $escape-reserved is false, the behavior differs in that characters
14930 * referred to in [RFC 2396] as reserved characters are not escaped. These
14931 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14932 *
14933 * [RFC 2396] does not define whether escaped URIs should use lower case or
14934 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14935 * compared using string comparison functions, this function must always use
14936 * the upper-case letters A-F.
14937 *
14938 * Generally, $escape-reserved should be set to true when escaping a string
14939 * that is to form a single part of a URI, and to false when escaping an
14940 * entire URI or URI reference.
14941 *
14942 * In the case of non-ascii characters, the string is encoded according to
14943 * utf-8 and then converted according to RFC 2396.
14944 *
14945 * Examples
14946 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14947 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14948 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14949 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14950 *
14951 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014952static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014953xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14954 xmlXPathObjectPtr str;
14955 int escape_reserved;
14956 xmlBufferPtr target;
14957 xmlChar *cptr;
14958 xmlChar escape[4];
14959
14960 CHECK_ARITY(2);
14961
14962 escape_reserved = xmlXPathPopBoolean(ctxt);
14963
14964 CAST_TO_STRING;
14965 str = valuePop(ctxt);
14966
14967 target = xmlBufferCreate();
14968
14969 escape[0] = '%';
14970 escape[3] = 0;
14971
14972 if (target) {
14973 for (cptr = str->stringval; *cptr; cptr++) {
14974 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14975 (*cptr >= 'a' && *cptr <= 'z') ||
14976 (*cptr >= '0' && *cptr <= '9') ||
14977 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14978 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14979 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14980 (*cptr == '%' &&
14981 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14982 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14983 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14984 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14985 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14986 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14987 (!escape_reserved &&
14988 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14989 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14990 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14991 *cptr == ','))) {
14992 xmlBufferAdd(target, cptr, 1);
14993 } else {
14994 if ((*cptr >> 4) < 10)
14995 escape[1] = '0' + (*cptr >> 4);
14996 else
14997 escape[1] = 'A' - 10 + (*cptr >> 4);
14998 if ((*cptr & 0xF) < 10)
14999 escape[2] = '0' + (*cptr & 0xF);
15000 else
15001 escape[2] = 'A' - 10 + (*cptr & 0xF);
15002
15003 xmlBufferAdd(target, &escape[0], 3);
15004 }
15005 }
15006 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015007 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15008 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015009 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015010 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015011}
15012
Owen Taylor3473f882001-02-23 17:55:21 +000015013/**
15014 * xmlXPathRegisterAllFunctions:
15015 * @ctxt: the XPath context
15016 *
15017 * Registers all default XPath functions in this context
15018 */
15019void
15020xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15021{
15022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15023 xmlXPathBooleanFunction);
15024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15025 xmlXPathCeilingFunction);
15026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15027 xmlXPathCountFunction);
15028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15029 xmlXPathConcatFunction);
15030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15031 xmlXPathContainsFunction);
15032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15033 xmlXPathIdFunction);
15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15035 xmlXPathFalseFunction);
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15037 xmlXPathFloorFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15039 xmlXPathLastFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15041 xmlXPathLangFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15043 xmlXPathLocalNameFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15045 xmlXPathNotFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15047 xmlXPathNameFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15049 xmlXPathNamespaceURIFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15051 xmlXPathNormalizeFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15053 xmlXPathNumberFunction);
15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15055 xmlXPathPositionFunction);
15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15057 xmlXPathRoundFunction);
15058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15059 xmlXPathStringFunction);
15060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15061 xmlXPathStringLengthFunction);
15062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15063 xmlXPathStartsWithFunction);
15064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15065 xmlXPathSubstringFunction);
15066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15067 xmlXPathSubstringBeforeFunction);
15068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15069 xmlXPathSubstringAfterFunction);
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15071 xmlXPathSumFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15073 xmlXPathTrueFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15075 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015076
15077 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15078 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15079 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015080}
15081
15082#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015083#define bottom_xpath
15084#include "elfgcchack.h"