blob: 9c4db87c58b3a43dfab42d0f80d423735b1b5ff3 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000068* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000069* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000076#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000085/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000086* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
William M. Brackd1757ab2004-10-02 22:07:48 +000093 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000098
William M. Brack21e4ef22005-01-02 09:53:13 +000099#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000100
101/************************************************************************
102 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000103 * Floating point stuff *
104 * *
105 ************************************************************************/
106
Daniel Veillardc0631a62001-09-20 13:56:06 +0000107#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000108#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000109#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000110#include "trionan.c"
111
Owen Taylor3473f882001-02-23 17:55:21 +0000112/*
Owen Taylor3473f882001-02-23 17:55:21 +0000113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000118static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000119static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000128 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Bjorn Reese45029602001-08-21 09:23:53 +0000130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000134
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000135 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000136}
137
Daniel Veillardcda96922001-08-21 10:56:31 +0000138/**
139 * xmlXPathIsNaN:
140 * @val: a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val: a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
166}
167
Daniel Veillard4432df22003-09-28 18:58:27 +0000168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000170/**
171 * xmlXPathGetSign:
172 * @val: a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000180static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000181xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000182 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000183}
184
185
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
189 */
190/* #define DEBUG */
191/* #define DEBUG_STEP */
192/* #define DEBUG_STEP_NTH */
193/* #define DEBUG_EXPR */
194/* #define DEBUG_EVAL_COUNTS */
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000201 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000202 NULL
203};
204static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205#ifndef LIBXML_THREAD_ENABLED
206/*
207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
209 */
210static int xmlXPathDisableOptimizer = 0;
211#endif
212
Owen Taylor3473f882001-02-23 17:55:21 +0000213/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000214 * *
215 * Error handling routines *
216 * *
217 ************************************************************************/
218
Daniel Veillard24505b02005-07-28 23:49:35 +0000219/**
220 * XP_ERRORNULL:
221 * @X: the error code
222 *
223 * Macro to raise an XPath error and return NULL.
224 */
225#define XP_ERRORNULL(X) \
226 { xmlXPathErr(ctxt, X); return(NULL); }
227
William M. Brack08171912003-12-29 02:52:11 +0000228/*
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000231static const char *xmlXPathErrorMessages[] = {
232 "Ok\n",
233 "Number encoding\n",
234 "Unfinished literal\n",
235 "Start of literal\n",
236 "Expected $ for variable reference\n",
237 "Undefined variable\n",
238 "Invalid predicate\n",
239 "Invalid expression\n",
240 "Missing closing curly brace\n",
241 "Unregistered function\n",
242 "Invalid operand\n",
243 "Invalid type\n",
244 "Invalid number of arguments\n",
245 "Invalid context size\n",
246 "Invalid context position\n",
247 "Memory allocation error\n",
248 "Syntax error\n",
249 "Resource error\n",
250 "Sub resource error\n",
251 "Undefined namespace prefix\n",
252 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000253 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000254 "Invalid or incomplete context\n",
255 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000256};
William M. Brackcd65bc92005-01-06 09:39:18 +0000257#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
258 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259/**
260 * xmlXPathErrMemory:
261 * @ctxt: an XPath context
262 * @extra: extra informations
263 *
264 * Handle a redefinition of attribute error
265 */
266static void
267xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268{
269 if (ctxt != NULL) {
270 if (extra) {
271 xmlChar buf[200];
272
273 xmlStrPrintf(buf, 200,
274 BAD_CAST "Memory allocation failed : %s\n",
275 extra);
276 ctxt->lastError.message = (char *) xmlStrdup(buf);
277 } else {
278 ctxt->lastError.message = (char *)
279 xmlStrdup(BAD_CAST "Memory allocation failed\n");
280 }
281 ctxt->lastError.domain = XML_FROM_XPATH;
282 ctxt->lastError.code = XML_ERR_NO_MEMORY;
283 if (ctxt->error != NULL)
284 ctxt->error(ctxt->userData, &ctxt->lastError);
285 } else {
286 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000287 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 NULL, NULL, XML_FROM_XPATH,
289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290 extra, NULL, NULL, 0, 0,
291 "Memory allocation failed : %s\n", extra);
292 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000293 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000294 NULL, NULL, XML_FROM_XPATH,
295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296 NULL, NULL, NULL, 0, 0,
297 "Memory allocation failed\n");
298 }
299}
300
301/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000302 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000303 * @ctxt: an XPath parser context
304 * @extra: extra informations
305 *
306 * Handle a redefinition of attribute error
307 */
308static void
309xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000311 if (ctxt == NULL)
312 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000313 else {
314 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000315 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000316 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000317}
318
319/**
320 * xmlXPathErr:
321 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000322 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000324 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000325 */
326void
327xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328{
William M. Brackcd65bc92005-01-06 09:39:18 +0000329 if ((error < 0) || (error > MAXERRNO))
330 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000331 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000332 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000333 NULL, NULL, XML_FROM_XPATH,
334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335 XML_ERR_ERROR, NULL, 0,
336 NULL, NULL, NULL, 0, 0,
337 xmlXPathErrorMessages[error]);
338 return;
339 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000340 ctxt->error = error;
341 if (ctxt->context == NULL) {
342 __xmlRaiseError(NULL, NULL, NULL,
343 NULL, NULL, XML_FROM_XPATH,
344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345 XML_ERR_ERROR, NULL, 0,
346 (const char *) ctxt->base, NULL, NULL,
347 ctxt->cur - ctxt->base, 0,
348 xmlXPathErrorMessages[error]);
349 return;
350 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000351
352 /* cleanup current last error */
353 xmlResetError(&ctxt->context->lastError);
354
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000355 ctxt->context->lastError.domain = XML_FROM_XPATH;
356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000358 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361 ctxt->context->lastError.node = ctxt->context->debugNode;
362 if (ctxt->context->error != NULL) {
363 ctxt->context->error(ctxt->context->userData,
364 &ctxt->context->lastError);
365 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000366 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000367 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369 XML_ERR_ERROR, NULL, 0,
370 (const char *) ctxt->base, NULL, NULL,
371 ctxt->cur - ctxt->base, 0,
372 xmlXPathErrorMessages[error]);
373 }
374
375}
376
377/**
378 * xmlXPatherror:
379 * @ctxt: the XPath Parser context
380 * @file: the file name
381 * @line: the line number
382 * @no: the error number
383 *
384 * Formats an error message.
385 */
386void
387xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388 int line ATTRIBUTE_UNUSED, int no) {
389 xmlXPathErr(ctxt, no);
390}
391
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000392/************************************************************************
393 * *
394 * Utilities *
395 * *
396 ************************************************************************/
397
398/**
399 * xsltPointerList:
400 *
401 * Pointer-list for various purposes.
402 */
403typedef struct _xmlPointerList xmlPointerList;
404typedef xmlPointerList *xmlPointerListPtr;
405struct _xmlPointerList {
406 void **items;
407 int number;
408 int size;
409};
410/*
411* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412* and here, we should make the functions public.
413*/
414static int
415xmlPointerListAddSize(xmlPointerListPtr list,
416 void *item,
417 int initialSize)
418{
419 if (list->items == NULL) {
420 if (initialSize <= 0)
421 initialSize = 1;
422 list->items = (void **) xmlMalloc(
423 initialSize * sizeof(void *));
424 if (list->items == NULL) {
425 xmlXPathErrMemory(NULL,
426 "xmlPointerListCreate: allocating item\n");
427 return(-1);
428 }
429 list->number = 0;
430 list->size = initialSize;
431 } else if (list->size <= list->number) {
432 list->size *= 2;
433 list->items = (void **) xmlRealloc(list->items,
434 list->size * sizeof(void *));
435 if (list->items == NULL) {
436 xmlXPathErrMemory(NULL,
437 "xmlPointerListCreate: re-allocating item\n");
438 list->size = 0;
439 return(-1);
440 }
441 }
442 list->items[list->number++] = item;
443 return(0);
444}
445
446/**
447 * xsltPointerListCreate:
448 *
449 * Creates an xsltPointerList structure.
450 *
451 * Returns a xsltPointerList structure or NULL in case of an error.
452 */
453static xmlPointerListPtr
454xmlPointerListCreate(int initialSize)
455{
456 xmlPointerListPtr ret;
457
458 ret = xmlMalloc(sizeof(xmlPointerList));
459 if (ret == NULL) {
460 xmlXPathErrMemory(NULL,
461 "xmlPointerListCreate: allocating item\n");
462 return (NULL);
463 }
464 memset(ret, 0, sizeof(xmlPointerList));
465 if (initialSize > 0) {
466 xmlPointerListAddSize(ret, NULL, initialSize);
467 ret->number = 0;
468 }
469 return (ret);
470}
471
472/**
473 * xsltPointerListFree:
474 *
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
477 */
478static void
479xmlPointerListFree(xmlPointerListPtr list)
480{
481 if (list == NULL)
482 return;
483 if (list->items != NULL)
484 xmlFree(list->items);
485 xmlFree(list);
486}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000487
488/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489 * *
490 * Parser Types *
491 * *
492 ************************************************************************/
493
494/*
495 * Types are private:
496 */
497
498typedef enum {
499 XPATH_OP_END=0,
500 XPATH_OP_AND,
501 XPATH_OP_OR,
502 XPATH_OP_EQUAL,
503 XPATH_OP_CMP,
504 XPATH_OP_PLUS,
505 XPATH_OP_MULT,
506 XPATH_OP_UNION,
507 XPATH_OP_ROOT,
508 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000509 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000510 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000511 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000512 XPATH_OP_VARIABLE,
513 XPATH_OP_FUNCTION,
514 XPATH_OP_ARG,
515 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000516 XPATH_OP_FILTER, /* 17 */
517 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000518#ifdef LIBXML_XPTR_ENABLED
519 ,XPATH_OP_RANGETO
520#endif
521} xmlXPathOp;
522
523typedef enum {
524 AXIS_ANCESTOR = 1,
525 AXIS_ANCESTOR_OR_SELF,
526 AXIS_ATTRIBUTE,
527 AXIS_CHILD,
528 AXIS_DESCENDANT,
529 AXIS_DESCENDANT_OR_SELF,
530 AXIS_FOLLOWING,
531 AXIS_FOLLOWING_SIBLING,
532 AXIS_NAMESPACE,
533 AXIS_PARENT,
534 AXIS_PRECEDING,
535 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000536 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000537} xmlXPathAxisVal;
538
539typedef enum {
540 NODE_TEST_NONE = 0,
541 NODE_TEST_TYPE = 1,
542 NODE_TEST_PI = 2,
543 NODE_TEST_ALL = 3,
544 NODE_TEST_NS = 4,
545 NODE_TEST_NAME = 5
546} xmlXPathTestVal;
547
548typedef enum {
549 NODE_TYPE_NODE = 0,
550 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000552 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553} xmlXPathTypeVal;
554
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000555#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000556
557typedef struct _xmlXPathStepOp xmlXPathStepOp;
558typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000560 xmlXPathOp op; /* The identifier of the operation */
561 int ch1; /* First child */
562 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000563 int value;
564 int value2;
565 int value3;
566 void *value4;
567 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000568 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000569 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000570 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000571};
572
573struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000574 int nbStep; /* Number of steps in this expression */
575 int maxStep; /* Maximum number of steps allocated */
576 xmlXPathStepOp *steps; /* ops for computation of this expression */
577 int last; /* index of last step in expression */
578 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000579 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000580#ifdef DEBUG_EVAL_COUNTS
581 int nb;
582 xmlChar *string;
583#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000584#ifdef XPATH_STREAMING
585 xmlPatternPtr stream;
586#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000587};
588
589/************************************************************************
590 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000591 * Forward declarations *
592 * *
593 ************************************************************************/
594static void
595xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596static void
597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598static int
599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600 xmlXPathStepOpPtr op, xmlNodePtr *first);
601static int
602xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000603 xmlXPathStepOpPtr op,
604 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000605
606/************************************************************************
607 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000608 * Parser Type functions *
609 * *
610 ************************************************************************/
611
612/**
613 * xmlXPathNewCompExpr:
614 *
615 * Create a new Xpath component
616 *
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000619static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000620xmlXPathNewCompExpr(void) {
621 xmlXPathCompExprPtr cur;
622
623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000625 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626 return(NULL);
627 }
628 memset(cur, 0, sizeof(xmlXPathCompExpr));
629 cur->maxStep = 10;
630 cur->nbStep = 0;
631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632 sizeof(xmlXPathStepOp));
633 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000634 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000635 xmlFree(cur);
636 return(NULL);
637 }
638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000640#ifdef DEBUG_EVAL_COUNTS
641 cur->nb = 0;
642#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000643 return(cur);
644}
645
646/**
647 * xmlXPathFreeCompExpr:
648 * @comp: an XPATH comp
649 *
650 * Free up the memory allocated by @comp
651 */
652void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000653xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000655 xmlXPathStepOpPtr op;
656 int i;
657
658 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000659 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000660 if (comp->dict == NULL) {
661 for (i = 0; i < comp->nbStep; i++) {
662 op = &comp->steps[i];
663 if (op->value4 != NULL) {
664 if (op->op == XPATH_OP_VALUE)
665 xmlXPathFreeObject(op->value4);
666 else
667 xmlFree(op->value4);
668 }
669 if (op->value5 != NULL)
670 xmlFree(op->value5);
671 }
672 } else {
673 for (i = 0; i < comp->nbStep; i++) {
674 op = &comp->steps[i];
675 if (op->value4 != NULL) {
676 if (op->op == XPATH_OP_VALUE)
677 xmlXPathFreeObject(op->value4);
678 }
679 }
680 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000681 }
682 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000683 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000685#ifdef DEBUG_EVAL_COUNTS
686 if (comp->string != NULL) {
687 xmlFree(comp->string);
688 }
689#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000690#ifdef XPATH_STREAMING
691 if (comp->stream != NULL) {
692 xmlFreePatternList(comp->stream);
693 }
694#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000695 if (comp->expr != NULL) {
696 xmlFree(comp->expr);
697 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000698
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000699 xmlFree(comp);
700}
701
702/**
703 * xmlXPathCompExprAdd:
704 * @comp: the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
707 * @op: an op
708 * @value: the first int value
709 * @value2: the second int value
710 * @value3: the third int value
711 * @value4: the first string value
712 * @value5: the second string value
713 *
William M. Brack08171912003-12-29 02:52:11 +0000714 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000715 *
716 * Returns -1 in case of failure, the index otherwise
717 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000718static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000719xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720 xmlXPathOp op, int value,
721 int value2, int value3, void *value4, void *value5) {
722 if (comp->nbStep >= comp->maxStep) {
723 xmlXPathStepOp *real;
724
725 comp->maxStep *= 2;
726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727 comp->maxStep * sizeof(xmlXPathStepOp));
728 if (real == NULL) {
729 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000730 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000731 return(-1);
732 }
733 comp->steps = real;
734 }
735 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000736 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000737 comp->steps[comp->nbStep].ch1 = ch1;
738 comp->steps[comp->nbStep].ch2 = ch2;
739 comp->steps[comp->nbStep].op = op;
740 comp->steps[comp->nbStep].value = value;
741 comp->steps[comp->nbStep].value2 = value2;
742 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000743 if ((comp->dict != NULL) &&
744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745 (op == XPATH_OP_COLLECT))) {
746 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000747 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000748 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000749 xmlFree(value4);
750 } else
751 comp->steps[comp->nbStep].value4 = NULL;
752 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000753 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000754 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000755 xmlFree(value5);
756 } else
757 comp->steps[comp->nbStep].value5 = NULL;
758 } else {
759 comp->steps[comp->nbStep].value4 = value4;
760 comp->steps[comp->nbStep].value5 = value5;
761 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000762 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000763 return(comp->nbStep++);
764}
765
Daniel Veillardf06307e2001-07-03 10:35:50 +0000766/**
767 * xmlXPathCompSwap:
768 * @comp: the compiled expression
769 * @op: operation index
770 *
771 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000772 */
773static void
774xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775 int tmp;
776
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000777#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000778 /*
779 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000780 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000781 * application
782 */
783 if (xmlXPathDisableOptimizer)
784 return;
785#endif
786
Daniel Veillardf06307e2001-07-03 10:35:50 +0000787 tmp = op->ch1;
788 op->ch1 = op->ch2;
789 op->ch2 = tmp;
790}
791
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000792#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
794 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000795#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
797 (op), (val), (val2), (val3), (val4), (val5))
798
799#define PUSH_LEAVE_EXPR(op, val, val2) \
800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802#define PUSH_UNARY_EXPR(op, ch, val, val2) \
803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000806xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
807 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000808
809/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000810 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000811 * XPath object cache structures *
812 * *
813 ************************************************************************/
814
815/* #define XP_DEFAULT_CACHE_ON */
816
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000817#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000818
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000819typedef struct _xmlXPathContextCache xmlXPathContextCache;
820typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000827 int maxNodeset;
828 int maxString;
829 int maxBoolean;
830 int maxNumber;
831 int maxMisc;
832#ifdef XP_DEBUG_OBJ_USAGE
833 int dbgCachedAll;
834 int dbgCachedNodeset;
835 int dbgCachedString;
836 int dbgCachedBool;
837 int dbgCachedNumber;
838 int dbgCachedPoint;
839 int dbgCachedRange;
840 int dbgCachedLocset;
841 int dbgCachedUsers;
842 int dbgCachedXSLTTree;
843 int dbgCachedUndefined;
844
845
846 int dbgReusedAll;
847 int dbgReusedNodeset;
848 int dbgReusedString;
849 int dbgReusedBool;
850 int dbgReusedNumber;
851 int dbgReusedPoint;
852 int dbgReusedRange;
853 int dbgReusedLocset;
854 int dbgReusedUsers;
855 int dbgReusedXSLTTree;
856 int dbgReusedUndefined;
857
858#endif
859};
860
861/************************************************************************
862 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000863 * Debugging related functions *
864 * *
865 ************************************************************************/
866
Owen Taylor3473f882001-02-23 17:55:21 +0000867#define STRANGE \
868 xmlGenericError(xmlGenericErrorContext, \
869 "Internal error at %s:%d\n", \
870 __FILE__, __LINE__);
871
872#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000873static void
874xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000875 int i;
876 char shift[100];
877
878 for (i = 0;((i < depth) && (i < 25));i++)
879 shift[2 * i] = shift[2 * i + 1] = ' ';
880 shift[2 * i] = shift[2 * i + 1] = 0;
881 if (cur == NULL) {
882 fprintf(output, shift);
883 fprintf(output, "Node is NULL !\n");
884 return;
885
886 }
887
888 if ((cur->type == XML_DOCUMENT_NODE) ||
889 (cur->type == XML_HTML_DOCUMENT_NODE)) {
890 fprintf(output, shift);
891 fprintf(output, " /\n");
892 } else if (cur->type == XML_ATTRIBUTE_NODE)
893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894 else
895 xmlDebugDumpOneNode(output, cur, depth);
896}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000897static void
898xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000899 xmlNodePtr tmp;
900 int i;
901 char shift[100];
902
903 for (i = 0;((i < depth) && (i < 25));i++)
904 shift[2 * i] = shift[2 * i + 1] = ' ';
905 shift[2 * i] = shift[2 * i + 1] = 0;
906 if (cur == NULL) {
907 fprintf(output, shift);
908 fprintf(output, "Node is NULL !\n");
909 return;
910
911 }
912
913 while (cur != NULL) {
914 tmp = cur;
915 cur = cur->next;
916 xmlDebugDumpOneNode(output, tmp, depth);
917 }
918}
Owen Taylor3473f882001-02-23 17:55:21 +0000919
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000920static void
921xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000922 int i;
923 char shift[100];
924
925 for (i = 0;((i < depth) && (i < 25));i++)
926 shift[2 * i] = shift[2 * i + 1] = ' ';
927 shift[2 * i] = shift[2 * i + 1] = 0;
928
929 if (cur == NULL) {
930 fprintf(output, shift);
931 fprintf(output, "NodeSet is NULL !\n");
932 return;
933
934 }
935
Daniel Veillard911f49a2001-04-07 15:39:35 +0000936 if (cur != NULL) {
937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938 for (i = 0;i < cur->nodeNr;i++) {
939 fprintf(output, shift);
940 fprintf(output, "%d", i + 1);
941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942 }
Owen Taylor3473f882001-02-23 17:55:21 +0000943 }
944}
945
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000946static void
947xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000948 int i;
949 char shift[100];
950
951 for (i = 0;((i < depth) && (i < 25));i++)
952 shift[2 * i] = shift[2 * i + 1] = ' ';
953 shift[2 * i] = shift[2 * i + 1] = 0;
954
955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956 fprintf(output, shift);
957 fprintf(output, "Value Tree is NULL !\n");
958 return;
959
960 }
961
962 fprintf(output, shift);
963 fprintf(output, "%d", i + 1);
964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965}
Owen Taylor3473f882001-02-23 17:55:21 +0000966#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000967static void
968xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000969 int i;
970 char shift[100];
971
972 for (i = 0;((i < depth) && (i < 25));i++)
973 shift[2 * i] = shift[2 * i + 1] = ' ';
974 shift[2 * i] = shift[2 * i + 1] = 0;
975
976 if (cur == NULL) {
977 fprintf(output, shift);
978 fprintf(output, "LocationSet is NULL !\n");
979 return;
980
981 }
982
983 for (i = 0;i < cur->locNr;i++) {
984 fprintf(output, shift);
985 fprintf(output, "%d : ", i + 1);
986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987 }
988}
Daniel Veillard017b1082001-06-21 11:20:21 +0000989#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000990
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000991/**
992 * xmlXPathDebugDumpObject:
993 * @output: the FILE * to dump the output
994 * @cur: the object to inspect
995 * @depth: indentation level
996 *
997 * Dump the content of the object for debugging purposes
998 */
999void
1000xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001001 int i;
1002 char shift[100];
1003
Daniel Veillarda82b1822004-11-08 16:24:57 +00001004 if (output == NULL) return;
1005
Owen Taylor3473f882001-02-23 17:55:21 +00001006 for (i = 0;((i < depth) && (i < 25));i++)
1007 shift[2 * i] = shift[2 * i + 1] = ' ';
1008 shift[2 * i] = shift[2 * i + 1] = 0;
1009
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001010
1011 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001012
1013 if (cur == NULL) {
1014 fprintf(output, "Object is empty (NULL)\n");
1015 return;
1016 }
1017 switch(cur->type) {
1018 case XPATH_UNDEFINED:
1019 fprintf(output, "Object is uninitialized\n");
1020 break;
1021 case XPATH_NODESET:
1022 fprintf(output, "Object is a Node Set :\n");
1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024 break;
1025 case XPATH_XSLT_TREE:
1026 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001028 break;
1029 case XPATH_BOOLEAN:
1030 fprintf(output, "Object is a Boolean : ");
1031 if (cur->boolval) fprintf(output, "true\n");
1032 else fprintf(output, "false\n");
1033 break;
1034 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001035 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001036 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001037 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001038 break;
1039 case -1:
1040 fprintf(output, "Object is a number : -Infinity\n");
1041 break;
1042 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001043 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001044 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001047 } else {
1048 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049 }
1050 }
Owen Taylor3473f882001-02-23 17:55:21 +00001051 break;
1052 case XPATH_STRING:
1053 fprintf(output, "Object is a string : ");
1054 xmlDebugDumpString(output, cur->stringval);
1055 fprintf(output, "\n");
1056 break;
1057 case XPATH_POINT:
1058 fprintf(output, "Object is a point : index %d in node", cur->index);
1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060 fprintf(output, "\n");
1061 break;
1062 case XPATH_RANGE:
1063 if ((cur->user2 == NULL) ||
1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065 fprintf(output, "Object is a collapsed range :\n");
1066 fprintf(output, shift);
1067 if (cur->index >= 0)
1068 fprintf(output, "index %d in ", cur->index);
1069 fprintf(output, "node\n");
1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071 depth + 1);
1072 } else {
1073 fprintf(output, "Object is a range :\n");
1074 fprintf(output, shift);
1075 fprintf(output, "From ");
1076 if (cur->index >= 0)
1077 fprintf(output, "index %d in ", cur->index);
1078 fprintf(output, "node\n");
1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080 depth + 1);
1081 fprintf(output, shift);
1082 fprintf(output, "To ");
1083 if (cur->index2 >= 0)
1084 fprintf(output, "index %d in ", cur->index2);
1085 fprintf(output, "node\n");
1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087 depth + 1);
1088 fprintf(output, "\n");
1089 }
1090 break;
1091 case XPATH_LOCATIONSET:
1092#if defined(LIBXML_XPTR_ENABLED)
1093 fprintf(output, "Object is a Location Set:\n");
1094 xmlXPathDebugDumpLocationSet(output,
1095 (xmlLocationSetPtr) cur->user, depth);
1096#endif
1097 break;
1098 case XPATH_USERS:
1099 fprintf(output, "Object is user defined\n");
1100 break;
1101 }
1102}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001103
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001104static void
1105xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001106 xmlXPathStepOpPtr op, int depth) {
1107 int i;
1108 char shift[100];
1109
1110 for (i = 0;((i < depth) && (i < 25));i++)
1111 shift[2 * i] = shift[2 * i + 1] = ' ';
1112 shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114 fprintf(output, shift);
1115 if (op == NULL) {
1116 fprintf(output, "Step is NULL\n");
1117 return;
1118 }
1119 switch (op->op) {
1120 case XPATH_OP_END:
1121 fprintf(output, "END"); break;
1122 case XPATH_OP_AND:
1123 fprintf(output, "AND"); break;
1124 case XPATH_OP_OR:
1125 fprintf(output, "OR"); break;
1126 case XPATH_OP_EQUAL:
1127 if (op->value)
1128 fprintf(output, "EQUAL =");
1129 else
1130 fprintf(output, "EQUAL !=");
1131 break;
1132 case XPATH_OP_CMP:
1133 if (op->value)
1134 fprintf(output, "CMP <");
1135 else
1136 fprintf(output, "CMP >");
1137 if (!op->value2)
1138 fprintf(output, "=");
1139 break;
1140 case XPATH_OP_PLUS:
1141 if (op->value == 0)
1142 fprintf(output, "PLUS -");
1143 else if (op->value == 1)
1144 fprintf(output, "PLUS +");
1145 else if (op->value == 2)
1146 fprintf(output, "PLUS unary -");
1147 else if (op->value == 3)
1148 fprintf(output, "PLUS unary - -");
1149 break;
1150 case XPATH_OP_MULT:
1151 if (op->value == 0)
1152 fprintf(output, "MULT *");
1153 else if (op->value == 1)
1154 fprintf(output, "MULT div");
1155 else
1156 fprintf(output, "MULT mod");
1157 break;
1158 case XPATH_OP_UNION:
1159 fprintf(output, "UNION"); break;
1160 case XPATH_OP_ROOT:
1161 fprintf(output, "ROOT"); break;
1162 case XPATH_OP_NODE:
1163 fprintf(output, "NODE"); break;
1164 case XPATH_OP_RESET:
1165 fprintf(output, "RESET"); break;
1166 case XPATH_OP_SORT:
1167 fprintf(output, "SORT"); break;
1168 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001172 const xmlChar *prefix = op->value4;
1173 const xmlChar *name = op->value5;
1174
1175 fprintf(output, "COLLECT ");
1176 switch (axis) {
1177 case AXIS_ANCESTOR:
1178 fprintf(output, " 'ancestors' "); break;
1179 case AXIS_ANCESTOR_OR_SELF:
1180 fprintf(output, " 'ancestors-or-self' "); break;
1181 case AXIS_ATTRIBUTE:
1182 fprintf(output, " 'attributes' "); break;
1183 case AXIS_CHILD:
1184 fprintf(output, " 'child' "); break;
1185 case AXIS_DESCENDANT:
1186 fprintf(output, " 'descendant' "); break;
1187 case AXIS_DESCENDANT_OR_SELF:
1188 fprintf(output, " 'descendant-or-self' "); break;
1189 case AXIS_FOLLOWING:
1190 fprintf(output, " 'following' "); break;
1191 case AXIS_FOLLOWING_SIBLING:
1192 fprintf(output, " 'following-siblings' "); break;
1193 case AXIS_NAMESPACE:
1194 fprintf(output, " 'namespace' "); break;
1195 case AXIS_PARENT:
1196 fprintf(output, " 'parent' "); break;
1197 case AXIS_PRECEDING:
1198 fprintf(output, " 'preceding' "); break;
1199 case AXIS_PRECEDING_SIBLING:
1200 fprintf(output, " 'preceding-sibling' "); break;
1201 case AXIS_SELF:
1202 fprintf(output, " 'self' "); break;
1203 }
1204 switch (test) {
1205 case NODE_TEST_NONE:
1206 fprintf(output, "'none' "); break;
1207 case NODE_TEST_TYPE:
1208 fprintf(output, "'type' "); break;
1209 case NODE_TEST_PI:
1210 fprintf(output, "'PI' "); break;
1211 case NODE_TEST_ALL:
1212 fprintf(output, "'all' "); break;
1213 case NODE_TEST_NS:
1214 fprintf(output, "'namespace' "); break;
1215 case NODE_TEST_NAME:
1216 fprintf(output, "'name' "); break;
1217 }
1218 switch (type) {
1219 case NODE_TYPE_NODE:
1220 fprintf(output, "'node' "); break;
1221 case NODE_TYPE_COMMENT:
1222 fprintf(output, "'comment' "); break;
1223 case NODE_TYPE_TEXT:
1224 fprintf(output, "'text' "); break;
1225 case NODE_TYPE_PI:
1226 fprintf(output, "'PI' "); break;
1227 }
1228 if (prefix != NULL)
1229 fprintf(output, "%s:", prefix);
1230 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001231 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001232 break;
1233
1234 }
1235 case XPATH_OP_VALUE: {
1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238 fprintf(output, "ELEM ");
1239 xmlXPathDebugDumpObject(output, object, 0);
1240 goto finish;
1241 }
1242 case XPATH_OP_VARIABLE: {
1243 const xmlChar *prefix = op->value5;
1244 const xmlChar *name = op->value4;
1245
1246 if (prefix != NULL)
1247 fprintf(output, "VARIABLE %s:%s", prefix, name);
1248 else
1249 fprintf(output, "VARIABLE %s", name);
1250 break;
1251 }
1252 case XPATH_OP_FUNCTION: {
1253 int nbargs = op->value;
1254 const xmlChar *prefix = op->value5;
1255 const xmlChar *name = op->value4;
1256
1257 if (prefix != NULL)
1258 fprintf(output, "FUNCTION %s:%s(%d args)",
1259 prefix, name, nbargs);
1260 else
1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262 break;
1263 }
1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001267#ifdef LIBXML_XPTR_ENABLED
1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001270 default:
1271 fprintf(output, "UNKNOWN %d\n", op->op); return;
1272 }
1273 fprintf(output, "\n");
1274finish:
1275 if (op->ch1 >= 0)
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277 if (op->ch2 >= 0)
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001280
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001281/**
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output: the FILE * for the output
1284 * @comp: the precompiled XPath expression
1285 * @depth: the indentation level.
1286 *
1287 * Dumps the tree of the compiled XPath expression.
1288 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001289void
1290xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001292 int i;
1293 char shift[100];
1294
Daniel Veillarda82b1822004-11-08 16:24:57 +00001295 if ((output == NULL) || (comp == NULL)) return;
1296
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001297 for (i = 0;((i < depth) && (i < 25));i++)
1298 shift[2 * i] = shift[2 * i + 1] = ' ';
1299 shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301 fprintf(output, shift);
1302
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001303 fprintf(output, "Compiled Expression : %d elements\n",
1304 comp->nbStep);
1305 i = comp->last;
1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001308
1309#ifdef XP_DEBUG_OBJ_USAGE
1310
1311/*
1312* XPath object usage related debugging variables.
1313*/
1314static int xmlXPathDebugObjCounterUndefined = 0;
1315static int xmlXPathDebugObjCounterNodeset = 0;
1316static int xmlXPathDebugObjCounterBool = 0;
1317static int xmlXPathDebugObjCounterNumber = 0;
1318static int xmlXPathDebugObjCounterString = 0;
1319static int xmlXPathDebugObjCounterPoint = 0;
1320static int xmlXPathDebugObjCounterRange = 0;
1321static int xmlXPathDebugObjCounterLocset = 0;
1322static int xmlXPathDebugObjCounterUsers = 0;
1323static int xmlXPathDebugObjCounterXSLTTree = 0;
1324static int xmlXPathDebugObjCounterAll = 0;
1325
1326static int xmlXPathDebugObjTotalUndefined = 0;
1327static int xmlXPathDebugObjTotalNodeset = 0;
1328static int xmlXPathDebugObjTotalBool = 0;
1329static int xmlXPathDebugObjTotalNumber = 0;
1330static int xmlXPathDebugObjTotalString = 0;
1331static int xmlXPathDebugObjTotalPoint = 0;
1332static int xmlXPathDebugObjTotalRange = 0;
1333static int xmlXPathDebugObjTotalLocset = 0;
1334static int xmlXPathDebugObjTotalUsers = 0;
1335static int xmlXPathDebugObjTotalXSLTTree = 0;
1336static int xmlXPathDebugObjTotalAll = 0;
1337
1338static int xmlXPathDebugObjMaxUndefined = 0;
1339static int xmlXPathDebugObjMaxNodeset = 0;
1340static int xmlXPathDebugObjMaxBool = 0;
1341static int xmlXPathDebugObjMaxNumber = 0;
1342static int xmlXPathDebugObjMaxString = 0;
1343static int xmlXPathDebugObjMaxPoint = 0;
1344static int xmlXPathDebugObjMaxRange = 0;
1345static int xmlXPathDebugObjMaxLocset = 0;
1346static int xmlXPathDebugObjMaxUsers = 0;
1347static int xmlXPathDebugObjMaxXSLTTree = 0;
1348static int xmlXPathDebugObjMaxAll = 0;
1349
1350/* REVISIT TODO: Make this static when committing */
1351static void
1352xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353{
1354 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001355 if (ctxt->cache != NULL) {
1356 xmlXPathContextCachePtr cache =
1357 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001358
1359 cache->dbgCachedAll = 0;
1360 cache->dbgCachedNodeset = 0;
1361 cache->dbgCachedString = 0;
1362 cache->dbgCachedBool = 0;
1363 cache->dbgCachedNumber = 0;
1364 cache->dbgCachedPoint = 0;
1365 cache->dbgCachedRange = 0;
1366 cache->dbgCachedLocset = 0;
1367 cache->dbgCachedUsers = 0;
1368 cache->dbgCachedXSLTTree = 0;
1369 cache->dbgCachedUndefined = 0;
1370
1371 cache->dbgReusedAll = 0;
1372 cache->dbgReusedNodeset = 0;
1373 cache->dbgReusedString = 0;
1374 cache->dbgReusedBool = 0;
1375 cache->dbgReusedNumber = 0;
1376 cache->dbgReusedPoint = 0;
1377 cache->dbgReusedRange = 0;
1378 cache->dbgReusedLocset = 0;
1379 cache->dbgReusedUsers = 0;
1380 cache->dbgReusedXSLTTree = 0;
1381 cache->dbgReusedUndefined = 0;
1382 }
1383 }
1384
1385 xmlXPathDebugObjCounterUndefined = 0;
1386 xmlXPathDebugObjCounterNodeset = 0;
1387 xmlXPathDebugObjCounterBool = 0;
1388 xmlXPathDebugObjCounterNumber = 0;
1389 xmlXPathDebugObjCounterString = 0;
1390 xmlXPathDebugObjCounterPoint = 0;
1391 xmlXPathDebugObjCounterRange = 0;
1392 xmlXPathDebugObjCounterLocset = 0;
1393 xmlXPathDebugObjCounterUsers = 0;
1394 xmlXPathDebugObjCounterXSLTTree = 0;
1395 xmlXPathDebugObjCounterAll = 0;
1396
1397 xmlXPathDebugObjTotalUndefined = 0;
1398 xmlXPathDebugObjTotalNodeset = 0;
1399 xmlXPathDebugObjTotalBool = 0;
1400 xmlXPathDebugObjTotalNumber = 0;
1401 xmlXPathDebugObjTotalString = 0;
1402 xmlXPathDebugObjTotalPoint = 0;
1403 xmlXPathDebugObjTotalRange = 0;
1404 xmlXPathDebugObjTotalLocset = 0;
1405 xmlXPathDebugObjTotalUsers = 0;
1406 xmlXPathDebugObjTotalXSLTTree = 0;
1407 xmlXPathDebugObjTotalAll = 0;
1408
1409 xmlXPathDebugObjMaxUndefined = 0;
1410 xmlXPathDebugObjMaxNodeset = 0;
1411 xmlXPathDebugObjMaxBool = 0;
1412 xmlXPathDebugObjMaxNumber = 0;
1413 xmlXPathDebugObjMaxString = 0;
1414 xmlXPathDebugObjMaxPoint = 0;
1415 xmlXPathDebugObjMaxRange = 0;
1416 xmlXPathDebugObjMaxLocset = 0;
1417 xmlXPathDebugObjMaxUsers = 0;
1418 xmlXPathDebugObjMaxXSLTTree = 0;
1419 xmlXPathDebugObjMaxAll = 0;
1420
1421}
1422
1423static void
1424xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425 xmlXPathObjectType objType)
1426{
1427 int isCached = 0;
1428
1429 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001430 if (ctxt->cache != NULL) {
1431 xmlXPathContextCachePtr cache =
1432 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001433
1434 isCached = 1;
1435
1436 cache->dbgReusedAll++;
1437 switch (objType) {
1438 case XPATH_UNDEFINED:
1439 cache->dbgReusedUndefined++;
1440 break;
1441 case XPATH_NODESET:
1442 cache->dbgReusedNodeset++;
1443 break;
1444 case XPATH_BOOLEAN:
1445 cache->dbgReusedBool++;
1446 break;
1447 case XPATH_NUMBER:
1448 cache->dbgReusedNumber++;
1449 break;
1450 case XPATH_STRING:
1451 cache->dbgReusedString++;
1452 break;
1453 case XPATH_POINT:
1454 cache->dbgReusedPoint++;
1455 break;
1456 case XPATH_RANGE:
1457 cache->dbgReusedRange++;
1458 break;
1459 case XPATH_LOCATIONSET:
1460 cache->dbgReusedLocset++;
1461 break;
1462 case XPATH_USERS:
1463 cache->dbgReusedUsers++;
1464 break;
1465 case XPATH_XSLT_TREE:
1466 cache->dbgReusedXSLTTree++;
1467 break;
1468 default:
1469 break;
1470 }
1471 }
1472 }
1473
1474 switch (objType) {
1475 case XPATH_UNDEFINED:
1476 if (! isCached)
1477 xmlXPathDebugObjTotalUndefined++;
1478 xmlXPathDebugObjCounterUndefined++;
1479 if (xmlXPathDebugObjCounterUndefined >
1480 xmlXPathDebugObjMaxUndefined)
1481 xmlXPathDebugObjMaxUndefined =
1482 xmlXPathDebugObjCounterUndefined;
1483 break;
1484 case XPATH_NODESET:
1485 if (! isCached)
1486 xmlXPathDebugObjTotalNodeset++;
1487 xmlXPathDebugObjCounterNodeset++;
1488 if (xmlXPathDebugObjCounterNodeset >
1489 xmlXPathDebugObjMaxNodeset)
1490 xmlXPathDebugObjMaxNodeset =
1491 xmlXPathDebugObjCounterNodeset;
1492 break;
1493 case XPATH_BOOLEAN:
1494 if (! isCached)
1495 xmlXPathDebugObjTotalBool++;
1496 xmlXPathDebugObjCounterBool++;
1497 if (xmlXPathDebugObjCounterBool >
1498 xmlXPathDebugObjMaxBool)
1499 xmlXPathDebugObjMaxBool =
1500 xmlXPathDebugObjCounterBool;
1501 break;
1502 case XPATH_NUMBER:
1503 if (! isCached)
1504 xmlXPathDebugObjTotalNumber++;
1505 xmlXPathDebugObjCounterNumber++;
1506 if (xmlXPathDebugObjCounterNumber >
1507 xmlXPathDebugObjMaxNumber)
1508 xmlXPathDebugObjMaxNumber =
1509 xmlXPathDebugObjCounterNumber;
1510 break;
1511 case XPATH_STRING:
1512 if (! isCached)
1513 xmlXPathDebugObjTotalString++;
1514 xmlXPathDebugObjCounterString++;
1515 if (xmlXPathDebugObjCounterString >
1516 xmlXPathDebugObjMaxString)
1517 xmlXPathDebugObjMaxString =
1518 xmlXPathDebugObjCounterString;
1519 break;
1520 case XPATH_POINT:
1521 if (! isCached)
1522 xmlXPathDebugObjTotalPoint++;
1523 xmlXPathDebugObjCounterPoint++;
1524 if (xmlXPathDebugObjCounterPoint >
1525 xmlXPathDebugObjMaxPoint)
1526 xmlXPathDebugObjMaxPoint =
1527 xmlXPathDebugObjCounterPoint;
1528 break;
1529 case XPATH_RANGE:
1530 if (! isCached)
1531 xmlXPathDebugObjTotalRange++;
1532 xmlXPathDebugObjCounterRange++;
1533 if (xmlXPathDebugObjCounterRange >
1534 xmlXPathDebugObjMaxRange)
1535 xmlXPathDebugObjMaxRange =
1536 xmlXPathDebugObjCounterRange;
1537 break;
1538 case XPATH_LOCATIONSET:
1539 if (! isCached)
1540 xmlXPathDebugObjTotalLocset++;
1541 xmlXPathDebugObjCounterLocset++;
1542 if (xmlXPathDebugObjCounterLocset >
1543 xmlXPathDebugObjMaxLocset)
1544 xmlXPathDebugObjMaxLocset =
1545 xmlXPathDebugObjCounterLocset;
1546 break;
1547 case XPATH_USERS:
1548 if (! isCached)
1549 xmlXPathDebugObjTotalUsers++;
1550 xmlXPathDebugObjCounterUsers++;
1551 if (xmlXPathDebugObjCounterUsers >
1552 xmlXPathDebugObjMaxUsers)
1553 xmlXPathDebugObjMaxUsers =
1554 xmlXPathDebugObjCounterUsers;
1555 break;
1556 case XPATH_XSLT_TREE:
1557 if (! isCached)
1558 xmlXPathDebugObjTotalXSLTTree++;
1559 xmlXPathDebugObjCounterXSLTTree++;
1560 if (xmlXPathDebugObjCounterXSLTTree >
1561 xmlXPathDebugObjMaxXSLTTree)
1562 xmlXPathDebugObjMaxXSLTTree =
1563 xmlXPathDebugObjCounterXSLTTree;
1564 break;
1565 default:
1566 break;
1567 }
1568 if (! isCached)
1569 xmlXPathDebugObjTotalAll++;
1570 xmlXPathDebugObjCounterAll++;
1571 if (xmlXPathDebugObjCounterAll >
1572 xmlXPathDebugObjMaxAll)
1573 xmlXPathDebugObjMaxAll =
1574 xmlXPathDebugObjCounterAll;
1575}
1576
1577static void
1578xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579 xmlXPathObjectType objType)
1580{
1581 int isCached = 0;
1582
1583 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001584 if (ctxt->cache != NULL) {
1585 xmlXPathContextCachePtr cache =
1586 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001587
1588 isCached = 1;
1589
1590 cache->dbgCachedAll++;
1591 switch (objType) {
1592 case XPATH_UNDEFINED:
1593 cache->dbgCachedUndefined++;
1594 break;
1595 case XPATH_NODESET:
1596 cache->dbgCachedNodeset++;
1597 break;
1598 case XPATH_BOOLEAN:
1599 cache->dbgCachedBool++;
1600 break;
1601 case XPATH_NUMBER:
1602 cache->dbgCachedNumber++;
1603 break;
1604 case XPATH_STRING:
1605 cache->dbgCachedString++;
1606 break;
1607 case XPATH_POINT:
1608 cache->dbgCachedPoint++;
1609 break;
1610 case XPATH_RANGE:
1611 cache->dbgCachedRange++;
1612 break;
1613 case XPATH_LOCATIONSET:
1614 cache->dbgCachedLocset++;
1615 break;
1616 case XPATH_USERS:
1617 cache->dbgCachedUsers++;
1618 break;
1619 case XPATH_XSLT_TREE:
1620 cache->dbgCachedXSLTTree++;
1621 break;
1622 default:
1623 break;
1624 }
1625
1626 }
1627 }
1628 switch (objType) {
1629 case XPATH_UNDEFINED:
1630 xmlXPathDebugObjCounterUndefined--;
1631 break;
1632 case XPATH_NODESET:
1633 xmlXPathDebugObjCounterNodeset--;
1634 break;
1635 case XPATH_BOOLEAN:
1636 xmlXPathDebugObjCounterBool--;
1637 break;
1638 case XPATH_NUMBER:
1639 xmlXPathDebugObjCounterNumber--;
1640 break;
1641 case XPATH_STRING:
1642 xmlXPathDebugObjCounterString--;
1643 break;
1644 case XPATH_POINT:
1645 xmlXPathDebugObjCounterPoint--;
1646 break;
1647 case XPATH_RANGE:
1648 xmlXPathDebugObjCounterRange--;
1649 break;
1650 case XPATH_LOCATIONSET:
1651 xmlXPathDebugObjCounterLocset--;
1652 break;
1653 case XPATH_USERS:
1654 xmlXPathDebugObjCounterUsers--;
1655 break;
1656 case XPATH_XSLT_TREE:
1657 xmlXPathDebugObjCounterXSLTTree--;
1658 break;
1659 default:
1660 break;
1661 }
1662 xmlXPathDebugObjCounterAll--;
1663}
1664
1665/* REVISIT TODO: Make this static when committing */
1666static void
1667xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668{
1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670 reqXSLTTree, reqUndefined;
1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675 int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677 reqAll = xmlXPathDebugObjTotalAll;
1678 reqNodeset = xmlXPathDebugObjTotalNodeset;
1679 reqString = xmlXPathDebugObjTotalString;
1680 reqBool = xmlXPathDebugObjTotalBool;
1681 reqNumber = xmlXPathDebugObjTotalNumber;
1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683 reqUndefined = xmlXPathDebugObjTotalUndefined;
1684
1685 printf("# XPath object usage:\n");
1686
1687 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001688 if (ctxt->cache != NULL) {
1689 xmlXPathContextCachePtr cache =
1690 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001691
1692 reAll = cache->dbgReusedAll;
1693 reqAll += reAll;
1694 reNodeset = cache->dbgReusedNodeset;
1695 reqNodeset += reNodeset;
1696 reString = cache->dbgReusedString;
1697 reqString += reString;
1698 reBool = cache->dbgReusedBool;
1699 reqBool += reBool;
1700 reNumber = cache->dbgReusedNumber;
1701 reqNumber += reNumber;
1702 reXSLTTree = cache->dbgReusedXSLTTree;
1703 reqXSLTTree += reXSLTTree;
1704 reUndefined = cache->dbgReusedUndefined;
1705 reqUndefined += reUndefined;
1706
1707 caAll = cache->dbgCachedAll;
1708 caBool = cache->dbgCachedBool;
1709 caNodeset = cache->dbgCachedNodeset;
1710 caString = cache->dbgCachedString;
1711 caNumber = cache->dbgCachedNumber;
1712 caXSLTTree = cache->dbgCachedXSLTTree;
1713 caUndefined = cache->dbgCachedUndefined;
1714
1715 if (cache->nodesetObjs)
1716 leftObjs -= cache->nodesetObjs->number;
1717 if (cache->stringObjs)
1718 leftObjs -= cache->stringObjs->number;
1719 if (cache->booleanObjs)
1720 leftObjs -= cache->booleanObjs->number;
1721 if (cache->numberObjs)
1722 leftObjs -= cache->numberObjs->number;
1723 if (cache->miscObjs)
1724 leftObjs -= cache->miscObjs->number;
1725 }
1726 }
1727
1728 printf("# all\n");
1729 printf("# total : %d\n", reqAll);
1730 printf("# left : %d\n", leftObjs);
1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1732 printf("# reused : %d\n", reAll);
1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1734
1735 printf("# node-sets\n");
1736 printf("# total : %d\n", reqNodeset);
1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1738 printf("# reused : %d\n", reNodeset);
1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741 printf("# strings\n");
1742 printf("# total : %d\n", reqString);
1743 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1744 printf("# reused : %d\n", reString);
1745 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1746
1747 printf("# booleans\n");
1748 printf("# total : %d\n", reqBool);
1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1750 printf("# reused : %d\n", reBool);
1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1752
1753 printf("# numbers\n");
1754 printf("# total : %d\n", reqNumber);
1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1756 printf("# reused : %d\n", reNumber);
1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759 printf("# XSLT result tree fragments\n");
1760 printf("# total : %d\n", reqXSLTTree);
1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762 printf("# reused : %d\n", reXSLTTree);
1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765 printf("# undefined\n");
1766 printf("# total : %d\n", reqUndefined);
1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1768 printf("# reused : %d\n", reUndefined);
1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771}
1772
1773#endif /* XP_DEBUG_OBJ_USAGE */
1774
Daniel Veillard017b1082001-06-21 11:20:21 +00001775#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001776
1777/************************************************************************
1778 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001779 * XPath object caching *
1780 * *
1781 ************************************************************************/
1782
1783/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001784 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001785 *
1786 * Create a new object cache
1787 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001788 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001789 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001790static xmlXPathContextCachePtr
1791xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001796 if (ret == NULL) {
1797 xmlXPathErrMemory(NULL, "creating object cache\n");
1798 return(NULL);
1799 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001801 ret->maxNodeset = 100;
1802 ret->maxString = 100;
1803 ret->maxBoolean = 100;
1804 ret->maxNumber = 100;
1805 ret->maxMisc = 100;
1806 return(ret);
1807}
1808
1809static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001810xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001811{
1812 int i;
1813 xmlXPathObjectPtr obj;
1814
1815 if (list == NULL)
1816 return;
1817
1818 for (i = 0; i < list->number; i++) {
1819 obj = list->items[i];
1820 /*
1821 * Note that it is already assured that we don't need to
1822 * look out for namespace nodes in the node-set.
1823 */
1824 if (obj->nodesetval != NULL) {
1825 if (obj->nodesetval->nodeTab != NULL)
1826 xmlFree(obj->nodesetval->nodeTab);
1827 xmlFree(obj->nodesetval);
1828 }
1829 xmlFree(obj);
1830#ifdef XP_DEBUG_OBJ_USAGE
1831 xmlXPathDebugObjCounterAll--;
1832#endif
1833 }
1834 xmlPointerListFree(list);
1835}
1836
1837static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001838xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001839{
1840 if (cache == NULL)
1841 return;
1842 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001843 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001844 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001851 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001852 xmlFree(cache);
1853}
1854
1855/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001856 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001857 *
1858 * @ctxt: the XPath context
1859 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001860 * @value: a value with semantics dependant on @options
1861 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001862 *
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001865 * to be reused.
1866 * @options:
1867 * 0: This will set the XPath object caching:
1868 * @value:
1869 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001870 * to be cached per slot
1871 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001872 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001874 *
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876 */
1877int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001878xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879 int active,
1880 int value,
1881 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001882{
1883 if (ctxt == NULL)
1884 return(-1);
1885 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001886 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001887
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001888 if (ctxt->cache == NULL) {
1889 ctxt->cache = xmlXPathNewCache();
1890 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001891 return(-1);
1892 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001893 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001894 if (options == 0) {
1895 if (value < 0)
1896 value = 100;
1897 cache->maxNodeset = value;
1898 cache->maxString = value;
1899 cache->maxNumber = value;
1900 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001901 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001902 }
1903 } else if (ctxt->cache != NULL) {
1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001906 }
1907 return(0);
1908}
1909
1910/**
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val: the NodePtr value
1914 *
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 *
1918 * Returns the created or reused object.
1919 */
1920static xmlXPathObjectPtr
1921xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001923 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924 xmlXPathContextCachePtr cache =
1925 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001926
1927 if ((cache->miscObjs != NULL) &&
1928 (cache->miscObjs->number != 0))
1929 {
1930 xmlXPathObjectPtr ret;
1931
1932 ret = (xmlXPathObjectPtr)
1933 cache->miscObjs->items[--cache->miscObjs->number];
1934 ret->type = XPATH_NODESET;
1935 ret->nodesetval = val;
1936#ifdef XP_DEBUG_OBJ_USAGE
1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938#endif
1939 return(ret);
1940 }
1941 }
1942
1943 return(xmlXPathWrapNodeSet(val));
1944
1945}
1946
1947/**
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val: the xmlChar * value
1951 *
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1954 *
1955 * Returns the created or reused object.
1956 */
1957static xmlXPathObjectPtr
1958xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001960 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001962
1963 if ((cache->stringObjs != NULL) &&
1964 (cache->stringObjs->number != 0))
1965 {
1966
1967 xmlXPathObjectPtr ret;
1968
1969 ret = (xmlXPathObjectPtr)
1970 cache->stringObjs->items[--cache->stringObjs->number];
1971 ret->type = XPATH_STRING;
1972 ret->stringval = val;
1973#ifdef XP_DEBUG_OBJ_USAGE
1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975#endif
1976 return(ret);
1977 } else if ((cache->miscObjs != NULL) &&
1978 (cache->miscObjs->number != 0))
1979 {
1980 xmlXPathObjectPtr ret;
1981 /*
1982 * Fallback to misc-cache.
1983 */
1984 ret = (xmlXPathObjectPtr)
1985 cache->miscObjs->items[--cache->miscObjs->number];
1986
1987 ret->type = XPATH_STRING;
1988 ret->stringval = val;
1989#ifdef XP_DEBUG_OBJ_USAGE
1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991#endif
1992 return(ret);
1993 }
1994 }
1995 return(xmlXPathWrapString(val));
1996}
1997
1998/**
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val: the NodePtr value
2002 *
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2006 *
2007 * Returns the created or reused object.
2008 */
2009static xmlXPathObjectPtr
2010xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002012 if ((ctxt != NULL) && (ctxt->cache)) {
2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002014
2015 if ((cache->nodesetObjs != NULL) &&
2016 (cache->nodesetObjs->number != 0))
2017 {
2018 xmlXPathObjectPtr ret;
2019 /*
2020 * Use the nodset-cache.
2021 */
2022 ret = (xmlXPathObjectPtr)
2023 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024 ret->type = XPATH_NODESET;
2025 ret->boolval = 0;
2026 if (val) {
2027 if ((ret->nodesetval->nodeMax == 0) ||
2028 (val->type == XML_NAMESPACE_DECL))
2029 {
2030 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031 } else {
2032 ret->nodesetval->nodeTab[0] = val;
2033 ret->nodesetval->nodeNr = 1;
2034 }
2035 }
2036#ifdef XP_DEBUG_OBJ_USAGE
2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038#endif
2039 return(ret);
2040 } else if ((cache->miscObjs != NULL) &&
2041 (cache->miscObjs->number != 0))
2042 {
2043 xmlXPathObjectPtr ret;
2044 /*
2045 * Fallback to misc-cache.
2046 */
2047
2048 ret = (xmlXPathObjectPtr)
2049 cache->miscObjs->items[--cache->miscObjs->number];
2050
2051 ret->type = XPATH_NODESET;
2052 ret->boolval = 0;
2053 ret->nodesetval = xmlXPathNodeSetCreate(val);
2054#ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056#endif
2057 return(ret);
2058 }
2059 }
2060 return(xmlXPathNewNodeSet(val));
2061}
2062
2063/**
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val: the char * value
2067 *
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 *
2071 * Returns the created or reused object.
2072 */
2073static xmlXPathObjectPtr
2074xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002076 if ((ctxt != NULL) && (ctxt->cache)) {
2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002078
2079 if ((cache->stringObjs != NULL) &&
2080 (cache->stringObjs->number != 0))
2081 {
2082 xmlXPathObjectPtr ret;
2083
2084 ret = (xmlXPathObjectPtr)
2085 cache->stringObjs->items[--cache->stringObjs->number];
2086
2087 ret->type = XPATH_STRING;
2088 ret->stringval = xmlStrdup(BAD_CAST val);
2089#ifdef XP_DEBUG_OBJ_USAGE
2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091#endif
2092 return(ret);
2093 } else if ((cache->miscObjs != NULL) &&
2094 (cache->miscObjs->number != 0))
2095 {
2096 xmlXPathObjectPtr ret;
2097
2098 ret = (xmlXPathObjectPtr)
2099 cache->miscObjs->items[--cache->miscObjs->number];
2100
2101 ret->type = XPATH_STRING;
2102 ret->stringval = xmlStrdup(BAD_CAST val);
2103#ifdef XP_DEBUG_OBJ_USAGE
2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105#endif
2106 return(ret);
2107 }
2108 }
2109 return(xmlXPathNewCString(val));
2110}
2111
2112/**
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val: the xmlChar * value
2116 *
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 *
2120 * Returns the created or reused object.
2121 */
2122static xmlXPathObjectPtr
2123xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002125 if ((ctxt != NULL) && (ctxt->cache)) {
2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002127
2128 if ((cache->stringObjs != NULL) &&
2129 (cache->stringObjs->number != 0))
2130 {
2131 xmlXPathObjectPtr ret;
2132
2133 ret = (xmlXPathObjectPtr)
2134 cache->stringObjs->items[--cache->stringObjs->number];
2135 ret->type = XPATH_STRING;
2136 if (val != NULL)
2137 ret->stringval = xmlStrdup(val);
2138 else
2139 ret->stringval = xmlStrdup((const xmlChar *)"");
2140#ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142#endif
2143 return(ret);
2144 } else if ((cache->miscObjs != NULL) &&
2145 (cache->miscObjs->number != 0))
2146 {
2147 xmlXPathObjectPtr ret;
2148
2149 ret = (xmlXPathObjectPtr)
2150 cache->miscObjs->items[--cache->miscObjs->number];
2151
2152 ret->type = XPATH_STRING;
2153 if (val != NULL)
2154 ret->stringval = xmlStrdup(val);
2155 else
2156 ret->stringval = xmlStrdup((const xmlChar *)"");
2157#ifdef XP_DEBUG_OBJ_USAGE
2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159#endif
2160 return(ret);
2161 }
2162 }
2163 return(xmlXPathNewString(val));
2164}
2165
2166/**
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val: the boolean value
2170 *
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 *
2174 * Returns the created or reused object.
2175 */
2176static xmlXPathObjectPtr
2177xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002179 if ((ctxt != NULL) && (ctxt->cache)) {
2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002181
2182 if ((cache->booleanObjs != NULL) &&
2183 (cache->booleanObjs->number != 0))
2184 {
2185 xmlXPathObjectPtr ret;
2186
2187 ret = (xmlXPathObjectPtr)
2188 cache->booleanObjs->items[--cache->booleanObjs->number];
2189 ret->type = XPATH_BOOLEAN;
2190 ret->boolval = (val != 0);
2191#ifdef XP_DEBUG_OBJ_USAGE
2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193#endif
2194 return(ret);
2195 } else if ((cache->miscObjs != NULL) &&
2196 (cache->miscObjs->number != 0))
2197 {
2198 xmlXPathObjectPtr ret;
2199
2200 ret = (xmlXPathObjectPtr)
2201 cache->miscObjs->items[--cache->miscObjs->number];
2202
2203 ret->type = XPATH_BOOLEAN;
2204 ret->boolval = (val != 0);
2205#ifdef XP_DEBUG_OBJ_USAGE
2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207#endif
2208 return(ret);
2209 }
2210 }
2211 return(xmlXPathNewBoolean(val));
2212}
2213
2214/**
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val: the double value
2218 *
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 *
2222 * Returns the created or reused object.
2223 */
2224static xmlXPathObjectPtr
2225xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002227 if ((ctxt != NULL) && (ctxt->cache)) {
2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002229
2230 if ((cache->numberObjs != NULL) &&
2231 (cache->numberObjs->number != 0))
2232 {
2233 xmlXPathObjectPtr ret;
2234
2235 ret = (xmlXPathObjectPtr)
2236 cache->numberObjs->items[--cache->numberObjs->number];
2237 ret->type = XPATH_NUMBER;
2238 ret->floatval = val;
2239#ifdef XP_DEBUG_OBJ_USAGE
2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241#endif
2242 return(ret);
2243 } else if ((cache->miscObjs != NULL) &&
2244 (cache->miscObjs->number != 0))
2245 {
2246 xmlXPathObjectPtr ret;
2247
2248 ret = (xmlXPathObjectPtr)
2249 cache->miscObjs->items[--cache->miscObjs->number];
2250
2251 ret->type = XPATH_NUMBER;
2252 ret->floatval = val;
2253#ifdef XP_DEBUG_OBJ_USAGE
2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255#endif
2256 return(ret);
2257 }
2258 }
2259 return(xmlXPathNewFloat(val));
2260}
2261
2262/**
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val: an XPath object
2266 *
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2269 *
2270 * Returns a created or reused object, the old one is freed (cached)
2271 * (or the operation is done directly on @val)
2272 */
2273
2274static xmlXPathObjectPtr
2275xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276 xmlChar *res = NULL;
2277
2278 if (val == NULL)
2279 return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281 switch (val->type) {
2282 case XPATH_UNDEFINED:
2283#ifdef DEBUG_EXPR
2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285#endif
2286 break;
2287 case XPATH_NODESET:
2288 case XPATH_XSLT_TREE:
2289 res = xmlXPathCastNodeSetToString(val->nodesetval);
2290 break;
2291 case XPATH_STRING:
2292 return(val);
2293 case XPATH_BOOLEAN:
2294 res = xmlXPathCastBooleanToString(val->boolval);
2295 break;
2296 case XPATH_NUMBER:
2297 res = xmlXPathCastNumberToString(val->floatval);
2298 break;
2299 case XPATH_USERS:
2300 case XPATH_POINT:
2301 case XPATH_RANGE:
2302 case XPATH_LOCATIONSET:
2303 TODO;
2304 break;
2305 }
2306 xmlXPathReleaseObject(ctxt, val);
2307 if (res == NULL)
2308 return(xmlXPathCacheNewCString(ctxt, ""));
2309 return(xmlXPathCacheWrapString(ctxt, res));
2310}
2311
2312/**
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val: the original object
2316 *
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2319 *
2320 * Returns a created or reused created object.
2321 */
2322static xmlXPathObjectPtr
2323xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324{
2325 if (val == NULL)
2326 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002327
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002328 if (XP_HAS_CACHE(ctxt)) {
2329 switch (val->type) {
2330 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002331 return(xmlXPathCacheWrapNodeSet(ctxt,
2332 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002333 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002335 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002337 case XPATH_NUMBER:
2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339 default:
2340 break;
2341 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002342 }
2343 return(xmlXPathObjectCopy(val));
2344}
2345
2346/**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val: an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 * is done directly on @val)
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359 xmlXPathObjectPtr ret;
2360
2361 if (val == NULL)
2362 return(xmlXPathCacheNewBoolean(ctxt, 0));
2363 if (val->type == XPATH_BOOLEAN)
2364 return(val);
2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366 xmlXPathReleaseObject(ctxt, val);
2367 return(ret);
2368}
2369
2370/**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val: an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 * is done directly on @val)
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383 xmlXPathObjectPtr ret;
2384
2385 if (val == NULL)
2386 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387 if (val->type == XPATH_NUMBER)
2388 return(val);
2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390 xmlXPathReleaseObject(ctxt, val);
2391 return(ret);
2392}
2393
2394/************************************************************************
2395 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002396 * Parser stacks related functions and macros *
2397 * *
2398 ************************************************************************/
2399
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002400/**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002408xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002409valuePop(xmlXPathParserContextPtr ctxt)
2410{
2411 xmlXPathObjectPtr ret;
2412
Daniel Veillarda82b1822004-11-08 16:24:57 +00002413 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002414 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002415 ctxt->valueNr--;
2416 if (ctxt->valueNr > 0)
2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418 else
2419 ctxt->value = NULL;
2420 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002421 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002422 return (ret);
2423}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002424/**
2425 * valuePush:
2426 * @ctxt: an XPath evaluation context
2427 * @value: the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002430 *
2431 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002432 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002433int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002436 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002437 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002438 xmlXPathObjectPtr *tmp;
2439
2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002443 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445 return (0);
2446 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002447 ctxt->valueMax *= 2;
2448 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002449 }
2450 ctxt->valueTab[ctxt->valueNr] = value;
2451 ctxt->value = value;
2452 return (ctxt->valueNr++);
2453}
Owen Taylor3473f882001-02-23 17:55:21 +00002454
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002455/**
2456 * xmlXPathPopBoolean:
2457 * @ctxt: an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464int
2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466 xmlXPathObjectPtr obj;
2467 int ret;
2468
2469 obj = valuePop(ctxt);
2470 if (obj == NULL) {
2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472 return(0);
2473 }
William M. Brack08171912003-12-29 02:52:11 +00002474 if (obj->type != XPATH_BOOLEAN)
2475 ret = xmlXPathCastToBoolean(obj);
2476 else
2477 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002478 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002479 return(ret);
2480}
2481
2482/**
2483 * xmlXPathPopNumber:
2484 * @ctxt: an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491double
2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493 xmlXPathObjectPtr obj;
2494 double ret;
2495
2496 obj = valuePop(ctxt);
2497 if (obj == NULL) {
2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499 return(0);
2500 }
William M. Brack08171912003-12-29 02:52:11 +00002501 if (obj->type != XPATH_NUMBER)
2502 ret = xmlXPathCastToNumber(obj);
2503 else
2504 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002505 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002506 return(ret);
2507}
2508
2509/**
2510 * xmlXPathPopString:
2511 * @ctxt: an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518xmlChar *
2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520 xmlXPathObjectPtr obj;
2521 xmlChar * ret;
2522
2523 obj = valuePop(ctxt);
2524 if (obj == NULL) {
2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526 return(NULL);
2527 }
William M. Brack08171912003-12-29 02:52:11 +00002528 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002529 /* TODO: needs refactoring somewhere else */
2530 if (obj->stringval == ret)
2531 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002532 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002533 return(ret);
2534}
2535
2536/**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt: an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545xmlNodeSetPtr
2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547 xmlXPathObjectPtr obj;
2548 xmlNodeSetPtr ret;
2549
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002550 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002551 if (ctxt->value == NULL) {
2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553 return(NULL);
2554 }
2555 if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 xmlXPathSetTypeError(ctxt);
2557 return(NULL);
2558 }
2559 obj = valuePop(ctxt);
2560 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002561#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002562 /* to fix memory leak of not clearing obj->user */
2563 if (obj->boolval && obj->user != NULL)
2564 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002565#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002566 obj->nodesetval = NULL;
2567 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002568 return(ret);
2569}
2570
2571/**
2572 * xmlXPathPopExternal:
2573 * @ctxt: an XPath parser context
2574 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002575 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580void *
2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582 xmlXPathObjectPtr obj;
2583 void * ret;
2584
Daniel Veillarda82b1822004-11-08 16:24:57 +00002585 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587 return(NULL);
2588 }
2589 if (ctxt->value->type != XPATH_USERS) {
2590 xmlXPathSetTypeError(ctxt);
2591 return(NULL);
2592 }
2593 obj = valuePop(ctxt);
2594 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002595 obj->user = NULL;
2596 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002597 return(ret);
2598}
2599
Owen Taylor3473f882001-02-23 17:55:21 +00002600/*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 * CUR returns the current xmlChar value, i.e. a 8 bit value
2608 * in ISO-Latin or UTF-8.
2609 * This should be used internally by the parser
2610 * only to compare to ASCII values otherwise it would break when
2611 * running with UTF-8 encoding.
2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2613 * to compare on ASCII based substring.
2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 * strings within the parser.
2616 * CURRENT Returns the current char value, with the full decoding of
2617 * UTF-8 if we are using this mode. It returns an int.
2618 * NEXT Skip to the next character, this does the proper decoding
2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 * It returns the pointer to the current xmlChar.
2621 */
2622
2623#define CUR (*ctxt->cur)
2624#define SKIP(val) ctxt->cur += (val)
2625#define NXT(val) ctxt->cur[(val)]
2626#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629#define COPY_BUF(l,b,i,v) \
2630 if (l == 1) b[i++] = (xmlChar) v; \
2631 else i += xmlCopyChar(l,&b[i],v)
2632
2633#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002634
2635#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638#define CURRENT (*ctxt->cur)
2639#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2640
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002641
2642#ifndef DBL_DIG
2643#define DBL_DIG 16
2644#endif
2645#ifndef DBL_EPSILON
2646#define DBL_EPSILON 1E-9
2647#endif
2648
2649#define UPPER_DOUBLE 1E9
2650#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002651#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002652
2653#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002654#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002655#define EXPONENT_DIGITS (3 + 2)
2656
2657/**
2658 * xmlXPathFormatNumber:
2659 * @number: number to format
2660 * @buffer: output buffer
2661 * @buffersize: size of output buffer
2662 *
2663 * Convert the number into a string representation.
2664 */
2665static void
2666xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667{
Daniel Veillardcda96922001-08-21 10:56:31 +00002668 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002669 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002670 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002671 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002672 break;
2673 case -1:
2674 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002675 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002676 break;
2677 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002678 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002679 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002680 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002681 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002682 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002683 } else if (number == ((int) number)) {
2684 char work[30];
2685 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002686 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687
2688 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002689 if (value == 0) {
2690 *ptr++ = '0';
2691 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002692 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002693 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002694 while ((*cur) && (ptr - buffer < buffersize)) {
2695 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002696 }
2697 }
2698 if (ptr - buffer < buffersize) {
2699 *ptr = 0;
2700 } else if (buffersize > 0) {
2701 ptr--;
2702 *ptr = 0;
2703 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002704 } else {
William M. Brackca797882007-05-11 14:45:53 +00002705 /*
2706 For the dimension of work,
2707 DBL_DIG is number of significant digits
2708 EXPONENT is only needed for "scientific notation"
2709 3 is sign, decimal point, and terminating zero
2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711 Note that this dimension is slightly (a few characters)
2712 larger than actually necessary.
2713 */
2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002715 int integer_place, fraction_place;
2716 char *ptr;
2717 char *after_fraction;
2718 double absolute_value;
2719 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002720
Bjorn Reese70a9da52001-04-21 16:57:29 +00002721 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002722
Bjorn Reese70a9da52001-04-21 16:57:29 +00002723 /*
2724 * First choose format - scientific or regular floating point.
2725 * In either case, result is in work, and after_fraction points
2726 * just past the fractional part.
2727 */
2728 if ( ((absolute_value > UPPER_DOUBLE) ||
2729 (absolute_value < LOWER_DOUBLE)) &&
2730 (absolute_value != 0.0) ) {
2731 /* Use scientific notation */
2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002734 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002735 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002736 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002737
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002738 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002739 else {
2740 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002741 if (absolute_value > 0.0) {
2742 integer_place = (int)log10(absolute_value);
2743 if (integer_place > 0)
2744 fraction_place = DBL_DIG - integer_place - 1;
2745 else
2746 fraction_place = DBL_DIG - integer_place;
2747 } else {
2748 fraction_place = 1;
2749 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002750 size = snprintf(work, sizeof(work), "%0.*f",
2751 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002752 }
2753
Bjorn Reese70a9da52001-04-21 16:57:29 +00002754 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002755 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002756 ptr = after_fraction;
2757 while (*(--ptr) == '0')
2758 ;
2759 if (*ptr != '.')
2760 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002761 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002762
2763 /* Finally copy result back to caller */
2764 size = strlen(work) + 1;
2765 if (size > buffersize) {
2766 work[buffersize - 1] = 0;
2767 size = buffersize;
2768 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002769 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002770 }
2771 break;
2772 }
2773}
2774
Owen Taylor3473f882001-02-23 17:55:21 +00002775
2776/************************************************************************
2777 * *
2778 * Routines to handle NodeSets *
2779 * *
2780 ************************************************************************/
2781
2782/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002783 * xmlXPathOrderDocElems:
2784 * @doc: an input document
2785 *
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002791 *
William M. Brack08171912003-12-29 02:52:11 +00002792 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002793 * of error.
2794 */
2795long
2796xmlXPathOrderDocElems(xmlDocPtr doc) {
2797 long count = 0;
2798 xmlNodePtr cur;
2799
2800 if (doc == NULL)
2801 return(-1);
2802 cur = doc->children;
2803 while (cur != NULL) {
2804 if (cur->type == XML_ELEMENT_NODE) {
2805 cur->content = (void *) (-(++count));
2806 if (cur->children != NULL) {
2807 cur = cur->children;
2808 continue;
2809 }
2810 }
2811 if (cur->next != NULL) {
2812 cur = cur->next;
2813 continue;
2814 }
2815 do {
2816 cur = cur->parent;
2817 if (cur == NULL)
2818 break;
2819 if (cur == (xmlNodePtr) doc) {
2820 cur = NULL;
2821 break;
2822 }
2823 if (cur->next != NULL) {
2824 cur = cur->next;
2825 break;
2826 }
2827 } while (cur != NULL);
2828 }
2829 return(count);
2830}
2831
2832/**
Owen Taylor3473f882001-02-23 17:55:21 +00002833 * xmlXPathCmpNodes:
2834 * @node1: the first node
2835 * @node2: the second node
2836 *
2837 * Compare two nodes w.r.t document order
2838 *
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002840 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002841 */
2842int
2843xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002845 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002847 xmlNodePtr cur, root;
2848
2849 if ((node1 == NULL) || (node2 == NULL))
2850 return(-2);
2851 /*
2852 * a couple of optimizations which will avoid computations in most cases
2853 */
William M. Brackee0b9822007-03-07 08:15:01 +00002854 if (node1 == node2) /* trivial case */
2855 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002856 if (node1->type == XML_ATTRIBUTE_NODE) {
2857 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002858 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002859 node1 = node1->parent;
2860 }
2861 if (node2->type == XML_ATTRIBUTE_NODE) {
2862 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002863 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002864 node2 = node2->parent;
2865 }
2866 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002867 if (attr1 == attr2) {
2868 /* not required, but we keep attributes in order */
2869 if (attr1 != 0) {
2870 cur = attrNode2->prev;
2871 while (cur != NULL) {
2872 if (cur == attrNode1)
2873 return (1);
2874 cur = cur->prev;
2875 }
2876 return (-1);
2877 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002878 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002879 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002880 if (attr2 == 1)
2881 return(1);
2882 return(-1);
2883 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002884 if ((node1->type == XML_NAMESPACE_DECL) ||
2885 (node2->type == XML_NAMESPACE_DECL))
2886 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002887 if (node1 == node2->prev)
2888 return(1);
2889 if (node1 == node2->next)
2890 return(-1);
2891
2892 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002893 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002894 */
2895 if ((node1->type == XML_ELEMENT_NODE) &&
2896 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002897 (0 > (long) node1->content) &&
2898 (0 > (long) node2->content) &&
2899 (node1->doc == node2->doc)) {
2900 long l1, l2;
2901
2902 l1 = -((long) node1->content);
2903 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002904 if (l1 < l2)
2905 return(1);
2906 if (l1 > l2)
2907 return(-1);
2908 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002909
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002910 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002911 * compute depth to root
2912 */
2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914 if (cur == node1)
2915 return(1);
2916 depth2++;
2917 }
2918 root = cur;
2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920 if (cur == node2)
2921 return(-1);
2922 depth1++;
2923 }
2924 /*
2925 * Distinct document (or distinct entities :-( ) case.
2926 */
2927 if (root != cur) {
2928 return(-2);
2929 }
2930 /*
2931 * get the nearest common ancestor.
2932 */
2933 while (depth1 > depth2) {
2934 depth1--;
2935 node1 = node1->parent;
2936 }
2937 while (depth2 > depth1) {
2938 depth2--;
2939 node2 = node2->parent;
2940 }
2941 while (node1->parent != node2->parent) {
2942 node1 = node1->parent;
2943 node2 = node2->parent;
2944 /* should not happen but just in case ... */
2945 if ((node1 == NULL) || (node2 == NULL))
2946 return(-2);
2947 }
2948 /*
2949 * Find who's first.
2950 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002951 if (node1 == node2->prev)
2952 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 if (node1 == node2->next)
2954 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002955 /*
2956 * Speedup using document order if availble.
2957 */
2958 if ((node1->type == XML_ELEMENT_NODE) &&
2959 (node2->type == XML_ELEMENT_NODE) &&
2960 (0 > (long) node1->content) &&
2961 (0 > (long) node2->content) &&
2962 (node1->doc == node2->doc)) {
2963 long l1, l2;
2964
2965 l1 = -((long) node1->content);
2966 l2 = -((long) node2->content);
2967 if (l1 < l2)
2968 return(1);
2969 if (l1 > l2)
2970 return(-1);
2971 }
2972
Owen Taylor3473f882001-02-23 17:55:21 +00002973 for (cur = node1->next;cur != NULL;cur = cur->next)
2974 if (cur == node2)
2975 return(1);
2976 return(-1); /* assume there is no sibling list corruption */
2977}
2978
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002979#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002980/**
2981 * xmlXPathCmpNodesExt:
2982 * @node1: the first node
2983 * @node2: the second node
2984 *
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2987 *
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 * it's the same node, -1 otherwise
2990 */
2991static int
2992xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993 int depth1, depth2;
2994 int misc = 0, precedence1 = 0, precedence2 = 0;
2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002998
2999 if ((node1 == NULL) || (node2 == NULL))
3000 return(-2);
3001
3002 if (node1 == node2)
3003 return(0);
3004
3005 /*
3006 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003007 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003008 switch (node1->type) {
3009 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003010 if (node2->type == XML_ELEMENT_NODE) {
3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012 (0 > (long) node2->content) &&
3013 (node1->doc == node2->doc))
3014 {
3015 l1 = -((long) node1->content);
3016 l2 = -((long) node2->content);
3017 if (l1 < l2)
3018 return(1);
3019 if (l1 > l2)
3020 return(-1);
3021 } else
3022 goto turtle_comparison;
3023 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003024 break;
3025 case XML_ATTRIBUTE_NODE:
3026 precedence1 = 1; /* element is owner */
3027 miscNode1 = node1;
3028 node1 = node1->parent;
3029 misc = 1;
3030 break;
3031 case XML_TEXT_NODE:
3032 case XML_CDATA_SECTION_NODE:
3033 case XML_COMMENT_NODE:
3034 case XML_PI_NODE: {
3035 miscNode1 = node1;
3036 /*
3037 * Find nearest element node.
3038 */
3039 if (node1->prev != NULL) {
3040 do {
3041 node1 = node1->prev;
3042 if (node1->type == XML_ELEMENT_NODE) {
3043 precedence1 = 3; /* element in prev-sibl axis */
3044 break;
3045 }
3046 if (node1->prev == NULL) {
3047 precedence1 = 2; /* element is parent */
3048 /*
3049 * URGENT TODO: Are there any cases, where the
3050 * parent of such a node is not an element node?
3051 */
3052 node1 = node1->parent;
3053 break;
3054 }
3055 } while (1);
3056 } else {
3057 precedence1 = 2; /* element is parent */
3058 node1 = node1->parent;
3059 }
William M. Brack31700e62007-06-13 20:33:02 +00003060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061 (0 <= (long) node1->content)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003062 /*
3063 * Fallback for whatever case.
3064 */
3065 node1 = miscNode1;
3066 precedence1 = 0;
3067 } else
3068 misc = 1;
3069 }
3070 break;
3071 case XML_NAMESPACE_DECL:
3072 /*
3073 * TODO: why do we return 1 for namespace nodes?
3074 */
3075 return(1);
3076 default:
3077 break;
3078 }
3079 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003080 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003081 break;
3082 case XML_ATTRIBUTE_NODE:
3083 precedence2 = 1; /* element is owner */
3084 miscNode2 = node2;
3085 node2 = node2->parent;
3086 misc = 1;
3087 break;
3088 case XML_TEXT_NODE:
3089 case XML_CDATA_SECTION_NODE:
3090 case XML_COMMENT_NODE:
3091 case XML_PI_NODE: {
3092 miscNode2 = node2;
3093 if (node2->prev != NULL) {
3094 do {
3095 node2 = node2->prev;
3096 if (node2->type == XML_ELEMENT_NODE) {
3097 precedence2 = 3; /* element in prev-sibl axis */
3098 break;
3099 }
3100 if (node2->prev == NULL) {
3101 precedence2 = 2; /* element is parent */
3102 node2 = node2->parent;
3103 break;
3104 }
3105 } while (1);
3106 } else {
3107 precedence2 = 2; /* element is parent */
3108 node2 = node2->parent;
3109 }
3110 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111 (0 <= (long) node1->content))
3112 {
3113 node2 = miscNode2;
3114 precedence2 = 0;
3115 } else
3116 misc = 1;
3117 }
3118 break;
3119 case XML_NAMESPACE_DECL:
3120 return(1);
3121 default:
3122 break;
3123 }
3124 if (misc) {
3125 if (node1 == node2) {
3126 if (precedence1 == precedence2) {
3127 /*
3128 * The ugly case; but normally there aren't many
3129 * adjacent non-element nodes around.
3130 */
3131 cur = miscNode2->prev;
3132 while (cur != NULL) {
3133 if (cur == miscNode1)
3134 return(1);
3135 if (cur->type == XML_ELEMENT_NODE)
3136 return(-1);
3137 cur = cur->prev;
3138 }
3139 return (-1);
3140 } else {
3141 /*
3142 * Evaluate based on higher precedence wrt to the element.
3143 * TODO: This assumes attributes are sorted before content.
3144 * Is this 100% correct?
3145 */
3146 if (precedence1 < precedence2)
3147 return(1);
3148 else
3149 return(-1);
3150 }
3151 }
3152 /*
3153 * Special case: One of the helper-elements is contained by the other.
3154 * <foo>
3155 * <node2>
3156 * <node1>Text-1(precedence1 == 2)</node1>
3157 * </node2>
3158 * Text-6(precedence2 == 3)
3159 * </foo>
3160 */
3161 if ((precedence2 == 3) && (precedence1 > 1)) {
3162 cur = node1->parent;
3163 while (cur) {
3164 if (cur == node2)
3165 return(1);
3166 cur = cur->parent;
3167 }
3168 }
3169 if ((precedence1 == 3) && (precedence2 > 1)) {
3170 cur = node2->parent;
3171 while (cur) {
3172 if (cur == node1)
3173 return(-1);
3174 cur = cur->parent;
3175 }
3176 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003177 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003178
3179 /*
3180 * Speedup using document order if availble.
3181 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003182 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003183 (node2->type == XML_ELEMENT_NODE) &&
3184 (0 > (long) node1->content) &&
3185 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003186 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003187
3188 l1 = -((long) node1->content);
3189 l2 = -((long) node2->content);
3190 if (l1 < l2)
3191 return(1);
3192 if (l1 > l2)
3193 return(-1);
3194 }
3195
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003196turtle_comparison:
3197
3198 if (node1 == node2->prev)
3199 return(1);
3200 if (node1 == node2->next)
3201 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003202 /*
3203 * compute depth to root
3204 */
3205 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3206 if (cur == node1)
3207 return(1);
3208 depth2++;
3209 }
3210 root = cur;
3211 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3212 if (cur == node2)
3213 return(-1);
3214 depth1++;
3215 }
3216 /*
3217 * Distinct document (or distinct entities :-( ) case.
3218 */
3219 if (root != cur) {
3220 return(-2);
3221 }
3222 /*
3223 * get the nearest common ancestor.
3224 */
3225 while (depth1 > depth2) {
3226 depth1--;
3227 node1 = node1->parent;
3228 }
3229 while (depth2 > depth1) {
3230 depth2--;
3231 node2 = node2->parent;
3232 }
3233 while (node1->parent != node2->parent) {
3234 node1 = node1->parent;
3235 node2 = node2->parent;
3236 /* should not happen but just in case ... */
3237 if ((node1 == NULL) || (node2 == NULL))
3238 return(-2);
3239 }
3240 /*
3241 * Find who's first.
3242 */
3243 if (node1 == node2->prev)
3244 return(1);
3245 if (node1 == node2->next)
3246 return(-1);
3247 /*
3248 * Speedup using document order if availble.
3249 */
3250 if ((node1->type == XML_ELEMENT_NODE) &&
3251 (node2->type == XML_ELEMENT_NODE) &&
3252 (0 > (long) node1->content) &&
3253 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003254 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003255
3256 l1 = -((long) node1->content);
3257 l2 = -((long) node2->content);
3258 if (l1 < l2)
3259 return(1);
3260 if (l1 > l2)
3261 return(-1);
3262 }
3263
3264 for (cur = node1->next;cur != NULL;cur = cur->next)
3265 if (cur == node2)
3266 return(1);
3267 return(-1); /* assume there is no sibling list corruption */
3268}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003269#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003270
Owen Taylor3473f882001-02-23 17:55:21 +00003271/**
3272 * xmlXPathNodeSetSort:
3273 * @set: the node set
3274 *
3275 * Sort the node set in document order
3276 */
3277void
3278xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003279 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003280 xmlNodePtr tmp;
3281
3282 if (set == NULL)
3283 return;
3284
3285 /* Use Shell's sort to sort the node-set */
3286 len = set->nodeNr;
3287 for (incr = len / 2; incr > 0; incr /= 2) {
3288 for (i = incr; i < len; i++) {
3289 j = i - incr;
3290 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003291#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003292 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293 set->nodeTab[j + incr]) == -1)
3294#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003295 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003296 set->nodeTab[j + incr]) == -1)
3297#endif
3298 {
Owen Taylor3473f882001-02-23 17:55:21 +00003299 tmp = set->nodeTab[j];
3300 set->nodeTab[j] = set->nodeTab[j + incr];
3301 set->nodeTab[j + incr] = tmp;
3302 j -= incr;
3303 } else
3304 break;
3305 }
3306 }
3307 }
3308}
3309
3310#define XML_NODESET_DEFAULT 10
3311/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003312 * xmlXPathNodeSetDupNs:
3313 * @node: the parent node of the namespace XPath node
3314 * @ns: the libxml namespace declaration node.
3315 *
3316 * Namespace node in libxml don't match the XPath semantic. In a node set
3317 * the namespace nodes are duplicated and the next pointer is set to the
3318 * parent node in the XPath semantic.
3319 *
3320 * Returns the newly created object.
3321 */
3322static xmlNodePtr
3323xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3324 xmlNsPtr cur;
3325
3326 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3327 return(NULL);
3328 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329 return((xmlNodePtr) ns);
3330
3331 /*
3332 * Allocate a new Namespace and fill the fields.
3333 */
3334 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3335 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003336 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003337 return(NULL);
3338 }
3339 memset(cur, 0, sizeof(xmlNs));
3340 cur->type = XML_NAMESPACE_DECL;
3341 if (ns->href != NULL)
3342 cur->href = xmlStrdup(ns->href);
3343 if (ns->prefix != NULL)
3344 cur->prefix = xmlStrdup(ns->prefix);
3345 cur->next = (xmlNsPtr) node;
3346 return((xmlNodePtr) cur);
3347}
3348
3349/**
3350 * xmlXPathNodeSetFreeNs:
3351 * @ns: the XPath namespace node found in a nodeset.
3352 *
William M. Brack08171912003-12-29 02:52:11 +00003353 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003354 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003355 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003356 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003357void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003358xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3360 return;
3361
3362 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363 if (ns->href != NULL)
3364 xmlFree((xmlChar *)ns->href);
3365 if (ns->prefix != NULL)
3366 xmlFree((xmlChar *)ns->prefix);
3367 xmlFree(ns);
3368 }
3369}
3370
3371/**
Owen Taylor3473f882001-02-23 17:55:21 +00003372 * xmlXPathNodeSetCreate:
3373 * @val: an initial xmlNodePtr, or NULL
3374 *
3375 * Create a new xmlNodeSetPtr of type double and of value @val
3376 *
3377 * Returns the newly created object.
3378 */
3379xmlNodeSetPtr
3380xmlXPathNodeSetCreate(xmlNodePtr val) {
3381 xmlNodeSetPtr ret;
3382
3383 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3384 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003385 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003386 return(NULL);
3387 }
3388 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3389 if (val != NULL) {
3390 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391 sizeof(xmlNodePtr));
3392 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003393 xmlXPathErrMemory(NULL, "creating nodeset\n");
3394 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003395 return(NULL);
3396 }
3397 memset(ret->nodeTab, 0 ,
3398 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003400 if (val->type == XML_NAMESPACE_DECL) {
3401 xmlNsPtr ns = (xmlNsPtr) val;
3402
3403 ret->nodeTab[ret->nodeNr++] =
3404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3405 } else
3406 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003407 }
3408 return(ret);
3409}
3410
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003411/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003412 * xmlXPathNodeSetCreateSize:
3413 * @size: the initial size of the set
3414 *
3415 * Create a new xmlNodeSetPtr of type double and of value @val
3416 *
3417 * Returns the newly created object.
3418 */
3419static xmlNodeSetPtr
3420xmlXPathNodeSetCreateSize(int size) {
3421 xmlNodeSetPtr ret;
3422
3423 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3424 if (ret == NULL) {
3425 xmlXPathErrMemory(NULL, "creating nodeset\n");
3426 return(NULL);
3427 }
3428 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429 if (size < XML_NODESET_DEFAULT)
3430 size = XML_NODESET_DEFAULT;
3431 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432 if (ret->nodeTab == NULL) {
3433 xmlXPathErrMemory(NULL, "creating nodeset\n");
3434 xmlFree(ret);
3435 return(NULL);
3436 }
3437 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3438 ret->nodeMax = size;
3439 return(ret);
3440}
3441
3442/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003443 * xmlXPathNodeSetContains:
3444 * @cur: the node-set
3445 * @val: the node
3446 *
3447 * checks whether @cur contains @val
3448 *
3449 * Returns true (1) if @cur contains @val, false (0) otherwise
3450 */
3451int
3452xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3453 int i;
3454
Daniel Veillarda82b1822004-11-08 16:24:57 +00003455 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003456 if (val->type == XML_NAMESPACE_DECL) {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3459 xmlNsPtr ns1, ns2;
3460
3461 ns1 = (xmlNsPtr) val;
3462 ns2 = (xmlNsPtr) cur->nodeTab[i];
3463 if (ns1 == ns2)
3464 return(1);
3465 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3467 return(1);
3468 }
3469 }
3470 } else {
3471 for (i = 0; i < cur->nodeNr; i++) {
3472 if (cur->nodeTab[i] == val)
3473 return(1);
3474 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003475 }
3476 return(0);
3477}
3478
3479/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 * xmlXPathNodeSetAddNs:
3481 * @cur: the initial node set
3482 * @node: the hosting node
3483 * @ns: a the namespace node
3484 *
3485 * add a new namespace node to an existing NodeSet
3486 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003487void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003488xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3489 int i;
3490
Daniel Veillarda82b1822004-11-08 16:24:57 +00003491
3492 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003494 (node->type != XML_ELEMENT_NODE))
3495 return;
3496
William M. Brack08171912003-12-29 02:52:11 +00003497 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003498 /*
William M. Brack08171912003-12-29 02:52:11 +00003499 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003500 */
3501 for (i = 0;i < cur->nodeNr;i++) {
3502 if ((cur->nodeTab[i] != NULL) &&
3503 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003504 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003505 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3506 return;
3507 }
3508
3509 /*
3510 * grow the nodeTab if needed
3511 */
3512 if (cur->nodeMax == 0) {
3513 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514 sizeof(xmlNodePtr));
3515 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003516 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003517 return;
3518 }
3519 memset(cur->nodeTab, 0 ,
3520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521 cur->nodeMax = XML_NODESET_DEFAULT;
3522 } else if (cur->nodeNr == cur->nodeMax) {
3523 xmlNodePtr *temp;
3524
3525 cur->nodeMax *= 2;
3526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527 sizeof(xmlNodePtr));
3528 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003529 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003530 return;
3531 }
3532 cur->nodeTab = temp;
3533 }
3534 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3535}
3536
3537/**
Owen Taylor3473f882001-02-23 17:55:21 +00003538 * xmlXPathNodeSetAdd:
3539 * @cur: the initial node set
3540 * @val: a new xmlNodePtr
3541 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003542 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003543 */
3544void
3545xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3546 int i;
3547
Daniel Veillarda82b1822004-11-08 16:24:57 +00003548 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003549
Daniel Veillardef0b4502003-03-24 13:57:34 +00003550#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003551 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003553#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003554
William M. Brack08171912003-12-29 02:52:11 +00003555 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003556 /*
William M. Brack08171912003-12-29 02:52:11 +00003557 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003558 */
3559 for (i = 0;i < cur->nodeNr;i++)
3560 if (cur->nodeTab[i] == val) return;
3561
3562 /*
3563 * grow the nodeTab if needed
3564 */
3565 if (cur->nodeMax == 0) {
3566 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567 sizeof(xmlNodePtr));
3568 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003569 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003570 return;
3571 }
3572 memset(cur->nodeTab, 0 ,
3573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574 cur->nodeMax = XML_NODESET_DEFAULT;
3575 } else if (cur->nodeNr == cur->nodeMax) {
3576 xmlNodePtr *temp;
3577
3578 cur->nodeMax *= 2;
3579 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580 sizeof(xmlNodePtr));
3581 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003582 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003583 return;
3584 }
3585 cur->nodeTab = temp;
3586 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003587 if (val->type == XML_NAMESPACE_DECL) {
3588 xmlNsPtr ns = (xmlNsPtr) val;
3589
3590 cur->nodeTab[cur->nodeNr++] =
3591 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3592 } else
3593 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003594}
3595
3596/**
3597 * xmlXPathNodeSetAddUnique:
3598 * @cur: the initial node set
3599 * @val: a new xmlNodePtr
3600 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003601 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003602 * when we are sure the node is not already in the set.
3603 */
3604void
3605xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003606 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003607
Daniel Veillardef0b4502003-03-24 13:57:34 +00003608#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003609 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003611#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003612
William M. Brack08171912003-12-29 02:52:11 +00003613 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003614 /*
3615 * grow the nodeTab if needed
3616 */
3617 if (cur->nodeMax == 0) {
3618 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619 sizeof(xmlNodePtr));
3620 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003621 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003622 return;
3623 }
3624 memset(cur->nodeTab, 0 ,
3625 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626 cur->nodeMax = XML_NODESET_DEFAULT;
3627 } else if (cur->nodeNr == cur->nodeMax) {
3628 xmlNodePtr *temp;
3629
3630 cur->nodeMax *= 2;
3631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632 sizeof(xmlNodePtr));
3633 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003634 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003635 return;
3636 }
3637 cur->nodeTab = temp;
3638 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003639 if (val->type == XML_NAMESPACE_DECL) {
3640 xmlNsPtr ns = (xmlNsPtr) val;
3641
3642 cur->nodeTab[cur->nodeNr++] =
3643 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3644 } else
3645 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003646}
3647
3648/**
3649 * xmlXPathNodeSetMerge:
3650 * @val1: the first NodeSet or NULL
3651 * @val2: the second NodeSet
3652 *
3653 * Merges two nodesets, all nodes from @val2 are added to @val1
3654 * if @val1 is NULL, a new set is created and copied from @val2
3655 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003656 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003657 */
3658xmlNodeSetPtr
3659xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003660 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003661 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003662
3663 if (val2 == NULL) return(val1);
3664 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003665 val1 = xmlXPathNodeSetCreate(NULL);
3666#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003667 /*
3668 * TODO: The optimization won't work in every case, since
3669 * those nasty namespace nodes need to be added with
3670 * xmlXPathNodeSetDupNs() to the set; thus a pure
3671 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003672 * If there was a flag on the nodesetval, indicating that
3673 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003674 */
3675 /*
3676 * Optimization: Create an equally sized node-set
3677 * and memcpy the content.
3678 */
3679 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3680 if (val1 == NULL)
3681 return(NULL);
3682 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003683 if (val2->nodeNr == 1)
3684 *(val1->nodeTab) = *(val2->nodeTab);
3685 else {
3686 memcpy(val1->nodeTab, val2->nodeTab,
3687 val2->nodeNr * sizeof(xmlNodePtr));
3688 }
3689 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003690 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003691 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003692#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003693 }
3694
William M. Brack08171912003-12-29 02:52:11 +00003695 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003696 initNr = val1->nodeNr;
3697
3698 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003699 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003700 /*
William M. Brack08171912003-12-29 02:52:11 +00003701 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003702 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003703 skip = 0;
3704 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003705 n1 = val1->nodeTab[j];
3706 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003707 skip = 1;
3708 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003709 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3710 (n2->type == XML_NAMESPACE_DECL)) {
3711 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3712 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3713 ((xmlNsPtr) n2)->prefix)))
3714 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003715 skip = 1;
3716 break;
3717 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003718 }
3719 }
3720 if (skip)
3721 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003722
3723 /*
3724 * grow the nodeTab if needed
3725 */
3726 if (val1->nodeMax == 0) {
3727 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3728 sizeof(xmlNodePtr));
3729 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003730 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003731 return(NULL);
3732 }
3733 memset(val1->nodeTab, 0 ,
3734 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3735 val1->nodeMax = XML_NODESET_DEFAULT;
3736 } else if (val1->nodeNr == val1->nodeMax) {
3737 xmlNodePtr *temp;
3738
3739 val1->nodeMax *= 2;
3740 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3741 sizeof(xmlNodePtr));
3742 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003743 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003744 return(NULL);
3745 }
3746 val1->nodeTab = temp;
3747 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003748 if (n2->type == XML_NAMESPACE_DECL) {
3749 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003750
3751 val1->nodeTab[val1->nodeNr++] =
3752 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3753 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003754 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003755 }
3756
3757 return(val1);
3758}
3759
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003760#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003761/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003762 * xmlXPathNodeSetMergeUnique:
3763 * @val1: the first NodeSet or NULL
3764 * @val2: the second NodeSet
3765 *
3766 * Merges two nodesets, all nodes from @val2 are added to @val1
3767 * if @val1 is NULL, a new set is created and copied from @val2
3768 *
3769 * Returns @val1 once extended or NULL in case of error.
3770 */
3771static xmlNodeSetPtr
3772xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003773 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003774
3775 if (val2 == NULL) return(val1);
3776 if (val1 == NULL) {
3777 val1 = xmlXPathNodeSetCreate(NULL);
3778 }
3779
William M. Brack08171912003-12-29 02:52:11 +00003780 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003781
3782 for (i = 0;i < val2->nodeNr;i++) {
3783 /*
3784 * grow the nodeTab if needed
3785 */
3786 if (val1->nodeMax == 0) {
3787 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3788 sizeof(xmlNodePtr));
3789 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003790 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003791 return(NULL);
3792 }
3793 memset(val1->nodeTab, 0 ,
3794 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3795 val1->nodeMax = XML_NODESET_DEFAULT;
3796 } else if (val1->nodeNr == val1->nodeMax) {
3797 xmlNodePtr *temp;
3798
3799 val1->nodeMax *= 2;
3800 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3801 sizeof(xmlNodePtr));
3802 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003803 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003804 return(NULL);
3805 }
3806 val1->nodeTab = temp;
3807 }
3808 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3809 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3810
3811 val1->nodeTab[val1->nodeNr++] =
3812 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3813 } else
3814 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3815 }
3816
3817 return(val1);
3818}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003819#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3820
3821/**
3822 * xmlXPathNodeSetMergeAndClear:
3823 * @set1: the first NodeSet or NULL
3824 * @set2: the second NodeSet
3825 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3826 *
3827 * Merges two nodesets, all nodes from @set2 are added to @set1
3828 * if @set1 is NULL, a new set is created and copied from @set2.
3829 * Checks for duplicate nodes. Clears set2.
3830 *
3831 * Returns @set1 once extended or NULL in case of error.
3832 */
3833static xmlNodeSetPtr
3834xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3835 int hasNullEntries)
3836{
3837 if ((set1 == NULL) && (hasNullEntries == 0)) {
3838 /*
3839 * Note that doing a memcpy of the list, namespace nodes are
3840 * just assigned to set1, since set2 is cleared anyway.
3841 */
3842 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3843 if (set1 == NULL)
3844 return(NULL);
3845 if (set2->nodeNr != 0) {
3846 memcpy(set1->nodeTab, set2->nodeTab,
3847 set2->nodeNr * sizeof(xmlNodePtr));
3848 set1->nodeNr = set2->nodeNr;
3849 }
3850 } else {
3851 int i, j, initNbSet1;
3852 xmlNodePtr n1, n2;
3853
3854 if (set1 == NULL)
3855 set1 = xmlXPathNodeSetCreate(NULL);
3856
3857 initNbSet1 = set1->nodeNr;
3858 for (i = 0;i < set2->nodeNr;i++) {
3859 n2 = set2->nodeTab[i];
3860 /*
3861 * Skip NULLed entries.
3862 */
3863 if (n2 == NULL)
3864 continue;
3865 /*
3866 * Skip duplicates.
3867 */
3868 for (j = 0; j < initNbSet1; j++) {
3869 n1 = set1->nodeTab[j];
3870 if (n1 == n2) {
3871 goto skip_node;
3872 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3873 (n2->type == XML_NAMESPACE_DECL))
3874 {
3875 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3876 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3877 ((xmlNsPtr) n2)->prefix)))
3878 {
3879 /*
3880 * Free the namespace node.
3881 */
3882 set2->nodeTab[i] = NULL;
3883 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3884 goto skip_node;
3885 }
3886 }
3887 }
3888 /*
3889 * grow the nodeTab if needed
3890 */
3891 if (set1->nodeMax == 0) {
3892 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3893 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3894 if (set1->nodeTab == NULL) {
3895 xmlXPathErrMemory(NULL, "merging nodeset\n");
3896 return(NULL);
3897 }
3898 memset(set1->nodeTab, 0,
3899 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3900 set1->nodeMax = XML_NODESET_DEFAULT;
3901 } else if (set1->nodeNr >= set1->nodeMax) {
3902 xmlNodePtr *temp;
3903
3904 set1->nodeMax *= 2;
3905 temp = (xmlNodePtr *) xmlRealloc(
3906 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3907 if (temp == NULL) {
3908 xmlXPathErrMemory(NULL, "merging nodeset\n");
3909 return(NULL);
3910 }
3911 set1->nodeTab = temp;
3912 }
3913 if (n2->type == XML_NAMESPACE_DECL) {
3914 xmlNsPtr ns = (xmlNsPtr) n2;
3915
3916 set1->nodeTab[set1->nodeNr++] =
3917 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3918 } else
3919 set1->nodeTab[set1->nodeNr++] = n2;
3920skip_node:
3921 {}
3922 }
3923 }
3924 set2->nodeNr = 0;
3925 return(set1);
3926}
3927
3928/**
3929 * xmlXPathNodeSetMergeAndClearNoDupls:
3930 * @set1: the first NodeSet or NULL
3931 * @set2: the second NodeSet
3932 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3933 *
3934 * Merges two nodesets, all nodes from @set2 are added to @set1
3935 * if @set1 is NULL, a new set is created and copied from @set2.
3936 * Doesn't chack for duplicate nodes. Clears set2.
3937 *
3938 * Returns @set1 once extended or NULL in case of error.
3939 */
3940static xmlNodeSetPtr
3941xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3942 int hasNullEntries)
3943{
3944 if (set2 == NULL)
3945 return(set1);
3946 if ((set1 == NULL) && (hasNullEntries == 0)) {
3947 /*
3948 * Note that doing a memcpy of the list, namespace nodes are
3949 * just assigned to set1, since set2 is cleared anyway.
3950 */
3951 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3952 if (set1 == NULL)
3953 return(NULL);
3954 if (set2->nodeNr != 0) {
3955 memcpy(set1->nodeTab, set2->nodeTab,
3956 set2->nodeNr * sizeof(xmlNodePtr));
3957 set1->nodeNr = set2->nodeNr;
3958 }
3959 } else {
3960 int i;
3961 xmlNodePtr n2;
3962
3963 if (set1 == NULL)
3964 set1 = xmlXPathNodeSetCreate(NULL);
3965
3966 for (i = 0;i < set2->nodeNr;i++) {
3967 n2 = set2->nodeTab[i];
3968 /*
3969 * Skip NULLed entries.
3970 */
3971 if (n2 == NULL)
3972 continue;
3973 if (set1->nodeMax == 0) {
3974 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3975 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3976 if (set1->nodeTab == NULL) {
3977 xmlXPathErrMemory(NULL, "merging nodeset\n");
3978 return(NULL);
3979 }
3980 memset(set1->nodeTab, 0,
3981 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3982 set1->nodeMax = XML_NODESET_DEFAULT;
3983 } else if (set1->nodeNr >= set1->nodeMax) {
3984 xmlNodePtr *temp;
3985
3986 set1->nodeMax *= 2;
3987 temp = (xmlNodePtr *) xmlRealloc(
3988 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3989 if (temp == NULL) {
3990 xmlXPathErrMemory(NULL, "merging nodeset\n");
3991 return(NULL);
3992 }
3993 set1->nodeTab = temp;
3994 }
3995 set1->nodeTab[set1->nodeNr++] = n2;
3996 }
3997 }
3998 set2->nodeNr = 0;
3999 return(set1);
4000}
Daniel Veillard75be0132002-03-13 10:03:35 +00004001
4002/**
Owen Taylor3473f882001-02-23 17:55:21 +00004003 * xmlXPathNodeSetDel:
4004 * @cur: the initial node set
4005 * @val: an xmlNodePtr
4006 *
4007 * Removes an xmlNodePtr from an existing NodeSet
4008 */
4009void
4010xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4011 int i;
4012
4013 if (cur == NULL) return;
4014 if (val == NULL) return;
4015
4016 /*
William M. Brack08171912003-12-29 02:52:11 +00004017 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004018 */
4019 for (i = 0;i < cur->nodeNr;i++)
4020 if (cur->nodeTab[i] == val) break;
4021
William M. Brack08171912003-12-29 02:52:11 +00004022 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004023#ifdef DEBUG
4024 xmlGenericError(xmlGenericErrorContext,
4025 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4026 val->name);
4027#endif
4028 return;
4029 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004030 if ((cur->nodeTab[i] != NULL) &&
4031 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4032 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004033 cur->nodeNr--;
4034 for (;i < cur->nodeNr;i++)
4035 cur->nodeTab[i] = cur->nodeTab[i + 1];
4036 cur->nodeTab[cur->nodeNr] = NULL;
4037}
4038
4039/**
4040 * xmlXPathNodeSetRemove:
4041 * @cur: the initial node set
4042 * @val: the index to remove
4043 *
4044 * Removes an entry from an existing NodeSet list.
4045 */
4046void
4047xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4048 if (cur == NULL) return;
4049 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004050 if ((cur->nodeTab[val] != NULL) &&
4051 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4052 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004053 cur->nodeNr--;
4054 for (;val < cur->nodeNr;val++)
4055 cur->nodeTab[val] = cur->nodeTab[val + 1];
4056 cur->nodeTab[cur->nodeNr] = NULL;
4057}
4058
4059/**
4060 * xmlXPathFreeNodeSet:
4061 * @obj: the xmlNodeSetPtr to free
4062 *
4063 * Free the NodeSet compound (not the actual nodes !).
4064 */
4065void
4066xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4067 if (obj == NULL) return;
4068 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004069 int i;
4070
William M. Brack08171912003-12-29 02:52:11 +00004071 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004072 for (i = 0;i < obj->nodeNr;i++)
4073 if ((obj->nodeTab[i] != NULL) &&
4074 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4075 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 xmlFree(obj->nodeTab);
4077 }
Owen Taylor3473f882001-02-23 17:55:21 +00004078 xmlFree(obj);
4079}
4080
4081/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004082 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004083 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004084 *
4085 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4086 * are feed), but does *not* free the list itself. Sets the length of the
4087 * list to 0.
4088 */
4089static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004090xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4091{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004092 if ((set == NULL) || (set->nodeNr <= 0))
4093 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004094 else if (hasNsNodes) {
4095 int i;
4096 xmlNodePtr node;
4097
4098 for (i = 0; i < set->nodeNr; i++) {
4099 node = set->nodeTab[i];
4100 if ((node != NULL) &&
4101 (node->type == XML_NAMESPACE_DECL))
4102 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4103 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004104 }
4105 set->nodeNr = 0;
4106}
4107
4108/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004109 * xmlXPathNodeSetClearFromPos:
4110 * @set: the node set to be cleared
4111 * @pos: the start position to clear from
4112 *
4113 * Clears the list from temporary XPath objects (e.g. namespace nodes
4114 * are feed) starting with the entry at @pos, but does *not* free the list
4115 * itself. Sets the length of the list to @pos.
4116 */
4117static void
4118xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4119{
4120 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4121 return;
4122 else if ((hasNsNodes)) {
4123 int i;
4124 xmlNodePtr node;
4125
4126 for (i = pos; i < set->nodeNr; i++) {
4127 node = set->nodeTab[i];
4128 if ((node != NULL) &&
4129 (node->type == XML_NAMESPACE_DECL))
4130 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4131 }
4132 }
4133 set->nodeNr = pos;
4134}
4135
4136/**
Owen Taylor3473f882001-02-23 17:55:21 +00004137 * xmlXPathFreeValueTree:
4138 * @obj: the xmlNodeSetPtr to free
4139 *
4140 * Free the NodeSet compound and the actual tree, this is different
4141 * from xmlXPathFreeNodeSet()
4142 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004143static void
Owen Taylor3473f882001-02-23 17:55:21 +00004144xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4145 int i;
4146
4147 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004148
4149 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004150 for (i = 0;i < obj->nodeNr;i++) {
4151 if (obj->nodeTab[i] != NULL) {
4152 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4153 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4154 } else {
4155 xmlFreeNodeList(obj->nodeTab[i]);
4156 }
4157 }
4158 }
Owen Taylor3473f882001-02-23 17:55:21 +00004159 xmlFree(obj->nodeTab);
4160 }
Owen Taylor3473f882001-02-23 17:55:21 +00004161 xmlFree(obj);
4162}
4163
4164#if defined(DEBUG) || defined(DEBUG_STEP)
4165/**
4166 * xmlGenericErrorContextNodeSet:
4167 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004168 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004169 *
4170 * Quick display of a NodeSet
4171 */
4172void
4173xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4174 int i;
4175
4176 if (output == NULL) output = xmlGenericErrorContext;
4177 if (obj == NULL) {
4178 fprintf(output, "NodeSet == NULL !\n");
4179 return;
4180 }
4181 if (obj->nodeNr == 0) {
4182 fprintf(output, "NodeSet is empty\n");
4183 return;
4184 }
4185 if (obj->nodeTab == NULL) {
4186 fprintf(output, " nodeTab == NULL !\n");
4187 return;
4188 }
4189 for (i = 0; i < obj->nodeNr; i++) {
4190 if (obj->nodeTab[i] == NULL) {
4191 fprintf(output, " NULL !\n");
4192 return;
4193 }
4194 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4195 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4196 fprintf(output, " /");
4197 else if (obj->nodeTab[i]->name == NULL)
4198 fprintf(output, " noname!");
4199 else fprintf(output, " %s", obj->nodeTab[i]->name);
4200 }
4201 fprintf(output, "\n");
4202}
4203#endif
4204
4205/**
4206 * xmlXPathNewNodeSet:
4207 * @val: the NodePtr value
4208 *
4209 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4210 * it with the single Node @val
4211 *
4212 * Returns the newly created object.
4213 */
4214xmlXPathObjectPtr
4215xmlXPathNewNodeSet(xmlNodePtr val) {
4216 xmlXPathObjectPtr ret;
4217
4218 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4219 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004220 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004221 return(NULL);
4222 }
4223 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4224 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004225 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004226 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004227 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004228#ifdef XP_DEBUG_OBJ_USAGE
4229 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4230#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004231 return(ret);
4232}
4233
4234/**
4235 * xmlXPathNewValueTree:
4236 * @val: the NodePtr value
4237 *
4238 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4239 * it with the tree root @val
4240 *
4241 * Returns the newly created object.
4242 */
4243xmlXPathObjectPtr
4244xmlXPathNewValueTree(xmlNodePtr val) {
4245 xmlXPathObjectPtr ret;
4246
4247 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4248 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004249 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004250 return(NULL);
4251 }
4252 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4253 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004254 ret->boolval = 1;
4255 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004256 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004257#ifdef XP_DEBUG_OBJ_USAGE
4258 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4259#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004260 return(ret);
4261}
4262
4263/**
4264 * xmlXPathNewNodeSetList:
4265 * @val: an existing NodeSet
4266 *
4267 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4268 * it with the Nodeset @val
4269 *
4270 * Returns the newly created object.
4271 */
4272xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004273xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4274{
Owen Taylor3473f882001-02-23 17:55:21 +00004275 xmlXPathObjectPtr ret;
4276 int i;
4277
4278 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004279 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004280 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004281 ret = xmlXPathNewNodeSet(NULL);
4282 else {
4283 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4284 for (i = 1; i < val->nodeNr; ++i)
4285 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4286 }
Owen Taylor3473f882001-02-23 17:55:21 +00004287
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004288 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004289}
4290
4291/**
4292 * xmlXPathWrapNodeSet:
4293 * @val: the NodePtr value
4294 *
4295 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4296 *
4297 * Returns the newly created object.
4298 */
4299xmlXPathObjectPtr
4300xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4301 xmlXPathObjectPtr ret;
4302
4303 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004305 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004306 return(NULL);
4307 }
4308 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309 ret->type = XPATH_NODESET;
4310 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004311#ifdef XP_DEBUG_OBJ_USAGE
4312 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4313#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004314 return(ret);
4315}
4316
4317/**
4318 * xmlXPathFreeNodeSetList:
4319 * @obj: an existing NodeSetList object
4320 *
4321 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4322 * the list contrary to xmlXPathFreeObject().
4323 */
4324void
4325xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4326 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004327#ifdef XP_DEBUG_OBJ_USAGE
4328 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4329#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004330 xmlFree(obj);
4331}
4332
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004333/**
4334 * xmlXPathDifference:
4335 * @nodes1: a node-set
4336 * @nodes2: a node-set
4337 *
4338 * Implements the EXSLT - Sets difference() function:
4339 * node-set set:difference (node-set, node-set)
4340 *
4341 * Returns the difference between the two node sets, or nodes1 if
4342 * nodes2 is empty
4343 */
4344xmlNodeSetPtr
4345xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4346 xmlNodeSetPtr ret;
4347 int i, l1;
4348 xmlNodePtr cur;
4349
4350 if (xmlXPathNodeSetIsEmpty(nodes2))
4351 return(nodes1);
4352
4353 ret = xmlXPathNodeSetCreate(NULL);
4354 if (xmlXPathNodeSetIsEmpty(nodes1))
4355 return(ret);
4356
4357 l1 = xmlXPathNodeSetGetLength(nodes1);
4358
4359 for (i = 0; i < l1; i++) {
4360 cur = xmlXPathNodeSetItem(nodes1, i);
4361 if (!xmlXPathNodeSetContains(nodes2, cur))
4362 xmlXPathNodeSetAddUnique(ret, cur);
4363 }
4364 return(ret);
4365}
4366
4367/**
4368 * xmlXPathIntersection:
4369 * @nodes1: a node-set
4370 * @nodes2: a node-set
4371 *
4372 * Implements the EXSLT - Sets intersection() function:
4373 * node-set set:intersection (node-set, node-set)
4374 *
4375 * Returns a node set comprising the nodes that are within both the
4376 * node sets passed as arguments
4377 */
4378xmlNodeSetPtr
4379xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4380 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4381 int i, l1;
4382 xmlNodePtr cur;
4383
4384 if (xmlXPathNodeSetIsEmpty(nodes1))
4385 return(ret);
4386 if (xmlXPathNodeSetIsEmpty(nodes2))
4387 return(ret);
4388
4389 l1 = xmlXPathNodeSetGetLength(nodes1);
4390
4391 for (i = 0; i < l1; i++) {
4392 cur = xmlXPathNodeSetItem(nodes1, i);
4393 if (xmlXPathNodeSetContains(nodes2, cur))
4394 xmlXPathNodeSetAddUnique(ret, cur);
4395 }
4396 return(ret);
4397}
4398
4399/**
4400 * xmlXPathDistinctSorted:
4401 * @nodes: a node-set, sorted by document order
4402 *
4403 * Implements the EXSLT - Sets distinct() function:
4404 * node-set set:distinct (node-set)
4405 *
4406 * Returns a subset of the nodes contained in @nodes, or @nodes if
4407 * it is empty
4408 */
4409xmlNodeSetPtr
4410xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4411 xmlNodeSetPtr ret;
4412 xmlHashTablePtr hash;
4413 int i, l;
4414 xmlChar * strval;
4415 xmlNodePtr cur;
4416
4417 if (xmlXPathNodeSetIsEmpty(nodes))
4418 return(nodes);
4419
4420 ret = xmlXPathNodeSetCreate(NULL);
4421 l = xmlXPathNodeSetGetLength(nodes);
4422 hash = xmlHashCreate (l);
4423 for (i = 0; i < l; i++) {
4424 cur = xmlXPathNodeSetItem(nodes, i);
4425 strval = xmlXPathCastNodeToString(cur);
4426 if (xmlHashLookup(hash, strval) == NULL) {
4427 xmlHashAddEntry(hash, strval, strval);
4428 xmlXPathNodeSetAddUnique(ret, cur);
4429 } else {
4430 xmlFree(strval);
4431 }
4432 }
4433 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4434 return(ret);
4435}
4436
4437/**
4438 * xmlXPathDistinct:
4439 * @nodes: a node-set
4440 *
4441 * Implements the EXSLT - Sets distinct() function:
4442 * node-set set:distinct (node-set)
4443 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4444 * is called with the sorted node-set
4445 *
4446 * Returns a subset of the nodes contained in @nodes, or @nodes if
4447 * it is empty
4448 */
4449xmlNodeSetPtr
4450xmlXPathDistinct (xmlNodeSetPtr nodes) {
4451 if (xmlXPathNodeSetIsEmpty(nodes))
4452 return(nodes);
4453
4454 xmlXPathNodeSetSort(nodes);
4455 return(xmlXPathDistinctSorted(nodes));
4456}
4457
4458/**
4459 * xmlXPathHasSameNodes:
4460 * @nodes1: a node-set
4461 * @nodes2: a node-set
4462 *
4463 * Implements the EXSLT - Sets has-same-nodes function:
4464 * boolean set:has-same-node(node-set, node-set)
4465 *
4466 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4467 * otherwise
4468 */
4469int
4470xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4471 int i, l;
4472 xmlNodePtr cur;
4473
4474 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4475 xmlXPathNodeSetIsEmpty(nodes2))
4476 return(0);
4477
4478 l = xmlXPathNodeSetGetLength(nodes1);
4479 for (i = 0; i < l; i++) {
4480 cur = xmlXPathNodeSetItem(nodes1, i);
4481 if (xmlXPathNodeSetContains(nodes2, cur))
4482 return(1);
4483 }
4484 return(0);
4485}
4486
4487/**
4488 * xmlXPathNodeLeadingSorted:
4489 * @nodes: a node-set, sorted by document order
4490 * @node: a node
4491 *
4492 * Implements the EXSLT - Sets leading() function:
4493 * node-set set:leading (node-set, node-set)
4494 *
4495 * Returns the nodes in @nodes that precede @node in document order,
4496 * @nodes if @node is NULL or an empty node-set if @nodes
4497 * doesn't contain @node
4498 */
4499xmlNodeSetPtr
4500xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4501 int i, l;
4502 xmlNodePtr cur;
4503 xmlNodeSetPtr ret;
4504
4505 if (node == NULL)
4506 return(nodes);
4507
4508 ret = xmlXPathNodeSetCreate(NULL);
4509 if (xmlXPathNodeSetIsEmpty(nodes) ||
4510 (!xmlXPathNodeSetContains(nodes, node)))
4511 return(ret);
4512
4513 l = xmlXPathNodeSetGetLength(nodes);
4514 for (i = 0; i < l; i++) {
4515 cur = xmlXPathNodeSetItem(nodes, i);
4516 if (cur == node)
4517 break;
4518 xmlXPathNodeSetAddUnique(ret, cur);
4519 }
4520 return(ret);
4521}
4522
4523/**
4524 * xmlXPathNodeLeading:
4525 * @nodes: a node-set
4526 * @node: a node
4527 *
4528 * Implements the EXSLT - Sets leading() function:
4529 * node-set set:leading (node-set, node-set)
4530 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4531 * is called.
4532 *
4533 * Returns the nodes in @nodes that precede @node in document order,
4534 * @nodes if @node is NULL or an empty node-set if @nodes
4535 * doesn't contain @node
4536 */
4537xmlNodeSetPtr
4538xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4539 xmlXPathNodeSetSort(nodes);
4540 return(xmlXPathNodeLeadingSorted(nodes, node));
4541}
4542
4543/**
4544 * xmlXPathLeadingSorted:
4545 * @nodes1: a node-set, sorted by document order
4546 * @nodes2: a node-set, sorted by document order
4547 *
4548 * Implements the EXSLT - Sets leading() function:
4549 * node-set set:leading (node-set, node-set)
4550 *
4551 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4552 * in document order, @nodes1 if @nodes2 is NULL or empty or
4553 * an empty node-set if @nodes1 doesn't contain @nodes2
4554 */
4555xmlNodeSetPtr
4556xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4557 if (xmlXPathNodeSetIsEmpty(nodes2))
4558 return(nodes1);
4559 return(xmlXPathNodeLeadingSorted(nodes1,
4560 xmlXPathNodeSetItem(nodes2, 1)));
4561}
4562
4563/**
4564 * xmlXPathLeading:
4565 * @nodes1: a node-set
4566 * @nodes2: a node-set
4567 *
4568 * Implements the EXSLT - Sets leading() function:
4569 * node-set set:leading (node-set, node-set)
4570 * @nodes1 and @nodes2 are sorted by document order, then
4571 * #exslSetsLeadingSorted is called.
4572 *
4573 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4574 * in document order, @nodes1 if @nodes2 is NULL or empty or
4575 * an empty node-set if @nodes1 doesn't contain @nodes2
4576 */
4577xmlNodeSetPtr
4578xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4579 if (xmlXPathNodeSetIsEmpty(nodes2))
4580 return(nodes1);
4581 if (xmlXPathNodeSetIsEmpty(nodes1))
4582 return(xmlXPathNodeSetCreate(NULL));
4583 xmlXPathNodeSetSort(nodes1);
4584 xmlXPathNodeSetSort(nodes2);
4585 return(xmlXPathNodeLeadingSorted(nodes1,
4586 xmlXPathNodeSetItem(nodes2, 1)));
4587}
4588
4589/**
4590 * xmlXPathNodeTrailingSorted:
4591 * @nodes: a node-set, sorted by document order
4592 * @node: a node
4593 *
4594 * Implements the EXSLT - Sets trailing() function:
4595 * node-set set:trailing (node-set, node-set)
4596 *
4597 * Returns the nodes in @nodes that follow @node in document order,
4598 * @nodes if @node is NULL or an empty node-set if @nodes
4599 * doesn't contain @node
4600 */
4601xmlNodeSetPtr
4602xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4603 int i, l;
4604 xmlNodePtr cur;
4605 xmlNodeSetPtr ret;
4606
4607 if (node == NULL)
4608 return(nodes);
4609
4610 ret = xmlXPathNodeSetCreate(NULL);
4611 if (xmlXPathNodeSetIsEmpty(nodes) ||
4612 (!xmlXPathNodeSetContains(nodes, node)))
4613 return(ret);
4614
4615 l = xmlXPathNodeSetGetLength(nodes);
William M. Brack97ac8192007-06-06 17:19:24 +00004616 for (i = l - 1; i >= 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004617 cur = xmlXPathNodeSetItem(nodes, i);
4618 if (cur == node)
4619 break;
4620 xmlXPathNodeSetAddUnique(ret, cur);
4621 }
William M. Brack97ac8192007-06-06 17:19:24 +00004622 xmlXPathNodeSetSort(ret); /* bug 413451 */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004623 return(ret);
4624}
4625
4626/**
4627 * xmlXPathNodeTrailing:
4628 * @nodes: a node-set
4629 * @node: a node
4630 *
4631 * Implements the EXSLT - Sets trailing() function:
4632 * node-set set:trailing (node-set, node-set)
4633 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4634 * is called.
4635 *
4636 * Returns the nodes in @nodes that follow @node in document order,
4637 * @nodes if @node is NULL or an empty node-set if @nodes
4638 * doesn't contain @node
4639 */
4640xmlNodeSetPtr
4641xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4642 xmlXPathNodeSetSort(nodes);
4643 return(xmlXPathNodeTrailingSorted(nodes, node));
4644}
4645
4646/**
4647 * xmlXPathTrailingSorted:
4648 * @nodes1: a node-set, sorted by document order
4649 * @nodes2: a node-set, sorted by document order
4650 *
4651 * Implements the EXSLT - Sets trailing() function:
4652 * node-set set:trailing (node-set, node-set)
4653 *
4654 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4655 * in document order, @nodes1 if @nodes2 is NULL or empty or
4656 * an empty node-set if @nodes1 doesn't contain @nodes2
4657 */
4658xmlNodeSetPtr
4659xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4660 if (xmlXPathNodeSetIsEmpty(nodes2))
4661 return(nodes1);
4662 return(xmlXPathNodeTrailingSorted(nodes1,
4663 xmlXPathNodeSetItem(nodes2, 0)));
4664}
4665
4666/**
4667 * xmlXPathTrailing:
4668 * @nodes1: a node-set
4669 * @nodes2: a node-set
4670 *
4671 * Implements the EXSLT - Sets trailing() function:
4672 * node-set set:trailing (node-set, node-set)
4673 * @nodes1 and @nodes2 are sorted by document order, then
4674 * #xmlXPathTrailingSorted is called.
4675 *
4676 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4677 * in document order, @nodes1 if @nodes2 is NULL or empty or
4678 * an empty node-set if @nodes1 doesn't contain @nodes2
4679 */
4680xmlNodeSetPtr
4681xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4682 if (xmlXPathNodeSetIsEmpty(nodes2))
4683 return(nodes1);
4684 if (xmlXPathNodeSetIsEmpty(nodes1))
4685 return(xmlXPathNodeSetCreate(NULL));
4686 xmlXPathNodeSetSort(nodes1);
4687 xmlXPathNodeSetSort(nodes2);
4688 return(xmlXPathNodeTrailingSorted(nodes1,
4689 xmlXPathNodeSetItem(nodes2, 0)));
4690}
4691
Owen Taylor3473f882001-02-23 17:55:21 +00004692/************************************************************************
4693 * *
4694 * Routines to handle extra functions *
4695 * *
4696 ************************************************************************/
4697
4698/**
4699 * xmlXPathRegisterFunc:
4700 * @ctxt: the XPath context
4701 * @name: the function name
4702 * @f: the function implementation or NULL
4703 *
4704 * Register a new function. If @f is NULL it unregisters the function
4705 *
4706 * Returns 0 in case of success, -1 in case of error
4707 */
4708int
4709xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4710 xmlXPathFunction f) {
4711 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4712}
4713
4714/**
4715 * xmlXPathRegisterFuncNS:
4716 * @ctxt: the XPath context
4717 * @name: the function name
4718 * @ns_uri: the function namespace URI
4719 * @f: the function implementation or NULL
4720 *
4721 * Register a new function. If @f is NULL it unregisters the function
4722 *
4723 * Returns 0 in case of success, -1 in case of error
4724 */
4725int
4726xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4727 const xmlChar *ns_uri, xmlXPathFunction f) {
4728 if (ctxt == NULL)
4729 return(-1);
4730 if (name == NULL)
4731 return(-1);
4732
4733 if (ctxt->funcHash == NULL)
4734 ctxt->funcHash = xmlHashCreate(0);
4735 if (ctxt->funcHash == NULL)
4736 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004737 if (f == NULL)
4738 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004739 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004740}
4741
4742/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004743 * xmlXPathRegisterFuncLookup:
4744 * @ctxt: the XPath context
4745 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004746 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004747 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004748 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004749 */
4750void
4751xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4752 xmlXPathFuncLookupFunc f,
4753 void *funcCtxt) {
4754 if (ctxt == NULL)
4755 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004756 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004757 ctxt->funcLookupData = funcCtxt;
4758}
4759
4760/**
Owen Taylor3473f882001-02-23 17:55:21 +00004761 * xmlXPathFunctionLookup:
4762 * @ctxt: the XPath context
4763 * @name: the function name
4764 *
4765 * Search in the Function array of the context for the given
4766 * function.
4767 *
4768 * Returns the xmlXPathFunction or NULL if not found
4769 */
4770xmlXPathFunction
4771xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004772 if (ctxt == NULL)
4773 return (NULL);
4774
4775 if (ctxt->funcLookupFunc != NULL) {
4776 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004777 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004778
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004779 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004780 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004781 if (ret != NULL)
4782 return(ret);
4783 }
Owen Taylor3473f882001-02-23 17:55:21 +00004784 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4785}
4786
4787/**
4788 * xmlXPathFunctionLookupNS:
4789 * @ctxt: the XPath context
4790 * @name: the function name
4791 * @ns_uri: the function namespace URI
4792 *
4793 * Search in the Function array of the context for the given
4794 * function.
4795 *
4796 * Returns the xmlXPathFunction or NULL if not found
4797 */
4798xmlXPathFunction
4799xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4800 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004801 xmlXPathFunction ret;
4802
Owen Taylor3473f882001-02-23 17:55:21 +00004803 if (ctxt == NULL)
4804 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004805 if (name == NULL)
4806 return(NULL);
4807
Thomas Broyerba4ad322001-07-26 16:55:21 +00004808 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004809 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004810
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004811 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004812 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004813 if (ret != NULL)
4814 return(ret);
4815 }
4816
4817 if (ctxt->funcHash == NULL)
4818 return(NULL);
4819
William M. Brackad0e67c2004-12-01 14:35:10 +00004820 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4821 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004822}
4823
4824/**
4825 * xmlXPathRegisteredFuncsCleanup:
4826 * @ctxt: the XPath context
4827 *
4828 * Cleanup the XPath context data associated to registered functions
4829 */
4830void
4831xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4832 if (ctxt == NULL)
4833 return;
4834
4835 xmlHashFree(ctxt->funcHash, NULL);
4836 ctxt->funcHash = NULL;
4837}
4838
4839/************************************************************************
4840 * *
William M. Brack08171912003-12-29 02:52:11 +00004841 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004842 * *
4843 ************************************************************************/
4844
4845/**
4846 * xmlXPathRegisterVariable:
4847 * @ctxt: the XPath context
4848 * @name: the variable name
4849 * @value: the variable value or NULL
4850 *
4851 * Register a new variable value. If @value is NULL it unregisters
4852 * the variable
4853 *
4854 * Returns 0 in case of success, -1 in case of error
4855 */
4856int
4857xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4858 xmlXPathObjectPtr value) {
4859 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4860}
4861
4862/**
4863 * xmlXPathRegisterVariableNS:
4864 * @ctxt: the XPath context
4865 * @name: the variable name
4866 * @ns_uri: the variable namespace URI
4867 * @value: the variable value or NULL
4868 *
4869 * Register a new variable value. If @value is NULL it unregisters
4870 * the variable
4871 *
4872 * Returns 0 in case of success, -1 in case of error
4873 */
4874int
4875xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4876 const xmlChar *ns_uri,
4877 xmlXPathObjectPtr value) {
4878 if (ctxt == NULL)
4879 return(-1);
4880 if (name == NULL)
4881 return(-1);
4882
4883 if (ctxt->varHash == NULL)
4884 ctxt->varHash = xmlHashCreate(0);
4885 if (ctxt->varHash == NULL)
4886 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004887 if (value == NULL)
4888 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4889 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004890 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4891 (void *) value,
4892 (xmlHashDeallocator)xmlXPathFreeObject));
4893}
4894
4895/**
4896 * xmlXPathRegisterVariableLookup:
4897 * @ctxt: the XPath context
4898 * @f: the lookup function
4899 * @data: the lookup data
4900 *
4901 * register an external mechanism to do variable lookup
4902 */
4903void
4904xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4905 xmlXPathVariableLookupFunc f, void *data) {
4906 if (ctxt == NULL)
4907 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004908 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004909 ctxt->varLookupData = data;
4910}
4911
4912/**
4913 * xmlXPathVariableLookup:
4914 * @ctxt: the XPath context
4915 * @name: the variable name
4916 *
4917 * Search in the Variable array of the context for the given
4918 * variable value.
4919 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004920 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004921 */
4922xmlXPathObjectPtr
4923xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4924 if (ctxt == NULL)
4925 return(NULL);
4926
4927 if (ctxt->varLookupFunc != NULL) {
4928 xmlXPathObjectPtr ret;
4929
4930 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4931 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004932 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004933 }
4934 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4935}
4936
4937/**
4938 * xmlXPathVariableLookupNS:
4939 * @ctxt: the XPath context
4940 * @name: the variable name
4941 * @ns_uri: the variable namespace URI
4942 *
4943 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004944 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004945 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004946 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004947 */
4948xmlXPathObjectPtr
4949xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4950 const xmlChar *ns_uri) {
4951 if (ctxt == NULL)
4952 return(NULL);
4953
4954 if (ctxt->varLookupFunc != NULL) {
4955 xmlXPathObjectPtr ret;
4956
4957 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4958 (ctxt->varLookupData, name, ns_uri);
4959 if (ret != NULL) return(ret);
4960 }
4961
4962 if (ctxt->varHash == NULL)
4963 return(NULL);
4964 if (name == NULL)
4965 return(NULL);
4966
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004967 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004968 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004969}
4970
4971/**
4972 * xmlXPathRegisteredVariablesCleanup:
4973 * @ctxt: the XPath context
4974 *
4975 * Cleanup the XPath context data associated to registered variables
4976 */
4977void
4978xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4979 if (ctxt == NULL)
4980 return;
4981
Daniel Veillard76d66f42001-05-16 21:05:17 +00004982 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004983 ctxt->varHash = NULL;
4984}
4985
4986/**
4987 * xmlXPathRegisterNs:
4988 * @ctxt: the XPath context
4989 * @prefix: the namespace prefix
4990 * @ns_uri: the namespace name
4991 *
4992 * Register a new namespace. If @ns_uri is NULL it unregisters
4993 * the namespace
4994 *
4995 * Returns 0 in case of success, -1 in case of error
4996 */
4997int
4998xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4999 const xmlChar *ns_uri) {
5000 if (ctxt == NULL)
5001 return(-1);
5002 if (prefix == NULL)
5003 return(-1);
5004
5005 if (ctxt->nsHash == NULL)
5006 ctxt->nsHash = xmlHashCreate(10);
5007 if (ctxt->nsHash == NULL)
5008 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005009 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005010 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005011 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005012 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005013 (xmlHashDeallocator)xmlFree));
5014}
5015
5016/**
5017 * xmlXPathNsLookup:
5018 * @ctxt: the XPath context
5019 * @prefix: the namespace prefix value
5020 *
5021 * Search in the namespace declaration array of the context for the given
5022 * namespace name associated to the given prefix
5023 *
5024 * Returns the value or NULL if not found
5025 */
5026const xmlChar *
5027xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5028 if (ctxt == NULL)
5029 return(NULL);
5030 if (prefix == NULL)
5031 return(NULL);
5032
5033#ifdef XML_XML_NAMESPACE
5034 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5035 return(XML_XML_NAMESPACE);
5036#endif
5037
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005038 if (ctxt->namespaces != NULL) {
5039 int i;
5040
5041 for (i = 0;i < ctxt->nsNr;i++) {
5042 if ((ctxt->namespaces[i] != NULL) &&
5043 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5044 return(ctxt->namespaces[i]->href);
5045 }
5046 }
Owen Taylor3473f882001-02-23 17:55:21 +00005047
5048 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5049}
5050
5051/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005052 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005053 * @ctxt: the XPath context
5054 *
5055 * Cleanup the XPath context data associated to registered variables
5056 */
5057void
5058xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5059 if (ctxt == NULL)
5060 return;
5061
Daniel Veillard42766c02002-08-22 20:52:17 +00005062 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005063 ctxt->nsHash = NULL;
5064}
5065
5066/************************************************************************
5067 * *
5068 * Routines to handle Values *
5069 * *
5070 ************************************************************************/
5071
William M. Brack08171912003-12-29 02:52:11 +00005072/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005073
5074/**
5075 * xmlXPathNewFloat:
5076 * @val: the double value
5077 *
5078 * Create a new xmlXPathObjectPtr of type double and of value @val
5079 *
5080 * Returns the newly created object.
5081 */
5082xmlXPathObjectPtr
5083xmlXPathNewFloat(double val) {
5084 xmlXPathObjectPtr ret;
5085
5086 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5087 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005088 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005089 return(NULL);
5090 }
5091 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5092 ret->type = XPATH_NUMBER;
5093 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005094#ifdef XP_DEBUG_OBJ_USAGE
5095 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5096#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005097 return(ret);
5098}
5099
5100/**
5101 * xmlXPathNewBoolean:
5102 * @val: the boolean value
5103 *
5104 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5105 *
5106 * Returns the newly created object.
5107 */
5108xmlXPathObjectPtr
5109xmlXPathNewBoolean(int val) {
5110 xmlXPathObjectPtr ret;
5111
5112 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5113 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005114 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005115 return(NULL);
5116 }
5117 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5118 ret->type = XPATH_BOOLEAN;
5119 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005120#ifdef XP_DEBUG_OBJ_USAGE
5121 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5122#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005123 return(ret);
5124}
5125
5126/**
5127 * xmlXPathNewString:
5128 * @val: the xmlChar * value
5129 *
5130 * Create a new xmlXPathObjectPtr of type string and of value @val
5131 *
5132 * Returns the newly created object.
5133 */
5134xmlXPathObjectPtr
5135xmlXPathNewString(const xmlChar *val) {
5136 xmlXPathObjectPtr ret;
5137
5138 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5139 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005140 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005141 return(NULL);
5142 }
5143 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5144 ret->type = XPATH_STRING;
5145 if (val != NULL)
5146 ret->stringval = xmlStrdup(val);
5147 else
5148 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005149#ifdef XP_DEBUG_OBJ_USAGE
5150 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5151#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005152 return(ret);
5153}
5154
5155/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005156 * xmlXPathWrapString:
5157 * @val: the xmlChar * value
5158 *
5159 * Wraps the @val string into an XPath object.
5160 *
5161 * Returns the newly created object.
5162 */
5163xmlXPathObjectPtr
5164xmlXPathWrapString (xmlChar *val) {
5165 xmlXPathObjectPtr ret;
5166
5167 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5168 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005169 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005170 return(NULL);
5171 }
5172 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5173 ret->type = XPATH_STRING;
5174 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005175#ifdef XP_DEBUG_OBJ_USAGE
5176 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5177#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005178 return(ret);
5179}
5180
5181/**
Owen Taylor3473f882001-02-23 17:55:21 +00005182 * xmlXPathNewCString:
5183 * @val: the char * value
5184 *
5185 * Create a new xmlXPathObjectPtr of type string and of value @val
5186 *
5187 * Returns the newly created object.
5188 */
5189xmlXPathObjectPtr
5190xmlXPathNewCString(const char *val) {
5191 xmlXPathObjectPtr ret;
5192
5193 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5194 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005195 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005196 return(NULL);
5197 }
5198 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5199 ret->type = XPATH_STRING;
5200 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005201#ifdef XP_DEBUG_OBJ_USAGE
5202 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5203#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005204 return(ret);
5205}
5206
5207/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005208 * xmlXPathWrapCString:
5209 * @val: the char * value
5210 *
5211 * Wraps a string into an XPath object.
5212 *
5213 * Returns the newly created object.
5214 */
5215xmlXPathObjectPtr
5216xmlXPathWrapCString (char * val) {
5217 return(xmlXPathWrapString((xmlChar *)(val)));
5218}
5219
5220/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005221 * xmlXPathWrapExternal:
5222 * @val: the user data
5223 *
5224 * Wraps the @val data into an XPath object.
5225 *
5226 * Returns the newly created object.
5227 */
5228xmlXPathObjectPtr
5229xmlXPathWrapExternal (void *val) {
5230 xmlXPathObjectPtr ret;
5231
5232 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5233 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005234 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005235 return(NULL);
5236 }
5237 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5238 ret->type = XPATH_USERS;
5239 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005240#ifdef XP_DEBUG_OBJ_USAGE
5241 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5242#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005243 return(ret);
5244}
5245
5246/**
Owen Taylor3473f882001-02-23 17:55:21 +00005247 * xmlXPathObjectCopy:
5248 * @val: the original object
5249 *
5250 * allocate a new copy of a given object
5251 *
5252 * Returns the newly created object.
5253 */
5254xmlXPathObjectPtr
5255xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5256 xmlXPathObjectPtr ret;
5257
5258 if (val == NULL)
5259 return(NULL);
5260
5261 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005263 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005264 return(NULL);
5265 }
5266 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005267#ifdef XP_DEBUG_OBJ_USAGE
5268 xmlXPathDebugObjUsageRequested(NULL, val->type);
5269#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005270 switch (val->type) {
5271 case XPATH_BOOLEAN:
5272 case XPATH_NUMBER:
5273 case XPATH_POINT:
5274 case XPATH_RANGE:
5275 break;
5276 case XPATH_STRING:
5277 ret->stringval = xmlStrdup(val->stringval);
5278 break;
5279 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005280#if 0
5281/*
5282 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5283 this previous handling is no longer correct, and can cause some serious
5284 problems (ref. bug 145547)
5285*/
Owen Taylor3473f882001-02-23 17:55:21 +00005286 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005287 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005288 xmlNodePtr cur, tmp;
5289 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005290
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005291 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005292 top = xmlNewDoc(NULL);
5293 top->name = (char *)
5294 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005295 ret->user = top;
5296 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005297 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005298 cur = val->nodesetval->nodeTab[0]->children;
5299 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005300 tmp = xmlDocCopyNode(cur, top, 1);
5301 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005302 cur = cur->next;
5303 }
5304 }
William M. Bracke9449c52004-07-11 14:41:20 +00005305
Daniel Veillard9adc0462003-03-24 18:39:54 +00005306 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005307 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005308 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005309 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005310 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005311#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005312 case XPATH_NODESET:
5313 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005314 /* Do not deallocate the copied tree value */
5315 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005316 break;
5317 case XPATH_LOCATIONSET:
5318#ifdef LIBXML_XPTR_ENABLED
5319 {
5320 xmlLocationSetPtr loc = val->user;
5321 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5322 break;
5323 }
5324#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005325 case XPATH_USERS:
5326 ret->user = val->user;
5327 break;
5328 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005329 xmlGenericError(xmlGenericErrorContext,
5330 "xmlXPathObjectCopy: unsupported type %d\n",
5331 val->type);
5332 break;
5333 }
5334 return(ret);
5335}
5336
5337/**
5338 * xmlXPathFreeObject:
5339 * @obj: the object to free
5340 *
5341 * Free up an xmlXPathObjectPtr object.
5342 */
5343void
5344xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5345 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005346 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005347 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005348#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005349 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005350 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005351 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005352 } else
5353#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005354 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005355 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005356 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005357 } else {
5358 if (obj->nodesetval != NULL)
5359 xmlXPathFreeNodeSet(obj->nodesetval);
5360 }
Owen Taylor3473f882001-02-23 17:55:21 +00005361#ifdef LIBXML_XPTR_ENABLED
5362 } else if (obj->type == XPATH_LOCATIONSET) {
5363 if (obj->user != NULL)
5364 xmlXPtrFreeLocationSet(obj->user);
5365#endif
5366 } else if (obj->type == XPATH_STRING) {
5367 if (obj->stringval != NULL)
5368 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005369 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005370#ifdef XP_DEBUG_OBJ_USAGE
5371 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5372#endif
5373 xmlFree(obj);
5374}
Owen Taylor3473f882001-02-23 17:55:21 +00005375
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005376/**
5377 * xmlXPathReleaseObject:
5378 * @obj: the xmlXPathObjectPtr to free or to cache
5379 *
5380 * Depending on the state of the cache this frees the given
5381 * XPath object or stores it in the cache.
5382 */
5383static void
5384xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5385{
5386#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5387 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5388 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5389
5390#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5391
5392 if (obj == NULL)
5393 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005394 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005395 xmlXPathFreeObject(obj);
5396 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005397 xmlXPathContextCachePtr cache =
5398 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005399
5400 switch (obj->type) {
5401 case XPATH_NODESET:
5402 case XPATH_XSLT_TREE:
5403 if (obj->nodesetval != NULL) {
5404 if (obj->boolval) {
5405 /*
5406 * It looks like the @boolval is used for
5407 * evaluation if this an XSLT Result Tree Fragment.
5408 * TODO: Check if this assumption is correct.
5409 */
5410 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5411 xmlXPathFreeValueTree(obj->nodesetval);
5412 obj->nodesetval = NULL;
5413 } else if ((obj->nodesetval->nodeMax <= 40) &&
5414 (XP_CACHE_WANTS(cache->nodesetObjs,
5415 cache->maxNodeset)))
5416 {
5417 XP_CACHE_ADD(cache->nodesetObjs, obj);
5418 goto obj_cached;
5419 } else {
5420 xmlXPathFreeNodeSet(obj->nodesetval);
5421 obj->nodesetval = NULL;
5422 }
5423 }
5424 break;
5425 case XPATH_STRING:
5426 if (obj->stringval != NULL)
5427 xmlFree(obj->stringval);
5428
5429 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5430 XP_CACHE_ADD(cache->stringObjs, obj);
5431 goto obj_cached;
5432 }
5433 break;
5434 case XPATH_BOOLEAN:
5435 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5436 XP_CACHE_ADD(cache->booleanObjs, obj);
5437 goto obj_cached;
5438 }
5439 break;
5440 case XPATH_NUMBER:
5441 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5442 XP_CACHE_ADD(cache->numberObjs, obj);
5443 goto obj_cached;
5444 }
5445 break;
5446#ifdef LIBXML_XPTR_ENABLED
5447 case XPATH_LOCATIONSET:
5448 if (obj->user != NULL) {
5449 xmlXPtrFreeLocationSet(obj->user);
5450 }
5451 goto free_obj;
5452#endif
5453 default:
5454 goto free_obj;
5455 }
5456
5457 /*
5458 * Fallback to adding to the misc-objects slot.
5459 */
5460 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5461 XP_CACHE_ADD(cache->miscObjs, obj);
5462 } else
5463 goto free_obj;
5464
5465obj_cached:
5466
5467#ifdef XP_DEBUG_OBJ_USAGE
5468 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5469#endif
5470
5471 if (obj->nodesetval != NULL) {
5472 xmlNodeSetPtr tmpset = obj->nodesetval;
5473
5474 /*
5475 * TODO: Due to those nasty ns-nodes, we need to traverse
5476 * the list and free the ns-nodes.
5477 * URGENT TODO: Check if it's actually slowing things down.
5478 * Maybe we shouldn't try to preserve the list.
5479 */
5480 if (tmpset->nodeNr > 1) {
5481 int i;
5482 xmlNodePtr node;
5483
5484 for (i = 0; i < tmpset->nodeNr; i++) {
5485 node = tmpset->nodeTab[i];
5486 if ((node != NULL) &&
5487 (node->type == XML_NAMESPACE_DECL))
5488 {
5489 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5490 }
5491 }
5492 } else if (tmpset->nodeNr == 1) {
5493 if ((tmpset->nodeTab[0] != NULL) &&
5494 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5495 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5496 }
5497 tmpset->nodeNr = 0;
5498 memset(obj, 0, sizeof(xmlXPathObject));
5499 obj->nodesetval = tmpset;
5500 } else
5501 memset(obj, 0, sizeof(xmlXPathObject));
5502
5503 return;
5504
5505free_obj:
5506 /*
5507 * Cache is full; free the object.
5508 */
5509 if (obj->nodesetval != NULL)
5510 xmlXPathFreeNodeSet(obj->nodesetval);
5511#ifdef XP_DEBUG_OBJ_USAGE
5512 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5513#endif
5514 xmlFree(obj);
5515 }
5516 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005517}
5518
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005519
5520/************************************************************************
5521 * *
5522 * Type Casting Routines *
5523 * *
5524 ************************************************************************/
5525
5526/**
5527 * xmlXPathCastBooleanToString:
5528 * @val: a boolean
5529 *
5530 * Converts a boolean to its string value.
5531 *
5532 * Returns a newly allocated string.
5533 */
5534xmlChar *
5535xmlXPathCastBooleanToString (int val) {
5536 xmlChar *ret;
5537 if (val)
5538 ret = xmlStrdup((const xmlChar *) "true");
5539 else
5540 ret = xmlStrdup((const xmlChar *) "false");
5541 return(ret);
5542}
5543
5544/**
5545 * xmlXPathCastNumberToString:
5546 * @val: a number
5547 *
5548 * Converts a number to its string value.
5549 *
5550 * Returns a newly allocated string.
5551 */
5552xmlChar *
5553xmlXPathCastNumberToString (double val) {
5554 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005555 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005556 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005557 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005558 break;
5559 case -1:
5560 ret = xmlStrdup((const xmlChar *) "-Infinity");
5561 break;
5562 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005563 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005564 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005565 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5566 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005567 } else {
5568 /* could be improved */
5569 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005570 xmlXPathFormatNumber(val, buf, 99);
5571 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005572 ret = xmlStrdup((const xmlChar *) buf);
5573 }
5574 }
5575 return(ret);
5576}
5577
5578/**
5579 * xmlXPathCastNodeToString:
5580 * @node: a node
5581 *
5582 * Converts a node to its string value.
5583 *
5584 * Returns a newly allocated string.
5585 */
5586xmlChar *
5587xmlXPathCastNodeToString (xmlNodePtr node) {
William M. Brackd611c882007-05-31 05:07:17 +00005588xmlChar *ret;
5589 if ((ret = xmlNodeGetContent(node)) == NULL)
5590 ret = xmlStrdup((const xmlChar *) "");
5591 return(ret);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005592}
5593
5594/**
5595 * xmlXPathCastNodeSetToString:
5596 * @ns: a node-set
5597 *
5598 * Converts a node-set to its string value.
5599 *
5600 * Returns a newly allocated string.
5601 */
5602xmlChar *
5603xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5604 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5605 return(xmlStrdup((const xmlChar *) ""));
5606
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005607 if (ns->nodeNr > 1)
5608 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005609 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5610}
5611
5612/**
5613 * xmlXPathCastToString:
5614 * @val: an XPath object
5615 *
5616 * Converts an existing object to its string() equivalent
5617 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005618 * Returns the allocated string value of the object, NULL in case of error.
5619 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005620 */
5621xmlChar *
5622xmlXPathCastToString(xmlXPathObjectPtr val) {
5623 xmlChar *ret = NULL;
5624
5625 if (val == NULL)
5626 return(xmlStrdup((const xmlChar *) ""));
5627 switch (val->type) {
5628 case XPATH_UNDEFINED:
5629#ifdef DEBUG_EXPR
5630 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5631#endif
5632 ret = xmlStrdup((const xmlChar *) "");
5633 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005634 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005635 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005636 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5637 break;
5638 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005639 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005640 case XPATH_BOOLEAN:
5641 ret = xmlXPathCastBooleanToString(val->boolval);
5642 break;
5643 case XPATH_NUMBER: {
5644 ret = xmlXPathCastNumberToString(val->floatval);
5645 break;
5646 }
5647 case XPATH_USERS:
5648 case XPATH_POINT:
5649 case XPATH_RANGE:
5650 case XPATH_LOCATIONSET:
5651 TODO
5652 ret = xmlStrdup((const xmlChar *) "");
5653 break;
5654 }
5655 return(ret);
5656}
5657
5658/**
5659 * xmlXPathConvertString:
5660 * @val: an XPath object
5661 *
5662 * Converts an existing object to its string() equivalent
5663 *
5664 * Returns the new object, the old one is freed (or the operation
5665 * is done directly on @val)
5666 */
5667xmlXPathObjectPtr
5668xmlXPathConvertString(xmlXPathObjectPtr val) {
5669 xmlChar *res = NULL;
5670
5671 if (val == NULL)
5672 return(xmlXPathNewCString(""));
5673
5674 switch (val->type) {
5675 case XPATH_UNDEFINED:
5676#ifdef DEBUG_EXPR
5677 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5678#endif
5679 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005680 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005681 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005682 res = xmlXPathCastNodeSetToString(val->nodesetval);
5683 break;
5684 case XPATH_STRING:
5685 return(val);
5686 case XPATH_BOOLEAN:
5687 res = xmlXPathCastBooleanToString(val->boolval);
5688 break;
5689 case XPATH_NUMBER:
5690 res = xmlXPathCastNumberToString(val->floatval);
5691 break;
5692 case XPATH_USERS:
5693 case XPATH_POINT:
5694 case XPATH_RANGE:
5695 case XPATH_LOCATIONSET:
5696 TODO;
5697 break;
5698 }
5699 xmlXPathFreeObject(val);
5700 if (res == NULL)
5701 return(xmlXPathNewCString(""));
5702 return(xmlXPathWrapString(res));
5703}
5704
5705/**
5706 * xmlXPathCastBooleanToNumber:
5707 * @val: a boolean
5708 *
5709 * Converts a boolean to its number value
5710 *
5711 * Returns the number value
5712 */
5713double
5714xmlXPathCastBooleanToNumber(int val) {
5715 if (val)
5716 return(1.0);
5717 return(0.0);
5718}
5719
5720/**
5721 * xmlXPathCastStringToNumber:
5722 * @val: a string
5723 *
5724 * Converts a string to its number value
5725 *
5726 * Returns the number value
5727 */
5728double
5729xmlXPathCastStringToNumber(const xmlChar * val) {
5730 return(xmlXPathStringEvalNumber(val));
5731}
5732
5733/**
5734 * xmlXPathCastNodeToNumber:
5735 * @node: a node
5736 *
5737 * Converts a node to its number value
5738 *
5739 * Returns the number value
5740 */
5741double
5742xmlXPathCastNodeToNumber (xmlNodePtr node) {
5743 xmlChar *strval;
5744 double ret;
5745
5746 if (node == NULL)
5747 return(xmlXPathNAN);
5748 strval = xmlXPathCastNodeToString(node);
5749 if (strval == NULL)
5750 return(xmlXPathNAN);
5751 ret = xmlXPathCastStringToNumber(strval);
5752 xmlFree(strval);
5753
5754 return(ret);
5755}
5756
5757/**
5758 * xmlXPathCastNodeSetToNumber:
5759 * @ns: a node-set
5760 *
5761 * Converts a node-set to its number value
5762 *
5763 * Returns the number value
5764 */
5765double
5766xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5767 xmlChar *str;
5768 double ret;
5769
5770 if (ns == NULL)
5771 return(xmlXPathNAN);
5772 str = xmlXPathCastNodeSetToString(ns);
5773 ret = xmlXPathCastStringToNumber(str);
5774 xmlFree(str);
5775 return(ret);
5776}
5777
5778/**
5779 * xmlXPathCastToNumber:
5780 * @val: an XPath object
5781 *
5782 * Converts an XPath object to its number value
5783 *
5784 * Returns the number value
5785 */
5786double
5787xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5788 double ret = 0.0;
5789
5790 if (val == NULL)
5791 return(xmlXPathNAN);
5792 switch (val->type) {
5793 case XPATH_UNDEFINED:
5794#ifdef DEGUB_EXPR
5795 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5796#endif
5797 ret = xmlXPathNAN;
5798 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005799 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005800 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005801 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5802 break;
5803 case XPATH_STRING:
5804 ret = xmlXPathCastStringToNumber(val->stringval);
5805 break;
5806 case XPATH_NUMBER:
5807 ret = val->floatval;
5808 break;
5809 case XPATH_BOOLEAN:
5810 ret = xmlXPathCastBooleanToNumber(val->boolval);
5811 break;
5812 case XPATH_USERS:
5813 case XPATH_POINT:
5814 case XPATH_RANGE:
5815 case XPATH_LOCATIONSET:
5816 TODO;
5817 ret = xmlXPathNAN;
5818 break;
5819 }
5820 return(ret);
5821}
5822
5823/**
5824 * xmlXPathConvertNumber:
5825 * @val: an XPath object
5826 *
5827 * Converts an existing object to its number() equivalent
5828 *
5829 * Returns the new object, the old one is freed (or the operation
5830 * is done directly on @val)
5831 */
5832xmlXPathObjectPtr
5833xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5834 xmlXPathObjectPtr ret;
5835
5836 if (val == NULL)
5837 return(xmlXPathNewFloat(0.0));
5838 if (val->type == XPATH_NUMBER)
5839 return(val);
5840 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5841 xmlXPathFreeObject(val);
5842 return(ret);
5843}
5844
5845/**
5846 * xmlXPathCastNumberToBoolean:
5847 * @val: a number
5848 *
5849 * Converts a number to its boolean value
5850 *
5851 * Returns the boolean value
5852 */
5853int
5854xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005855 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005856 return(0);
5857 return(1);
5858}
5859
5860/**
5861 * xmlXPathCastStringToBoolean:
5862 * @val: a string
5863 *
5864 * Converts a string to its boolean value
5865 *
5866 * Returns the boolean value
5867 */
5868int
5869xmlXPathCastStringToBoolean (const xmlChar *val) {
5870 if ((val == NULL) || (xmlStrlen(val) == 0))
5871 return(0);
5872 return(1);
5873}
5874
5875/**
5876 * xmlXPathCastNodeSetToBoolean:
5877 * @ns: a node-set
5878 *
5879 * Converts a node-set to its boolean value
5880 *
5881 * Returns the boolean value
5882 */
5883int
5884xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5885 if ((ns == NULL) || (ns->nodeNr == 0))
5886 return(0);
5887 return(1);
5888}
5889
5890/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005891 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005892 * @val: an XPath object
5893 *
5894 * Converts an XPath object to its boolean value
5895 *
5896 * Returns the boolean value
5897 */
5898int
5899xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5900 int ret = 0;
5901
5902 if (val == NULL)
5903 return(0);
5904 switch (val->type) {
5905 case XPATH_UNDEFINED:
5906#ifdef DEBUG_EXPR
5907 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5908#endif
5909 ret = 0;
5910 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005911 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005912 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005913 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5914 break;
5915 case XPATH_STRING:
5916 ret = xmlXPathCastStringToBoolean(val->stringval);
5917 break;
5918 case XPATH_NUMBER:
5919 ret = xmlXPathCastNumberToBoolean(val->floatval);
5920 break;
5921 case XPATH_BOOLEAN:
5922 ret = val->boolval;
5923 break;
5924 case XPATH_USERS:
5925 case XPATH_POINT:
5926 case XPATH_RANGE:
5927 case XPATH_LOCATIONSET:
5928 TODO;
5929 ret = 0;
5930 break;
5931 }
5932 return(ret);
5933}
5934
5935
5936/**
5937 * xmlXPathConvertBoolean:
5938 * @val: an XPath object
5939 *
5940 * Converts an existing object to its boolean() equivalent
5941 *
5942 * Returns the new object, the old one is freed (or the operation
5943 * is done directly on @val)
5944 */
5945xmlXPathObjectPtr
5946xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5947 xmlXPathObjectPtr ret;
5948
5949 if (val == NULL)
5950 return(xmlXPathNewBoolean(0));
5951 if (val->type == XPATH_BOOLEAN)
5952 return(val);
5953 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5954 xmlXPathFreeObject(val);
5955 return(ret);
5956}
5957
Owen Taylor3473f882001-02-23 17:55:21 +00005958/************************************************************************
5959 * *
5960 * Routines to handle XPath contexts *
5961 * *
5962 ************************************************************************/
5963
5964/**
5965 * xmlXPathNewContext:
5966 * @doc: the XML document
5967 *
5968 * Create a new xmlXPathContext
5969 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005970 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005971 */
5972xmlXPathContextPtr
5973xmlXPathNewContext(xmlDocPtr doc) {
5974 xmlXPathContextPtr ret;
5975
5976 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5977 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005978 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005979 return(NULL);
5980 }
5981 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5982 ret->doc = doc;
5983 ret->node = NULL;
5984
5985 ret->varHash = NULL;
5986
5987 ret->nb_types = 0;
5988 ret->max_types = 0;
5989 ret->types = NULL;
5990
5991 ret->funcHash = xmlHashCreate(0);
5992
5993 ret->nb_axis = 0;
5994 ret->max_axis = 0;
5995 ret->axis = NULL;
5996
5997 ret->nsHash = NULL;
5998 ret->user = NULL;
5999
6000 ret->contextSize = -1;
6001 ret->proximityPosition = -1;
6002
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006003#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006004 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006005 xmlXPathFreeContext(ret);
6006 return(NULL);
6007 }
6008#endif
6009
6010 xmlXPathRegisterAllFunctions(ret);
6011
Owen Taylor3473f882001-02-23 17:55:21 +00006012 return(ret);
6013}
6014
6015/**
6016 * xmlXPathFreeContext:
6017 * @ctxt: the context to free
6018 *
6019 * Free up an xmlXPathContext
6020 */
6021void
6022xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006023 if (ctxt == NULL) return;
6024
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006025 if (ctxt->cache != NULL)
6026 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006027 xmlXPathRegisteredNsCleanup(ctxt);
6028 xmlXPathRegisteredFuncsCleanup(ctxt);
6029 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006030 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006031 xmlFree(ctxt);
6032}
6033
6034/************************************************************************
6035 * *
6036 * Routines to handle XPath parser contexts *
6037 * *
6038 ************************************************************************/
6039
6040#define CHECK_CTXT(ctxt) \
6041 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006042 __xmlRaiseError(NULL, NULL, NULL, \
6043 NULL, NULL, XML_FROM_XPATH, \
6044 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6045 __FILE__, __LINE__, \
6046 NULL, NULL, NULL, 0, 0, \
6047 "NULL context pointer\n"); \
6048 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006049 } \
6050
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006051#define CHECK_CTXT_NEG(ctxt) \
6052 if (ctxt == NULL) { \
6053 __xmlRaiseError(NULL, NULL, NULL, \
6054 NULL, NULL, XML_FROM_XPATH, \
6055 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6056 __FILE__, __LINE__, \
6057 NULL, NULL, NULL, 0, 0, \
6058 "NULL context pointer\n"); \
6059 return(-1); \
6060 } \
6061
Owen Taylor3473f882001-02-23 17:55:21 +00006062
6063#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006064 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6065 (ctxt->doc->children == NULL)) { \
6066 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006067 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006068 }
Owen Taylor3473f882001-02-23 17:55:21 +00006069
6070
6071/**
6072 * xmlXPathNewParserContext:
6073 * @str: the XPath expression
6074 * @ctxt: the XPath context
6075 *
6076 * Create a new xmlXPathParserContext
6077 *
6078 * Returns the xmlXPathParserContext just allocated.
6079 */
6080xmlXPathParserContextPtr
6081xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6082 xmlXPathParserContextPtr ret;
6083
6084 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6085 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006086 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006087 return(NULL);
6088 }
6089 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6090 ret->cur = ret->base = str;
6091 ret->context = ctxt;
6092
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006093 ret->comp = xmlXPathNewCompExpr();
6094 if (ret->comp == NULL) {
6095 xmlFree(ret->valueTab);
6096 xmlFree(ret);
6097 return(NULL);
6098 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006099 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6100 ret->comp->dict = ctxt->dict;
6101 xmlDictReference(ret->comp->dict);
6102 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006103
6104 return(ret);
6105}
6106
6107/**
6108 * xmlXPathCompParserContext:
6109 * @comp: the XPath compiled expression
6110 * @ctxt: the XPath context
6111 *
6112 * Create a new xmlXPathParserContext when processing a compiled expression
6113 *
6114 * Returns the xmlXPathParserContext just allocated.
6115 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006116static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006117xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6118 xmlXPathParserContextPtr ret;
6119
6120 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6121 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006122 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006123 return(NULL);
6124 }
6125 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6126
Owen Taylor3473f882001-02-23 17:55:21 +00006127 /* Allocate the value stack */
6128 ret->valueTab = (xmlXPathObjectPtr *)
6129 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006130 if (ret->valueTab == NULL) {
6131 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006132 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006133 return(NULL);
6134 }
Owen Taylor3473f882001-02-23 17:55:21 +00006135 ret->valueNr = 0;
6136 ret->valueMax = 10;
6137 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006138
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006139 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006140 ret->comp = comp;
6141
Owen Taylor3473f882001-02-23 17:55:21 +00006142 return(ret);
6143}
6144
6145/**
6146 * xmlXPathFreeParserContext:
6147 * @ctxt: the context to free
6148 *
6149 * Free up an xmlXPathParserContext
6150 */
6151void
6152xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6153 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006154 xmlFree(ctxt->valueTab);
6155 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006156 if (ctxt->comp != NULL) {
6157#ifdef XPATH_STREAMING
6158 if (ctxt->comp->stream != NULL) {
6159 xmlFreePatternList(ctxt->comp->stream);
6160 ctxt->comp->stream = NULL;
6161 }
6162#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006163 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006164 }
Owen Taylor3473f882001-02-23 17:55:21 +00006165 xmlFree(ctxt);
6166}
6167
6168/************************************************************************
6169 * *
6170 * The implicit core function library *
6171 * *
6172 ************************************************************************/
6173
Owen Taylor3473f882001-02-23 17:55:21 +00006174/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006175 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006176 * @node: a node pointer
6177 *
6178 * Function computing the beginning of the string value of the node,
6179 * used to speed up comparisons
6180 *
6181 * Returns an int usable as a hash
6182 */
6183static unsigned int
6184xmlXPathNodeValHash(xmlNodePtr node) {
6185 int len = 2;
6186 const xmlChar * string = NULL;
6187 xmlNodePtr tmp = NULL;
6188 unsigned int ret = 0;
6189
6190 if (node == NULL)
6191 return(0);
6192
Daniel Veillard9adc0462003-03-24 18:39:54 +00006193 if (node->type == XML_DOCUMENT_NODE) {
6194 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6195 if (tmp == NULL)
6196 node = node->children;
6197 else
6198 node = tmp;
6199
6200 if (node == NULL)
6201 return(0);
6202 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006203
6204 switch (node->type) {
6205 case XML_COMMENT_NODE:
6206 case XML_PI_NODE:
6207 case XML_CDATA_SECTION_NODE:
6208 case XML_TEXT_NODE:
6209 string = node->content;
6210 if (string == NULL)
6211 return(0);
6212 if (string[0] == 0)
6213 return(0);
6214 return(((unsigned int) string[0]) +
6215 (((unsigned int) string[1]) << 8));
6216 case XML_NAMESPACE_DECL:
6217 string = ((xmlNsPtr)node)->href;
6218 if (string == NULL)
6219 return(0);
6220 if (string[0] == 0)
6221 return(0);
6222 return(((unsigned int) string[0]) +
6223 (((unsigned int) string[1]) << 8));
6224 case XML_ATTRIBUTE_NODE:
6225 tmp = ((xmlAttrPtr) node)->children;
6226 break;
6227 case XML_ELEMENT_NODE:
6228 tmp = node->children;
6229 break;
6230 default:
6231 return(0);
6232 }
6233 while (tmp != NULL) {
6234 switch (tmp->type) {
6235 case XML_COMMENT_NODE:
6236 case XML_PI_NODE:
6237 case XML_CDATA_SECTION_NODE:
6238 case XML_TEXT_NODE:
6239 string = tmp->content;
6240 break;
6241 case XML_NAMESPACE_DECL:
6242 string = ((xmlNsPtr)tmp)->href;
6243 break;
6244 default:
6245 break;
6246 }
6247 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006248 if (len == 1) {
6249 return(ret + (((unsigned int) string[0]) << 8));
6250 }
6251 if (string[1] == 0) {
6252 len = 1;
6253 ret = (unsigned int) string[0];
6254 } else {
6255 return(((unsigned int) string[0]) +
6256 (((unsigned int) string[1]) << 8));
6257 }
6258 }
6259 /*
6260 * Skip to next node
6261 */
6262 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6263 if (tmp->children->type != XML_ENTITY_DECL) {
6264 tmp = tmp->children;
6265 continue;
6266 }
6267 }
6268 if (tmp == node)
6269 break;
6270
6271 if (tmp->next != NULL) {
6272 tmp = tmp->next;
6273 continue;
6274 }
6275
6276 do {
6277 tmp = tmp->parent;
6278 if (tmp == NULL)
6279 break;
6280 if (tmp == node) {
6281 tmp = NULL;
6282 break;
6283 }
6284 if (tmp->next != NULL) {
6285 tmp = tmp->next;
6286 break;
6287 }
6288 } while (tmp != NULL);
6289 }
6290 return(ret);
6291}
6292
6293/**
6294 * xmlXPathStringHash:
6295 * @string: a string
6296 *
6297 * Function computing the beginning of the string value of the node,
6298 * used to speed up comparisons
6299 *
6300 * Returns an int usable as a hash
6301 */
6302static unsigned int
6303xmlXPathStringHash(const xmlChar * string) {
6304 if (string == NULL)
6305 return((unsigned int) 0);
6306 if (string[0] == 0)
6307 return(0);
6308 return(((unsigned int) string[0]) +
6309 (((unsigned int) string[1]) << 8));
6310}
6311
6312/**
Owen Taylor3473f882001-02-23 17:55:21 +00006313 * xmlXPathCompareNodeSetFloat:
6314 * @ctxt: the XPath Parser context
6315 * @inf: less than (1) or greater than (0)
6316 * @strict: is the comparison strict
6317 * @arg: the node set
6318 * @f: the value
6319 *
6320 * Implement the compare operation between a nodeset and a number
6321 * @ns < @val (1, 1, ...
6322 * @ns <= @val (1, 0, ...
6323 * @ns > @val (0, 1, ...
6324 * @ns >= @val (0, 0, ...
6325 *
6326 * If one object to be compared is a node-set and the other is a number,
6327 * then the comparison will be true if and only if there is a node in the
6328 * node-set such that the result of performing the comparison on the number
6329 * to be compared and on the result of converting the string-value of that
6330 * node to a number using the number function is true.
6331 *
6332 * Returns 0 or 1 depending on the results of the test.
6333 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006334static int
Owen Taylor3473f882001-02-23 17:55:21 +00006335xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6336 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6337 int i, ret = 0;
6338 xmlNodeSetPtr ns;
6339 xmlChar *str2;
6340
6341 if ((f == NULL) || (arg == NULL) ||
6342 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006343 xmlXPathReleaseObject(ctxt->context, arg);
6344 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006345 return(0);
6346 }
6347 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006348 if (ns != NULL) {
6349 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006350 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006351 if (str2 != NULL) {
6352 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006353 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006354 xmlFree(str2);
6355 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006356 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006357 ret = xmlXPathCompareValues(ctxt, inf, strict);
6358 if (ret)
6359 break;
6360 }
6361 }
Owen Taylor3473f882001-02-23 17:55:21 +00006362 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006363 xmlXPathReleaseObject(ctxt->context, arg);
6364 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006365 return(ret);
6366}
6367
6368/**
6369 * xmlXPathCompareNodeSetString:
6370 * @ctxt: the XPath Parser context
6371 * @inf: less than (1) or greater than (0)
6372 * @strict: is the comparison strict
6373 * @arg: the node set
6374 * @s: the value
6375 *
6376 * Implement the compare operation between a nodeset and a string
6377 * @ns < @val (1, 1, ...
6378 * @ns <= @val (1, 0, ...
6379 * @ns > @val (0, 1, ...
6380 * @ns >= @val (0, 0, ...
6381 *
6382 * If one object to be compared is a node-set and the other is a string,
6383 * then the comparison will be true if and only if there is a node in
6384 * the node-set such that the result of performing the comparison on the
6385 * string-value of the node and the other string is true.
6386 *
6387 * Returns 0 or 1 depending on the results of the test.
6388 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006389static int
Owen Taylor3473f882001-02-23 17:55:21 +00006390xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6391 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6392 int i, ret = 0;
6393 xmlNodeSetPtr ns;
6394 xmlChar *str2;
6395
6396 if ((s == NULL) || (arg == NULL) ||
6397 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006398 xmlXPathReleaseObject(ctxt->context, arg);
6399 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006400 return(0);
6401 }
6402 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006403 if (ns != NULL) {
6404 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006405 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006406 if (str2 != NULL) {
6407 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006408 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006409 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006410 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006411 ret = xmlXPathCompareValues(ctxt, inf, strict);
6412 if (ret)
6413 break;
6414 }
6415 }
Owen Taylor3473f882001-02-23 17:55:21 +00006416 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006417 xmlXPathReleaseObject(ctxt->context, arg);
6418 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006419 return(ret);
6420}
6421
6422/**
6423 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006424 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006425 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006426 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006427 * @arg2: the second node set object
6428 *
6429 * Implement the compare operation on nodesets:
6430 *
6431 * If both objects to be compared are node-sets, then the comparison
6432 * will be true if and only if there is a node in the first node-set
6433 * and a node in the second node-set such that the result of performing
6434 * the comparison on the string-values of the two nodes is true.
6435 * ....
6436 * When neither object to be compared is a node-set and the operator
6437 * is <=, <, >= or >, then the objects are compared by converting both
6438 * objects to numbers and comparing the numbers according to IEEE 754.
6439 * ....
6440 * The number function converts its argument to a number as follows:
6441 * - a string that consists of optional whitespace followed by an
6442 * optional minus sign followed by a Number followed by whitespace
6443 * is converted to the IEEE 754 number that is nearest (according
6444 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6445 * represented by the string; any other string is converted to NaN
6446 *
6447 * Conclusion all nodes need to be converted first to their string value
6448 * and then the comparison must be done when possible
6449 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006450static int
6451xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006452 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6453 int i, j, init = 0;
6454 double val1;
6455 double *values2;
6456 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006457 xmlNodeSetPtr ns1;
6458 xmlNodeSetPtr ns2;
6459
6460 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006461 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6462 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006463 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006464 }
Owen Taylor3473f882001-02-23 17:55:21 +00006465 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006466 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6467 xmlXPathFreeObject(arg1);
6468 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006469 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006470 }
Owen Taylor3473f882001-02-23 17:55:21 +00006471
6472 ns1 = arg1->nodesetval;
6473 ns2 = arg2->nodesetval;
6474
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006475 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006476 xmlXPathFreeObject(arg1);
6477 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006478 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006479 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006480 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006481 xmlXPathFreeObject(arg1);
6482 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006483 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006484 }
Owen Taylor3473f882001-02-23 17:55:21 +00006485
6486 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6487 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006488 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006489 xmlXPathFreeObject(arg1);
6490 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006491 return(0);
6492 }
6493 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006494 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006495 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006496 continue;
6497 for (j = 0;j < ns2->nodeNr;j++) {
6498 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006499 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006500 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006501 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006502 continue;
6503 if (inf && strict)
6504 ret = (val1 < values2[j]);
6505 else if (inf && !strict)
6506 ret = (val1 <= values2[j]);
6507 else if (!inf && strict)
6508 ret = (val1 > values2[j]);
6509 else if (!inf && !strict)
6510 ret = (val1 >= values2[j]);
6511 if (ret)
6512 break;
6513 }
6514 if (ret)
6515 break;
6516 init = 1;
6517 }
6518 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006519 xmlXPathFreeObject(arg1);
6520 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006521 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006522}
6523
6524/**
6525 * xmlXPathCompareNodeSetValue:
6526 * @ctxt: the XPath Parser context
6527 * @inf: less than (1) or greater than (0)
6528 * @strict: is the comparison strict
6529 * @arg: the node set
6530 * @val: the value
6531 *
6532 * Implement the compare operation between a nodeset and a value
6533 * @ns < @val (1, 1, ...
6534 * @ns <= @val (1, 0, ...
6535 * @ns > @val (0, 1, ...
6536 * @ns >= @val (0, 0, ...
6537 *
6538 * If one object to be compared is a node-set and the other is a boolean,
6539 * then the comparison will be true if and only if the result of performing
6540 * the comparison on the boolean and on the result of converting
6541 * the node-set to a boolean using the boolean function is true.
6542 *
6543 * Returns 0 or 1 depending on the results of the test.
6544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006545static int
Owen Taylor3473f882001-02-23 17:55:21 +00006546xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6547 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6548 if ((val == NULL) || (arg == NULL) ||
6549 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6550 return(0);
6551
6552 switch(val->type) {
6553 case XPATH_NUMBER:
6554 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6555 case XPATH_NODESET:
6556 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006557 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006558 case XPATH_STRING:
6559 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6560 case XPATH_BOOLEAN:
6561 valuePush(ctxt, arg);
6562 xmlXPathBooleanFunction(ctxt, 1);
6563 valuePush(ctxt, val);
6564 return(xmlXPathCompareValues(ctxt, inf, strict));
6565 default:
6566 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006567 }
6568 return(0);
6569}
6570
6571/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006572 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006573 * @arg: the nodeset object argument
6574 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006575 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006576 *
6577 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6578 * If one object to be compared is a node-set and the other is a string,
6579 * then the comparison will be true if and only if there is a node in
6580 * the node-set such that the result of performing the comparison on the
6581 * string-value of the node and the other string is true.
6582 *
6583 * Returns 0 or 1 depending on the results of the test.
6584 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006585static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006586xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006587{
Owen Taylor3473f882001-02-23 17:55:21 +00006588 int i;
6589 xmlNodeSetPtr ns;
6590 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006591 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006592
6593 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006594 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6595 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006596 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006597 /*
6598 * A NULL nodeset compared with a string is always false
6599 * (since there is no node equal, and no node not equal)
6600 */
6601 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006602 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006603 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006604 for (i = 0; i < ns->nodeNr; i++) {
6605 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6606 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6607 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6608 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006609 if (neq)
6610 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006611 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006612 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6613 if (neq)
6614 continue;
6615 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006616 } else if (neq) {
6617 if (str2 != NULL)
6618 xmlFree(str2);
6619 return (1);
6620 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006621 if (str2 != NULL)
6622 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006623 } else if (neq)
6624 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006625 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006626 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006627}
6628
6629/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006630 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006631 * @arg: the nodeset object argument
6632 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006633 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006634 *
6635 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6636 * If one object to be compared is a node-set and the other is a number,
6637 * then the comparison will be true if and only if there is a node in
6638 * the node-set such that the result of performing the comparison on the
6639 * number to be compared and on the result of converting the string-value
6640 * of that node to a number using the number function is true.
6641 *
6642 * Returns 0 or 1 depending on the results of the test.
6643 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006644static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006645xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6646 xmlXPathObjectPtr arg, double f, int neq) {
6647 int i, ret=0;
6648 xmlNodeSetPtr ns;
6649 xmlChar *str2;
6650 xmlXPathObjectPtr val;
6651 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006652
6653 if ((arg == NULL) ||
6654 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6655 return(0);
6656
William M. Brack0c022ad2002-07-12 00:56:01 +00006657 ns = arg->nodesetval;
6658 if (ns != NULL) {
6659 for (i=0;i<ns->nodeNr;i++) {
6660 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6661 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006662 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006663 xmlFree(str2);
6664 xmlXPathNumberFunction(ctxt, 1);
6665 val = valuePop(ctxt);
6666 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006667 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006668 if (!xmlXPathIsNaN(v)) {
6669 if ((!neq) && (v==f)) {
6670 ret = 1;
6671 break;
6672 } else if ((neq) && (v!=f)) {
6673 ret = 1;
6674 break;
6675 }
William M. Brack32f0f712005-07-14 07:00:33 +00006676 } else { /* NaN is unequal to any value */
6677 if (neq)
6678 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006679 }
6680 }
6681 }
6682 }
6683
6684 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006685}
6686
6687
6688/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006689 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006690 * @arg1: first nodeset object argument
6691 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006692 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006693 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006694 * Implement the equal / not equal operation on XPath nodesets:
6695 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006696 * If both objects to be compared are node-sets, then the comparison
6697 * will be true if and only if there is a node in the first node-set and
6698 * a node in the second node-set such that the result of performing the
6699 * comparison on the string-values of the two nodes is true.
6700 *
6701 * (needless to say, this is a costly operation)
6702 *
6703 * Returns 0 or 1 depending on the results of the test.
6704 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006705static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006706xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006707 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006708 unsigned int *hashs1;
6709 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006710 xmlChar **values1;
6711 xmlChar **values2;
6712 int ret = 0;
6713 xmlNodeSetPtr ns1;
6714 xmlNodeSetPtr ns2;
6715
6716 if ((arg1 == NULL) ||
6717 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6718 return(0);
6719 if ((arg2 == NULL) ||
6720 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6721 return(0);
6722
6723 ns1 = arg1->nodesetval;
6724 ns2 = arg2->nodesetval;
6725
Daniel Veillard911f49a2001-04-07 15:39:35 +00006726 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006727 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006728 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006729 return(0);
6730
6731 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006732 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006733 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006734 if (neq == 0)
6735 for (i = 0;i < ns1->nodeNr;i++)
6736 for (j = 0;j < ns2->nodeNr;j++)
6737 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6738 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006739
6740 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006741 if (values1 == NULL) {
6742 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006743 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006744 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006745 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6746 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006747 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006748 xmlFree(values1);
6749 return(0);
6750 }
Owen Taylor3473f882001-02-23 17:55:21 +00006751 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6752 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6753 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006754 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006755 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006756 xmlFree(values1);
6757 return(0);
6758 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006759 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6760 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006761 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006762 xmlFree(hashs1);
6763 xmlFree(values1);
6764 xmlFree(values2);
6765 return(0);
6766 }
Owen Taylor3473f882001-02-23 17:55:21 +00006767 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6768 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006769 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006770 for (j = 0;j < ns2->nodeNr;j++) {
6771 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006772 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006773 if (hashs1[i] != hashs2[j]) {
6774 if (neq) {
6775 ret = 1;
6776 break;
6777 }
6778 }
6779 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006780 if (values1[i] == NULL)
6781 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6782 if (values2[j] == NULL)
6783 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006784 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006785 if (ret)
6786 break;
6787 }
Owen Taylor3473f882001-02-23 17:55:21 +00006788 }
6789 if (ret)
6790 break;
6791 }
6792 for (i = 0;i < ns1->nodeNr;i++)
6793 if (values1[i] != NULL)
6794 xmlFree(values1[i]);
6795 for (j = 0;j < ns2->nodeNr;j++)
6796 if (values2[j] != NULL)
6797 xmlFree(values2[j]);
6798 xmlFree(values1);
6799 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006800 xmlFree(hashs1);
6801 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006802 return(ret);
6803}
6804
William M. Brack0c022ad2002-07-12 00:56:01 +00006805static int
6806xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6807 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006808 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006809 /*
6810 *At this point we are assured neither arg1 nor arg2
6811 *is a nodeset, so we can just pick the appropriate routine.
6812 */
Owen Taylor3473f882001-02-23 17:55:21 +00006813 switch (arg1->type) {
6814 case XPATH_UNDEFINED:
6815#ifdef DEBUG_EXPR
6816 xmlGenericError(xmlGenericErrorContext,
6817 "Equal: undefined\n");
6818#endif
6819 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006820 case XPATH_BOOLEAN:
6821 switch (arg2->type) {
6822 case XPATH_UNDEFINED:
6823#ifdef DEBUG_EXPR
6824 xmlGenericError(xmlGenericErrorContext,
6825 "Equal: undefined\n");
6826#endif
6827 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006828 case XPATH_BOOLEAN:
6829#ifdef DEBUG_EXPR
6830 xmlGenericError(xmlGenericErrorContext,
6831 "Equal: %d boolean %d \n",
6832 arg1->boolval, arg2->boolval);
6833#endif
6834 ret = (arg1->boolval == arg2->boolval);
6835 break;
6836 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006837 ret = (arg1->boolval ==
6838 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006839 break;
6840 case XPATH_STRING:
6841 if ((arg2->stringval == NULL) ||
6842 (arg2->stringval[0] == 0)) ret = 0;
6843 else
6844 ret = 1;
6845 ret = (arg1->boolval == ret);
6846 break;
6847 case XPATH_USERS:
6848 case XPATH_POINT:
6849 case XPATH_RANGE:
6850 case XPATH_LOCATIONSET:
6851 TODO
6852 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006853 case XPATH_NODESET:
6854 case XPATH_XSLT_TREE:
6855 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006856 }
6857 break;
6858 case XPATH_NUMBER:
6859 switch (arg2->type) {
6860 case XPATH_UNDEFINED:
6861#ifdef DEBUG_EXPR
6862 xmlGenericError(xmlGenericErrorContext,
6863 "Equal: undefined\n");
6864#endif
6865 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006866 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006867 ret = (arg2->boolval==
6868 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006869 break;
6870 case XPATH_STRING:
6871 valuePush(ctxt, arg2);
6872 xmlXPathNumberFunction(ctxt, 1);
6873 arg2 = valuePop(ctxt);
6874 /* no break on purpose */
6875 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006876 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006877 if (xmlXPathIsNaN(arg1->floatval) ||
6878 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006879 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006880 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6881 if (xmlXPathIsInf(arg2->floatval) == 1)
6882 ret = 1;
6883 else
6884 ret = 0;
6885 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6886 if (xmlXPathIsInf(arg2->floatval) == -1)
6887 ret = 1;
6888 else
6889 ret = 0;
6890 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6891 if (xmlXPathIsInf(arg1->floatval) == 1)
6892 ret = 1;
6893 else
6894 ret = 0;
6895 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6896 if (xmlXPathIsInf(arg1->floatval) == -1)
6897 ret = 1;
6898 else
6899 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006900 } else {
6901 ret = (arg1->floatval == arg2->floatval);
6902 }
Owen Taylor3473f882001-02-23 17:55:21 +00006903 break;
6904 case XPATH_USERS:
6905 case XPATH_POINT:
6906 case XPATH_RANGE:
6907 case XPATH_LOCATIONSET:
6908 TODO
6909 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006910 case XPATH_NODESET:
6911 case XPATH_XSLT_TREE:
6912 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006913 }
6914 break;
6915 case XPATH_STRING:
6916 switch (arg2->type) {
6917 case XPATH_UNDEFINED:
6918#ifdef DEBUG_EXPR
6919 xmlGenericError(xmlGenericErrorContext,
6920 "Equal: undefined\n");
6921#endif
6922 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006923 case XPATH_BOOLEAN:
6924 if ((arg1->stringval == NULL) ||
6925 (arg1->stringval[0] == 0)) ret = 0;
6926 else
6927 ret = 1;
6928 ret = (arg2->boolval == ret);
6929 break;
6930 case XPATH_STRING:
6931 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6932 break;
6933 case XPATH_NUMBER:
6934 valuePush(ctxt, arg1);
6935 xmlXPathNumberFunction(ctxt, 1);
6936 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006937 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006938 if (xmlXPathIsNaN(arg1->floatval) ||
6939 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006940 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006941 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6942 if (xmlXPathIsInf(arg2->floatval) == 1)
6943 ret = 1;
6944 else
6945 ret = 0;
6946 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6947 if (xmlXPathIsInf(arg2->floatval) == -1)
6948 ret = 1;
6949 else
6950 ret = 0;
6951 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6952 if (xmlXPathIsInf(arg1->floatval) == 1)
6953 ret = 1;
6954 else
6955 ret = 0;
6956 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6957 if (xmlXPathIsInf(arg1->floatval) == -1)
6958 ret = 1;
6959 else
6960 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006961 } else {
6962 ret = (arg1->floatval == arg2->floatval);
6963 }
Owen Taylor3473f882001-02-23 17:55:21 +00006964 break;
6965 case XPATH_USERS:
6966 case XPATH_POINT:
6967 case XPATH_RANGE:
6968 case XPATH_LOCATIONSET:
6969 TODO
6970 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006971 case XPATH_NODESET:
6972 case XPATH_XSLT_TREE:
6973 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006974 }
6975 break;
6976 case XPATH_USERS:
6977 case XPATH_POINT:
6978 case XPATH_RANGE:
6979 case XPATH_LOCATIONSET:
6980 TODO
6981 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006982 case XPATH_NODESET:
6983 case XPATH_XSLT_TREE:
6984 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006985 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006986 xmlXPathReleaseObject(ctxt->context, arg1);
6987 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006988 return(ret);
6989}
6990
William M. Brack0c022ad2002-07-12 00:56:01 +00006991/**
6992 * xmlXPathEqualValues:
6993 * @ctxt: the XPath Parser context
6994 *
6995 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6996 *
6997 * Returns 0 or 1 depending on the results of the test.
6998 */
6999int
7000xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7001 xmlXPathObjectPtr arg1, arg2, argtmp;
7002 int ret = 0;
7003
Daniel Veillard6128c012004-11-08 17:16:15 +00007004 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007005 arg2 = valuePop(ctxt);
7006 arg1 = valuePop(ctxt);
7007 if ((arg1 == NULL) || (arg2 == NULL)) {
7008 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007009 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007010 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007011 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007012 XP_ERROR0(XPATH_INVALID_OPERAND);
7013 }
7014
7015 if (arg1 == arg2) {
7016#ifdef DEBUG_EXPR
7017 xmlGenericError(xmlGenericErrorContext,
7018 "Equal: by pointer\n");
7019#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007020 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007021 return(1);
7022 }
7023
7024 /*
7025 *If either argument is a nodeset, it's a 'special case'
7026 */
7027 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7028 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7029 /*
7030 *Hack it to assure arg1 is the nodeset
7031 */
7032 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7033 argtmp = arg2;
7034 arg2 = arg1;
7035 arg1 = argtmp;
7036 }
7037 switch (arg2->type) {
7038 case XPATH_UNDEFINED:
7039#ifdef DEBUG_EXPR
7040 xmlGenericError(xmlGenericErrorContext,
7041 "Equal: undefined\n");
7042#endif
7043 break;
7044 case XPATH_NODESET:
7045 case XPATH_XSLT_TREE:
7046 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7047 break;
7048 case XPATH_BOOLEAN:
7049 if ((arg1->nodesetval == NULL) ||
7050 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7051 else
7052 ret = 1;
7053 ret = (ret == arg2->boolval);
7054 break;
7055 case XPATH_NUMBER:
7056 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7057 break;
7058 case XPATH_STRING:
7059 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7060 break;
7061 case XPATH_USERS:
7062 case XPATH_POINT:
7063 case XPATH_RANGE:
7064 case XPATH_LOCATIONSET:
7065 TODO
7066 break;
7067 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007068 xmlXPathReleaseObject(ctxt->context, arg1);
7069 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007070 return(ret);
7071 }
7072
7073 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7074}
7075
7076/**
7077 * xmlXPathNotEqualValues:
7078 * @ctxt: the XPath Parser context
7079 *
7080 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7081 *
7082 * Returns 0 or 1 depending on the results of the test.
7083 */
7084int
7085xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7086 xmlXPathObjectPtr arg1, arg2, argtmp;
7087 int ret = 0;
7088
Daniel Veillard6128c012004-11-08 17:16:15 +00007089 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007090 arg2 = valuePop(ctxt);
7091 arg1 = valuePop(ctxt);
7092 if ((arg1 == NULL) || (arg2 == NULL)) {
7093 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007094 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007095 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007096 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007097 XP_ERROR0(XPATH_INVALID_OPERAND);
7098 }
7099
7100 if (arg1 == arg2) {
7101#ifdef DEBUG_EXPR
7102 xmlGenericError(xmlGenericErrorContext,
7103 "NotEqual: by pointer\n");
7104#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007105 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007106 return(0);
7107 }
7108
7109 /*
7110 *If either argument is a nodeset, it's a 'special case'
7111 */
7112 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7113 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7114 /*
7115 *Hack it to assure arg1 is the nodeset
7116 */
7117 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7118 argtmp = arg2;
7119 arg2 = arg1;
7120 arg1 = argtmp;
7121 }
7122 switch (arg2->type) {
7123 case XPATH_UNDEFINED:
7124#ifdef DEBUG_EXPR
7125 xmlGenericError(xmlGenericErrorContext,
7126 "NotEqual: undefined\n");
7127#endif
7128 break;
7129 case XPATH_NODESET:
7130 case XPATH_XSLT_TREE:
7131 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7132 break;
7133 case XPATH_BOOLEAN:
7134 if ((arg1->nodesetval == NULL) ||
7135 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7136 else
7137 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007138 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007139 break;
7140 case XPATH_NUMBER:
7141 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7142 break;
7143 case XPATH_STRING:
7144 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7145 break;
7146 case XPATH_USERS:
7147 case XPATH_POINT:
7148 case XPATH_RANGE:
7149 case XPATH_LOCATIONSET:
7150 TODO
7151 break;
7152 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007153 xmlXPathReleaseObject(ctxt->context, arg1);
7154 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007155 return(ret);
7156 }
7157
7158 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7159}
Owen Taylor3473f882001-02-23 17:55:21 +00007160
7161/**
7162 * xmlXPathCompareValues:
7163 * @ctxt: the XPath Parser context
7164 * @inf: less than (1) or greater than (0)
7165 * @strict: is the comparison strict
7166 *
7167 * Implement the compare operation on XPath objects:
7168 * @arg1 < @arg2 (1, 1, ...
7169 * @arg1 <= @arg2 (1, 0, ...
7170 * @arg1 > @arg2 (0, 1, ...
7171 * @arg1 >= @arg2 (0, 0, ...
7172 *
7173 * When neither object to be compared is a node-set and the operator is
7174 * <=, <, >=, >, then the objects are compared by converted both objects
7175 * to numbers and comparing the numbers according to IEEE 754. The <
7176 * comparison will be true if and only if the first number is less than the
7177 * second number. The <= comparison will be true if and only if the first
7178 * number is less than or equal to the second number. The > comparison
7179 * will be true if and only if the first number is greater than the second
7180 * number. The >= comparison will be true if and only if the first number
7181 * is greater than or equal to the second number.
7182 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007183 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007184 */
7185int
7186xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007187 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007188 xmlXPathObjectPtr arg1, arg2;
7189
Daniel Veillard6128c012004-11-08 17:16:15 +00007190 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007191 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007192 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007193 if ((arg1 == NULL) || (arg2 == NULL)) {
7194 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007195 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007196 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007197 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007198 XP_ERROR0(XPATH_INVALID_OPERAND);
7199 }
7200
William M. Brack0c022ad2002-07-12 00:56:01 +00007201 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7202 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007203 /*
7204 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7205 * are not freed from within this routine; they will be freed from the
7206 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7207 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007208 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7209 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007210 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007211 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007212 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007213 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7214 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007215 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007216 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7217 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007218 }
7219 }
7220 return(ret);
7221 }
7222
7223 if (arg1->type != XPATH_NUMBER) {
7224 valuePush(ctxt, arg1);
7225 xmlXPathNumberFunction(ctxt, 1);
7226 arg1 = valuePop(ctxt);
7227 }
7228 if (arg1->type != XPATH_NUMBER) {
7229 xmlXPathFreeObject(arg1);
7230 xmlXPathFreeObject(arg2);
7231 XP_ERROR0(XPATH_INVALID_OPERAND);
7232 }
7233 if (arg2->type != XPATH_NUMBER) {
7234 valuePush(ctxt, arg2);
7235 xmlXPathNumberFunction(ctxt, 1);
7236 arg2 = valuePop(ctxt);
7237 }
7238 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007239 xmlXPathReleaseObject(ctxt->context, arg1);
7240 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007241 XP_ERROR0(XPATH_INVALID_OPERAND);
7242 }
7243 /*
7244 * Add tests for infinity and nan
7245 * => feedback on 3.4 for Inf and NaN
7246 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007247 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007248 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007249 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007250 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007251 arg1i=xmlXPathIsInf(arg1->floatval);
7252 arg2i=xmlXPathIsInf(arg2->floatval);
7253 if (inf && strict) {
7254 if ((arg1i == -1 && arg2i != -1) ||
7255 (arg2i == 1 && arg1i != 1)) {
7256 ret = 1;
7257 } else if (arg1i == 0 && arg2i == 0) {
7258 ret = (arg1->floatval < arg2->floatval);
7259 } else {
7260 ret = 0;
7261 }
7262 }
7263 else if (inf && !strict) {
7264 if (arg1i == -1 || arg2i == 1) {
7265 ret = 1;
7266 } else if (arg1i == 0 && arg2i == 0) {
7267 ret = (arg1->floatval <= arg2->floatval);
7268 } else {
7269 ret = 0;
7270 }
7271 }
7272 else if (!inf && strict) {
7273 if ((arg1i == 1 && arg2i != 1) ||
7274 (arg2i == -1 && arg1i != -1)) {
7275 ret = 1;
7276 } else if (arg1i == 0 && arg2i == 0) {
7277 ret = (arg1->floatval > arg2->floatval);
7278 } else {
7279 ret = 0;
7280 }
7281 }
7282 else if (!inf && !strict) {
7283 if (arg1i == 1 || arg2i == -1) {
7284 ret = 1;
7285 } else if (arg1i == 0 && arg2i == 0) {
7286 ret = (arg1->floatval >= arg2->floatval);
7287 } else {
7288 ret = 0;
7289 }
7290 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007291 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007292 xmlXPathReleaseObject(ctxt->context, arg1);
7293 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007294 return(ret);
7295}
7296
7297/**
7298 * xmlXPathValueFlipSign:
7299 * @ctxt: the XPath Parser context
7300 *
7301 * Implement the unary - operation on an XPath object
7302 * The numeric operators convert their operands to numbers as if
7303 * by calling the number function.
7304 */
7305void
7306xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007307 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007308 CAST_TO_NUMBER;
7309 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007310 if (xmlXPathIsNaN(ctxt->value->floatval))
7311 ctxt->value->floatval=xmlXPathNAN;
7312 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7313 ctxt->value->floatval=xmlXPathNINF;
7314 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7315 ctxt->value->floatval=xmlXPathPINF;
7316 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007317 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7318 ctxt->value->floatval = xmlXPathNZERO;
7319 else
7320 ctxt->value->floatval = 0;
7321 }
7322 else
7323 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007324}
7325
7326/**
7327 * xmlXPathAddValues:
7328 * @ctxt: the XPath Parser context
7329 *
7330 * Implement the add operation on XPath objects:
7331 * The numeric operators convert their operands to numbers as if
7332 * by calling the number function.
7333 */
7334void
7335xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7336 xmlXPathObjectPtr arg;
7337 double val;
7338
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007339 arg = valuePop(ctxt);
7340 if (arg == NULL)
7341 XP_ERROR(XPATH_INVALID_OPERAND);
7342 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007343 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007344 CAST_TO_NUMBER;
7345 CHECK_TYPE(XPATH_NUMBER);
7346 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007347}
7348
7349/**
7350 * xmlXPathSubValues:
7351 * @ctxt: the XPath Parser context
7352 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007353 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007354 * The numeric operators convert their operands to numbers as if
7355 * by calling the number function.
7356 */
7357void
7358xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7359 xmlXPathObjectPtr arg;
7360 double val;
7361
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007362 arg = valuePop(ctxt);
7363 if (arg == NULL)
7364 XP_ERROR(XPATH_INVALID_OPERAND);
7365 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007366 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007367 CAST_TO_NUMBER;
7368 CHECK_TYPE(XPATH_NUMBER);
7369 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007370}
7371
7372/**
7373 * xmlXPathMultValues:
7374 * @ctxt: the XPath Parser context
7375 *
7376 * Implement the multiply operation on XPath objects:
7377 * The numeric operators convert their operands to numbers as if
7378 * by calling the number function.
7379 */
7380void
7381xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7382 xmlXPathObjectPtr arg;
7383 double val;
7384
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007385 arg = valuePop(ctxt);
7386 if (arg == NULL)
7387 XP_ERROR(XPATH_INVALID_OPERAND);
7388 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007389 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007390 CAST_TO_NUMBER;
7391 CHECK_TYPE(XPATH_NUMBER);
7392 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007393}
7394
7395/**
7396 * xmlXPathDivValues:
7397 * @ctxt: the XPath Parser context
7398 *
7399 * Implement the div operation on XPath objects @arg1 / @arg2:
7400 * The numeric operators convert their operands to numbers as if
7401 * by calling the number function.
7402 */
7403void
7404xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7405 xmlXPathObjectPtr arg;
7406 double val;
7407
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007408 arg = valuePop(ctxt);
7409 if (arg == NULL)
7410 XP_ERROR(XPATH_INVALID_OPERAND);
7411 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007412 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007413 CAST_TO_NUMBER;
7414 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007415 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7416 ctxt->value->floatval = xmlXPathNAN;
7417 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007418 if (ctxt->value->floatval == 0)
7419 ctxt->value->floatval = xmlXPathNAN;
7420 else if (ctxt->value->floatval > 0)
7421 ctxt->value->floatval = xmlXPathNINF;
7422 else if (ctxt->value->floatval < 0)
7423 ctxt->value->floatval = xmlXPathPINF;
7424 }
7425 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007426 if (ctxt->value->floatval == 0)
7427 ctxt->value->floatval = xmlXPathNAN;
7428 else if (ctxt->value->floatval > 0)
7429 ctxt->value->floatval = xmlXPathPINF;
7430 else if (ctxt->value->floatval < 0)
7431 ctxt->value->floatval = xmlXPathNINF;
7432 } else
7433 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007434}
7435
7436/**
7437 * xmlXPathModValues:
7438 * @ctxt: the XPath Parser context
7439 *
7440 * Implement the mod operation on XPath objects: @arg1 / @arg2
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7443 */
7444void
7445xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7446 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007447 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007448
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007449 arg = valuePop(ctxt);
7450 if (arg == NULL)
7451 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007452 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007453 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007454 CAST_TO_NUMBER;
7455 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007456 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007457 if (arg2 == 0)
7458 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007459 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007460 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007461 }
Owen Taylor3473f882001-02-23 17:55:21 +00007462}
7463
7464/************************************************************************
7465 * *
7466 * The traversal functions *
7467 * *
7468 ************************************************************************/
7469
Owen Taylor3473f882001-02-23 17:55:21 +00007470/*
7471 * A traversal function enumerates nodes along an axis.
7472 * Initially it must be called with NULL, and it indicates
7473 * termination on the axis by returning NULL.
7474 */
7475typedef xmlNodePtr (*xmlXPathTraversalFunction)
7476 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7477
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007478/*
7479 * xmlXPathTraversalFunctionExt:
7480 * A traversal function enumerates nodes along an axis.
7481 * Initially it must be called with NULL, and it indicates
7482 * termination on the axis by returning NULL.
7483 * The context node of the traversal is specified via @contextNode.
7484 */
7485typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7486 (xmlNodePtr cur, xmlNodePtr contextNode);
7487
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007488/*
7489 * xmlXPathNodeSetMergeFunction:
7490 * Used for merging node sets in xmlXPathCollectAndTest().
7491 */
7492typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7493 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7494
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007495
Owen Taylor3473f882001-02-23 17:55:21 +00007496/**
7497 * xmlXPathNextSelf:
7498 * @ctxt: the XPath Parser context
7499 * @cur: the current node in the traversal
7500 *
7501 * Traversal function for the "self" direction
7502 * The self axis contains just the context node itself
7503 *
7504 * Returns the next element following that axis
7505 */
7506xmlNodePtr
7507xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007508 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007509 if (cur == NULL)
7510 return(ctxt->context->node);
7511 return(NULL);
7512}
7513
7514/**
7515 * xmlXPathNextChild:
7516 * @ctxt: the XPath Parser context
7517 * @cur: the current node in the traversal
7518 *
7519 * Traversal function for the "child" direction
7520 * The child axis contains the children of the context node in document order.
7521 *
7522 * Returns the next element following that axis
7523 */
7524xmlNodePtr
7525xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007526 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007527 if (cur == NULL) {
7528 if (ctxt->context->node == NULL) return(NULL);
7529 switch (ctxt->context->node->type) {
7530 case XML_ELEMENT_NODE:
7531 case XML_TEXT_NODE:
7532 case XML_CDATA_SECTION_NODE:
7533 case XML_ENTITY_REF_NODE:
7534 case XML_ENTITY_NODE:
7535 case XML_PI_NODE:
7536 case XML_COMMENT_NODE:
7537 case XML_NOTATION_NODE:
7538 case XML_DTD_NODE:
7539 return(ctxt->context->node->children);
7540 case XML_DOCUMENT_NODE:
7541 case XML_DOCUMENT_TYPE_NODE:
7542 case XML_DOCUMENT_FRAG_NODE:
7543 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007544#ifdef LIBXML_DOCB_ENABLED
7545 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007546#endif
7547 return(((xmlDocPtr) ctxt->context->node)->children);
7548 case XML_ELEMENT_DECL:
7549 case XML_ATTRIBUTE_DECL:
7550 case XML_ENTITY_DECL:
7551 case XML_ATTRIBUTE_NODE:
7552 case XML_NAMESPACE_DECL:
7553 case XML_XINCLUDE_START:
7554 case XML_XINCLUDE_END:
7555 return(NULL);
7556 }
7557 return(NULL);
7558 }
7559 if ((cur->type == XML_DOCUMENT_NODE) ||
7560 (cur->type == XML_HTML_DOCUMENT_NODE))
7561 return(NULL);
7562 return(cur->next);
7563}
7564
7565/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007566 * xmlXPathNextChildElement:
7567 * @ctxt: the XPath Parser context
7568 * @cur: the current node in the traversal
7569 *
7570 * Traversal function for the "child" direction and nodes of type element.
7571 * The child axis contains the children of the context node in document order.
7572 *
7573 * Returns the next element following that axis
7574 */
7575static xmlNodePtr
7576xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7577 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7578 if (cur == NULL) {
7579 cur = ctxt->context->node;
7580 if (cur == NULL) return(NULL);
7581 /*
7582 * Get the first element child.
7583 */
7584 switch (cur->type) {
7585 case XML_ELEMENT_NODE:
7586 case XML_DOCUMENT_FRAG_NODE:
7587 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7588 case XML_ENTITY_NODE:
7589 cur = cur->children;
7590 if (cur != NULL) {
7591 if (cur->type == XML_ELEMENT_NODE)
7592 return(cur);
7593 do {
7594 cur = cur->next;
7595 } while ((cur != NULL) &&
7596 (cur->type != XML_ELEMENT_NODE));
7597 return(cur);
7598 }
7599 return(NULL);
7600 case XML_DOCUMENT_NODE:
7601 case XML_HTML_DOCUMENT_NODE:
7602#ifdef LIBXML_DOCB_ENABLED
7603 case XML_DOCB_DOCUMENT_NODE:
7604#endif
7605 return(xmlDocGetRootElement((xmlDocPtr) cur));
7606 default:
7607 return(NULL);
7608 }
7609 return(NULL);
7610 }
7611 /*
7612 * Get the next sibling element node.
7613 */
7614 switch (cur->type) {
7615 case XML_ELEMENT_NODE:
7616 case XML_TEXT_NODE:
7617 case XML_ENTITY_REF_NODE:
7618 case XML_ENTITY_NODE:
7619 case XML_CDATA_SECTION_NODE:
7620 case XML_PI_NODE:
7621 case XML_COMMENT_NODE:
7622 case XML_XINCLUDE_END:
7623 break;
7624 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7625 default:
7626 return(NULL);
7627 }
7628 if (cur->next != NULL) {
7629 if (cur->next->type == XML_ELEMENT_NODE)
7630 return(cur->next);
7631 cur = cur->next;
7632 do {
7633 cur = cur->next;
7634 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7635 return(cur);
7636 }
7637 return(NULL);
7638}
7639
7640/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007641 * xmlXPathNextDescendantOrSelfElemParent:
7642 * @ctxt: the XPath Parser context
7643 * @cur: the current node in the traversal
7644 *
7645 * Traversal function for the "descendant-or-self" axis.
7646 * Additionally it returns only nodes which can be parents of
7647 * element nodes.
7648 *
7649 *
7650 * Returns the next element following that axis
7651 */
7652static xmlNodePtr
7653xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7654 xmlNodePtr contextNode)
7655{
7656 if (cur == NULL) {
7657 if (contextNode == NULL)
7658 return(NULL);
7659 switch (contextNode->type) {
7660 case XML_ELEMENT_NODE:
7661 case XML_XINCLUDE_START:
7662 case XML_DOCUMENT_FRAG_NODE:
7663 case XML_DOCUMENT_NODE:
7664#ifdef LIBXML_DOCB_ENABLED
7665 case XML_DOCB_DOCUMENT_NODE:
7666#endif
7667 case XML_HTML_DOCUMENT_NODE:
7668 return(contextNode);
7669 default:
7670 return(NULL);
7671 }
7672 return(NULL);
7673 } else {
7674 xmlNodePtr start = cur;
7675
7676 while (cur != NULL) {
7677 switch (cur->type) {
7678 case XML_ELEMENT_NODE:
7679 /* TODO: OK to have XInclude here? */
7680 case XML_XINCLUDE_START:
7681 case XML_DOCUMENT_FRAG_NODE:
7682 if (cur != start)
7683 return(cur);
7684 if (cur->children != NULL) {
7685 cur = cur->children;
7686 continue;
7687 }
7688 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007689 /* Not sure if we need those here. */
7690 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007691#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007692 case XML_DOCB_DOCUMENT_NODE:
7693#endif
7694 case XML_HTML_DOCUMENT_NODE:
7695 if (cur != start)
7696 return(cur);
7697 return(xmlDocGetRootElement((xmlDocPtr) cur));
7698 default:
7699 break;
7700 }
7701
7702next_sibling:
7703 if ((cur == NULL) || (cur == contextNode))
7704 return(NULL);
7705 if (cur->next != NULL) {
7706 cur = cur->next;
7707 } else {
7708 cur = cur->parent;
7709 goto next_sibling;
7710 }
7711 }
7712 }
7713 return(NULL);
7714}
7715
7716/**
Owen Taylor3473f882001-02-23 17:55:21 +00007717 * xmlXPathNextDescendant:
7718 * @ctxt: the XPath Parser context
7719 * @cur: the current node in the traversal
7720 *
7721 * Traversal function for the "descendant" direction
7722 * the descendant axis contains the descendants of the context node in document
7723 * order; a descendant is a child or a child of a child and so on.
7724 *
7725 * Returns the next element following that axis
7726 */
7727xmlNodePtr
7728xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007729 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007730 if (cur == NULL) {
7731 if (ctxt->context->node == NULL)
7732 return(NULL);
7733 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7734 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7735 return(NULL);
7736
7737 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7738 return(ctxt->context->doc->children);
7739 return(ctxt->context->node->children);
7740 }
7741
Daniel Veillard567e1b42001-08-01 15:53:47 +00007742 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007743 /*
7744 * Do not descend on entities declarations
7745 */
7746 if (cur->children->type != XML_ENTITY_DECL) {
7747 cur = cur->children;
7748 /*
7749 * Skip DTDs
7750 */
7751 if (cur->type != XML_DTD_NODE)
7752 return(cur);
7753 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007754 }
7755
7756 if (cur == ctxt->context->node) return(NULL);
7757
Daniel Veillard68e9e742002-11-16 15:35:11 +00007758 while (cur->next != NULL) {
7759 cur = cur->next;
7760 if ((cur->type != XML_ENTITY_DECL) &&
7761 (cur->type != XML_DTD_NODE))
7762 return(cur);
7763 }
Owen Taylor3473f882001-02-23 17:55:21 +00007764
7765 do {
7766 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007767 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007768 if (cur == ctxt->context->node) return(NULL);
7769 if (cur->next != NULL) {
7770 cur = cur->next;
7771 return(cur);
7772 }
7773 } while (cur != NULL);
7774 return(cur);
7775}
7776
7777/**
7778 * xmlXPathNextDescendantOrSelf:
7779 * @ctxt: the XPath Parser context
7780 * @cur: the current node in the traversal
7781 *
7782 * Traversal function for the "descendant-or-self" direction
7783 * the descendant-or-self axis contains the context node and the descendants
7784 * of the context node in document order; thus the context node is the first
7785 * node on the axis, and the first child of the context node is the second node
7786 * on the axis
7787 *
7788 * Returns the next element following that axis
7789 */
7790xmlNodePtr
7791xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007792 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007793 if (cur == NULL) {
7794 if (ctxt->context->node == NULL)
7795 return(NULL);
7796 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7797 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7798 return(NULL);
7799 return(ctxt->context->node);
7800 }
7801
7802 return(xmlXPathNextDescendant(ctxt, cur));
7803}
7804
7805/**
7806 * xmlXPathNextParent:
7807 * @ctxt: the XPath Parser context
7808 * @cur: the current node in the traversal
7809 *
7810 * Traversal function for the "parent" direction
7811 * The parent axis contains the parent of the context node, if there is one.
7812 *
7813 * Returns the next element following that axis
7814 */
7815xmlNodePtr
7816xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007817 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007818 /*
7819 * the parent of an attribute or namespace node is the element
7820 * to which the attribute or namespace node is attached
7821 * Namespace handling !!!
7822 */
7823 if (cur == NULL) {
7824 if (ctxt->context->node == NULL) return(NULL);
7825 switch (ctxt->context->node->type) {
7826 case XML_ELEMENT_NODE:
7827 case XML_TEXT_NODE:
7828 case XML_CDATA_SECTION_NODE:
7829 case XML_ENTITY_REF_NODE:
7830 case XML_ENTITY_NODE:
7831 case XML_PI_NODE:
7832 case XML_COMMENT_NODE:
7833 case XML_NOTATION_NODE:
7834 case XML_DTD_NODE:
7835 case XML_ELEMENT_DECL:
7836 case XML_ATTRIBUTE_DECL:
7837 case XML_XINCLUDE_START:
7838 case XML_XINCLUDE_END:
7839 case XML_ENTITY_DECL:
7840 if (ctxt->context->node->parent == NULL)
7841 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007842 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007843 ((ctxt->context->node->parent->name[0] == ' ') ||
7844 (xmlStrEqual(ctxt->context->node->parent->name,
7845 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007846 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007847 return(ctxt->context->node->parent);
7848 case XML_ATTRIBUTE_NODE: {
7849 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7850
7851 return(att->parent);
7852 }
7853 case XML_DOCUMENT_NODE:
7854 case XML_DOCUMENT_TYPE_NODE:
7855 case XML_DOCUMENT_FRAG_NODE:
7856 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007857#ifdef LIBXML_DOCB_ENABLED
7858 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007859#endif
7860 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007861 case XML_NAMESPACE_DECL: {
7862 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7863
7864 if ((ns->next != NULL) &&
7865 (ns->next->type != XML_NAMESPACE_DECL))
7866 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007867 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007868 }
Owen Taylor3473f882001-02-23 17:55:21 +00007869 }
7870 }
7871 return(NULL);
7872}
7873
7874/**
7875 * xmlXPathNextAncestor:
7876 * @ctxt: the XPath Parser context
7877 * @cur: the current node in the traversal
7878 *
7879 * Traversal function for the "ancestor" direction
7880 * the ancestor axis contains the ancestors of the context node; the ancestors
7881 * of the context node consist of the parent of context node and the parent's
7882 * parent and so on; the nodes are ordered in reverse document order; thus the
7883 * parent is the first node on the axis, and the parent's parent is the second
7884 * node on the axis
7885 *
7886 * Returns the next element following that axis
7887 */
7888xmlNodePtr
7889xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007890 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007891 /*
7892 * the parent of an attribute or namespace node is the element
7893 * to which the attribute or namespace node is attached
7894 * !!!!!!!!!!!!!
7895 */
7896 if (cur == NULL) {
7897 if (ctxt->context->node == NULL) return(NULL);
7898 switch (ctxt->context->node->type) {
7899 case XML_ELEMENT_NODE:
7900 case XML_TEXT_NODE:
7901 case XML_CDATA_SECTION_NODE:
7902 case XML_ENTITY_REF_NODE:
7903 case XML_ENTITY_NODE:
7904 case XML_PI_NODE:
7905 case XML_COMMENT_NODE:
7906 case XML_DTD_NODE:
7907 case XML_ELEMENT_DECL:
7908 case XML_ATTRIBUTE_DECL:
7909 case XML_ENTITY_DECL:
7910 case XML_NOTATION_NODE:
7911 case XML_XINCLUDE_START:
7912 case XML_XINCLUDE_END:
7913 if (ctxt->context->node->parent == NULL)
7914 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007915 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007916 ((ctxt->context->node->parent->name[0] == ' ') ||
7917 (xmlStrEqual(ctxt->context->node->parent->name,
7918 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007919 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007920 return(ctxt->context->node->parent);
7921 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007922 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007923
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007924 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007925 }
7926 case XML_DOCUMENT_NODE:
7927 case XML_DOCUMENT_TYPE_NODE:
7928 case XML_DOCUMENT_FRAG_NODE:
7929 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007930#ifdef LIBXML_DOCB_ENABLED
7931 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007932#endif
7933 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007934 case XML_NAMESPACE_DECL: {
7935 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7936
7937 if ((ns->next != NULL) &&
7938 (ns->next->type != XML_NAMESPACE_DECL))
7939 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007940 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007941 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007942 }
Owen Taylor3473f882001-02-23 17:55:21 +00007943 }
7944 return(NULL);
7945 }
7946 if (cur == ctxt->context->doc->children)
7947 return((xmlNodePtr) ctxt->context->doc);
7948 if (cur == (xmlNodePtr) ctxt->context->doc)
7949 return(NULL);
7950 switch (cur->type) {
7951 case XML_ELEMENT_NODE:
7952 case XML_TEXT_NODE:
7953 case XML_CDATA_SECTION_NODE:
7954 case XML_ENTITY_REF_NODE:
7955 case XML_ENTITY_NODE:
7956 case XML_PI_NODE:
7957 case XML_COMMENT_NODE:
7958 case XML_NOTATION_NODE:
7959 case XML_DTD_NODE:
7960 case XML_ELEMENT_DECL:
7961 case XML_ATTRIBUTE_DECL:
7962 case XML_ENTITY_DECL:
7963 case XML_XINCLUDE_START:
7964 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007965 if (cur->parent == NULL)
7966 return(NULL);
7967 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007968 ((cur->parent->name[0] == ' ') ||
7969 (xmlStrEqual(cur->parent->name,
7970 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007971 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007972 return(cur->parent);
7973 case XML_ATTRIBUTE_NODE: {
7974 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7975
7976 return(att->parent);
7977 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007978 case XML_NAMESPACE_DECL: {
7979 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7980
7981 if ((ns->next != NULL) &&
7982 (ns->next->type != XML_NAMESPACE_DECL))
7983 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007984 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007985 return(NULL);
7986 }
Owen Taylor3473f882001-02-23 17:55:21 +00007987 case XML_DOCUMENT_NODE:
7988 case XML_DOCUMENT_TYPE_NODE:
7989 case XML_DOCUMENT_FRAG_NODE:
7990 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007991#ifdef LIBXML_DOCB_ENABLED
7992 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007993#endif
7994 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007995 }
7996 return(NULL);
7997}
7998
7999/**
8000 * xmlXPathNextAncestorOrSelf:
8001 * @ctxt: the XPath Parser context
8002 * @cur: the current node in the traversal
8003 *
8004 * Traversal function for the "ancestor-or-self" direction
8005 * he ancestor-or-self axis contains the context node and ancestors of
8006 * the context node in reverse document order; thus the context node is
8007 * the first node on the axis, and the context node's parent the second;
8008 * parent here is defined the same as with the parent axis.
8009 *
8010 * Returns the next element following that axis
8011 */
8012xmlNodePtr
8013xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008014 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008015 if (cur == NULL)
8016 return(ctxt->context->node);
8017 return(xmlXPathNextAncestor(ctxt, cur));
8018}
8019
8020/**
8021 * xmlXPathNextFollowingSibling:
8022 * @ctxt: the XPath Parser context
8023 * @cur: the current node in the traversal
8024 *
8025 * Traversal function for the "following-sibling" direction
8026 * The following-sibling axis contains the following siblings of the context
8027 * node in document order.
8028 *
8029 * Returns the next element following that axis
8030 */
8031xmlNodePtr
8032xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008034 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8035 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8036 return(NULL);
8037 if (cur == (xmlNodePtr) ctxt->context->doc)
8038 return(NULL);
8039 if (cur == NULL)
8040 return(ctxt->context->node->next);
8041 return(cur->next);
8042}
8043
8044/**
8045 * xmlXPathNextPrecedingSibling:
8046 * @ctxt: the XPath Parser context
8047 * @cur: the current node in the traversal
8048 *
8049 * Traversal function for the "preceding-sibling" direction
8050 * The preceding-sibling axis contains the preceding siblings of the context
8051 * node in reverse document order; the first preceding sibling is first on the
8052 * axis; the sibling preceding that node is the second on the axis and so on.
8053 *
8054 * Returns the next element following that axis
8055 */
8056xmlNodePtr
8057xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008058 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008059 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8060 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8061 return(NULL);
8062 if (cur == (xmlNodePtr) ctxt->context->doc)
8063 return(NULL);
8064 if (cur == NULL)
8065 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008066 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8067 cur = cur->prev;
8068 if (cur == NULL)
8069 return(ctxt->context->node->prev);
8070 }
Owen Taylor3473f882001-02-23 17:55:21 +00008071 return(cur->prev);
8072}
8073
8074/**
8075 * xmlXPathNextFollowing:
8076 * @ctxt: the XPath Parser context
8077 * @cur: the current node in the traversal
8078 *
8079 * Traversal function for the "following" direction
8080 * The following axis contains all nodes in the same document as the context
8081 * node that are after the context node in document order, excluding any
8082 * descendants and excluding attribute nodes and namespace nodes; the nodes
8083 * are ordered in document order
8084 *
8085 * Returns the next element following that axis
8086 */
8087xmlNodePtr
8088xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008089 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008090 if (cur != NULL && cur->children != NULL)
8091 return cur->children ;
8092 if (cur == NULL) cur = ctxt->context->node;
8093 if (cur == NULL) return(NULL) ; /* ERROR */
8094 if (cur->next != NULL) return(cur->next) ;
8095 do {
8096 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008097 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008098 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8099 if (cur->next != NULL) return(cur->next);
8100 } while (cur != NULL);
8101 return(cur);
8102}
8103
8104/*
8105 * xmlXPathIsAncestor:
8106 * @ancestor: the ancestor node
8107 * @node: the current node
8108 *
8109 * Check that @ancestor is a @node's ancestor
8110 *
8111 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8112 */
8113static int
8114xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8115 if ((ancestor == NULL) || (node == NULL)) return(0);
8116 /* nodes need to be in the same document */
8117 if (ancestor->doc != node->doc) return(0);
8118 /* avoid searching if ancestor or node is the root node */
8119 if (ancestor == (xmlNodePtr) node->doc) return(1);
8120 if (node == (xmlNodePtr) ancestor->doc) return(0);
8121 while (node->parent != NULL) {
8122 if (node->parent == ancestor)
8123 return(1);
8124 node = node->parent;
8125 }
8126 return(0);
8127}
8128
8129/**
8130 * xmlXPathNextPreceding:
8131 * @ctxt: the XPath Parser context
8132 * @cur: the current node in the traversal
8133 *
8134 * Traversal function for the "preceding" direction
8135 * the preceding axis contains all nodes in the same document as the context
8136 * node that are before the context node in document order, excluding any
8137 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8138 * ordered in reverse document order
8139 *
8140 * Returns the next element following that axis
8141 */
8142xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008143xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8144{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008145 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008146 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008147 cur = ctxt->context->node;
8148 if (cur == NULL)
8149 return (NULL);
8150 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8151 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008152 do {
8153 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008154 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8155 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008156 }
8157
8158 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008159 if (cur == NULL)
8160 return (NULL);
8161 if (cur == ctxt->context->doc->children)
8162 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008163 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008164 return (cur);
8165}
8166
8167/**
8168 * xmlXPathNextPrecedingInternal:
8169 * @ctxt: the XPath Parser context
8170 * @cur: the current node in the traversal
8171 *
8172 * Traversal function for the "preceding" direction
8173 * the preceding axis contains all nodes in the same document as the context
8174 * node that are before the context node in document order, excluding any
8175 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8176 * ordered in reverse document order
8177 * This is a faster implementation but internal only since it requires a
8178 * state kept in the parser context: ctxt->ancestor.
8179 *
8180 * Returns the next element following that axis
8181 */
8182static xmlNodePtr
8183xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8184 xmlNodePtr cur)
8185{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008186 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008187 if (cur == NULL) {
8188 cur = ctxt->context->node;
8189 if (cur == NULL)
8190 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008191 if (cur->type == XML_NAMESPACE_DECL)
8192 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008193 ctxt->ancestor = cur->parent;
8194 }
8195 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8196 cur = cur->prev;
8197 while (cur->prev == NULL) {
8198 cur = cur->parent;
8199 if (cur == NULL)
8200 return (NULL);
8201 if (cur == ctxt->context->doc->children)
8202 return (NULL);
8203 if (cur != ctxt->ancestor)
8204 return (cur);
8205 ctxt->ancestor = cur->parent;
8206 }
8207 cur = cur->prev;
8208 while (cur->last != NULL)
8209 cur = cur->last;
8210 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008211}
8212
8213/**
8214 * xmlXPathNextNamespace:
8215 * @ctxt: the XPath Parser context
8216 * @cur: the current attribute in the traversal
8217 *
8218 * Traversal function for the "namespace" direction
8219 * the namespace axis contains the namespace nodes of the context node;
8220 * the order of nodes on this axis is implementation-defined; the axis will
8221 * be empty unless the context node is an element
8222 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008223 * We keep the XML namespace node at the end of the list.
8224 *
Owen Taylor3473f882001-02-23 17:55:21 +00008225 * Returns the next element following that axis
8226 */
8227xmlNodePtr
8228xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008229 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008230 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008231 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008232 if (ctxt->context->tmpNsList != NULL)
8233 xmlFree(ctxt->context->tmpNsList);
8234 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008235 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008236 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008237 if (ctxt->context->tmpNsList != NULL) {
8238 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8239 ctxt->context->tmpNsNr++;
8240 }
8241 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008242 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008243 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008244 if (ctxt->context->tmpNsNr > 0) {
8245 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8246 } else {
8247 if (ctxt->context->tmpNsList != NULL)
8248 xmlFree(ctxt->context->tmpNsList);
8249 ctxt->context->tmpNsList = NULL;
8250 return(NULL);
8251 }
Owen Taylor3473f882001-02-23 17:55:21 +00008252}
8253
8254/**
8255 * xmlXPathNextAttribute:
8256 * @ctxt: the XPath Parser context
8257 * @cur: the current attribute in the traversal
8258 *
8259 * Traversal function for the "attribute" direction
8260 * TODO: support DTD inherited default attributes
8261 *
8262 * Returns the next element following that axis
8263 */
8264xmlNodePtr
8265xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008266 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008267 if (ctxt->context->node == NULL)
8268 return(NULL);
8269 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8270 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 if (cur == NULL) {
8272 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8273 return(NULL);
8274 return((xmlNodePtr)ctxt->context->node->properties);
8275 }
8276 return((xmlNodePtr)cur->next);
8277}
8278
8279/************************************************************************
8280 * *
8281 * NodeTest Functions *
8282 * *
8283 ************************************************************************/
8284
Owen Taylor3473f882001-02-23 17:55:21 +00008285#define IS_FUNCTION 200
8286
Owen Taylor3473f882001-02-23 17:55:21 +00008287
8288/************************************************************************
8289 * *
8290 * Implicit tree core function library *
8291 * *
8292 ************************************************************************/
8293
8294/**
8295 * xmlXPathRoot:
8296 * @ctxt: the XPath Parser context
8297 *
8298 * Initialize the context to the root of the document
8299 */
8300void
8301xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008302 if ((ctxt == NULL) || (ctxt->context == NULL))
8303 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008304 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008305 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8306 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008307}
8308
8309/************************************************************************
8310 * *
8311 * The explicit core function library *
8312 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8313 * *
8314 ************************************************************************/
8315
8316
8317/**
8318 * xmlXPathLastFunction:
8319 * @ctxt: the XPath Parser context
8320 * @nargs: the number of arguments
8321 *
8322 * Implement the last() XPath function
8323 * number last()
8324 * The last function returns the number of nodes in the context node list.
8325 */
8326void
8327xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8328 CHECK_ARITY(0);
8329 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008330 valuePush(ctxt,
8331 xmlXPathCacheNewFloat(ctxt->context,
8332 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008333#ifdef DEBUG_EXPR
8334 xmlGenericError(xmlGenericErrorContext,
8335 "last() : %d\n", ctxt->context->contextSize);
8336#endif
8337 } else {
8338 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8339 }
8340}
8341
8342/**
8343 * xmlXPathPositionFunction:
8344 * @ctxt: the XPath Parser context
8345 * @nargs: the number of arguments
8346 *
8347 * Implement the position() XPath function
8348 * number position()
8349 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008350 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008351 * will be equal to last().
8352 */
8353void
8354xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8355 CHECK_ARITY(0);
8356 if (ctxt->context->proximityPosition >= 0) {
8357 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008358 xmlXPathCacheNewFloat(ctxt->context,
8359 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008360#ifdef DEBUG_EXPR
8361 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8362 ctxt->context->proximityPosition);
8363#endif
8364 } else {
8365 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8366 }
8367}
8368
8369/**
8370 * xmlXPathCountFunction:
8371 * @ctxt: the XPath Parser context
8372 * @nargs: the number of arguments
8373 *
8374 * Implement the count() XPath function
8375 * number count(node-set)
8376 */
8377void
8378xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8379 xmlXPathObjectPtr cur;
8380
8381 CHECK_ARITY(1);
8382 if ((ctxt->value == NULL) ||
8383 ((ctxt->value->type != XPATH_NODESET) &&
8384 (ctxt->value->type != XPATH_XSLT_TREE)))
8385 XP_ERROR(XPATH_INVALID_TYPE);
8386 cur = valuePop(ctxt);
8387
Daniel Veillard911f49a2001-04-07 15:39:35 +00008388 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008389 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008390 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008391 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8392 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008393 } else {
8394 if ((cur->nodesetval->nodeNr != 1) ||
8395 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008396 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008397 } else {
8398 xmlNodePtr tmp;
8399 int i = 0;
8400
8401 tmp = cur->nodesetval->nodeTab[0];
8402 if (tmp != NULL) {
8403 tmp = tmp->children;
8404 while (tmp != NULL) {
8405 tmp = tmp->next;
8406 i++;
8407 }
8408 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008409 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008410 }
8411 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008412 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008413}
8414
8415/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008416 * xmlXPathGetElementsByIds:
8417 * @doc: the document
8418 * @ids: a whitespace separated list of IDs
8419 *
8420 * Selects elements by their unique ID.
8421 *
8422 * Returns a node-set of selected elements.
8423 */
8424static xmlNodeSetPtr
8425xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8426 xmlNodeSetPtr ret;
8427 const xmlChar *cur = ids;
8428 xmlChar *ID;
8429 xmlAttrPtr attr;
8430 xmlNodePtr elem = NULL;
8431
Daniel Veillard7a985a12003-07-06 17:57:42 +00008432 if (ids == NULL) return(NULL);
8433
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008434 ret = xmlXPathNodeSetCreate(NULL);
8435
William M. Brack76e95df2003-10-18 16:20:14 +00008436 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008437 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008438 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008439 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008440
8441 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008442 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008443 /*
8444 * We used to check the fact that the value passed
8445 * was an NCName, but this generated much troubles for
8446 * me and Aleksey Sanin, people blatantly violated that
8447 * constaint, like Visa3D spec.
8448 * if (xmlValidateNCName(ID, 1) == 0)
8449 */
8450 attr = xmlGetID(doc, ID);
8451 if (attr != NULL) {
8452 if (attr->type == XML_ATTRIBUTE_NODE)
8453 elem = attr->parent;
8454 else if (attr->type == XML_ELEMENT_NODE)
8455 elem = (xmlNodePtr) attr;
8456 else
8457 elem = NULL;
8458 if (elem != NULL)
8459 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008460 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008461 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008462 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008463
William M. Brack76e95df2003-10-18 16:20:14 +00008464 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008465 ids = cur;
8466 }
8467 return(ret);
8468}
8469
8470/**
Owen Taylor3473f882001-02-23 17:55:21 +00008471 * xmlXPathIdFunction:
8472 * @ctxt: the XPath Parser context
8473 * @nargs: the number of arguments
8474 *
8475 * Implement the id() XPath function
8476 * node-set id(object)
8477 * The id function selects elements by their unique ID
8478 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8479 * then the result is the union of the result of applying id to the
8480 * string value of each of the nodes in the argument node-set. When the
8481 * argument to id is of any other type, the argument is converted to a
8482 * string as if by a call to the string function; the string is split
8483 * into a whitespace-separated list of tokens (whitespace is any sequence
8484 * of characters matching the production S); the result is a node-set
8485 * containing the elements in the same document as the context node that
8486 * have a unique ID equal to any of the tokens in the list.
8487 */
8488void
8489xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008490 xmlChar *tokens;
8491 xmlNodeSetPtr ret;
8492 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008493
8494 CHECK_ARITY(1);
8495 obj = valuePop(ctxt);
8496 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008497 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008498 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008499 int i;
8500
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008501 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008502
Daniel Veillard911f49a2001-04-07 15:39:35 +00008503 if (obj->nodesetval != NULL) {
8504 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008505 tokens =
8506 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8507 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8508 ret = xmlXPathNodeSetMerge(ret, ns);
8509 xmlXPathFreeNodeSet(ns);
8510 if (tokens != NULL)
8511 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008512 }
Owen Taylor3473f882001-02-23 17:55:21 +00008513 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008514 xmlXPathReleaseObject(ctxt->context, obj);
8515 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008516 return;
8517 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008518 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008519 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008520 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8521 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008522 return;
8523}
8524
8525/**
8526 * xmlXPathLocalNameFunction:
8527 * @ctxt: the XPath Parser context
8528 * @nargs: the number of arguments
8529 *
8530 * Implement the local-name() XPath function
8531 * string local-name(node-set?)
8532 * The local-name function returns a string containing the local part
8533 * of the name of the node in the argument node-set that is first in
8534 * document order. If the node-set is empty or the first node has no
8535 * name, an empty string is returned. If the argument is omitted it
8536 * defaults to the context node.
8537 */
8538void
8539xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8540 xmlXPathObjectPtr cur;
8541
Daniel Veillarda82b1822004-11-08 16:24:57 +00008542 if (ctxt == NULL) return;
8543
Owen Taylor3473f882001-02-23 17:55:21 +00008544 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008545 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8546 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008547 nargs = 1;
8548 }
8549
8550 CHECK_ARITY(1);
8551 if ((ctxt->value == NULL) ||
8552 ((ctxt->value->type != XPATH_NODESET) &&
8553 (ctxt->value->type != XPATH_XSLT_TREE)))
8554 XP_ERROR(XPATH_INVALID_TYPE);
8555 cur = valuePop(ctxt);
8556
Daniel Veillard911f49a2001-04-07 15:39:35 +00008557 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008558 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008559 } else {
8560 int i = 0; /* Should be first in document order !!!!! */
8561 switch (cur->nodesetval->nodeTab[i]->type) {
8562 case XML_ELEMENT_NODE:
8563 case XML_ATTRIBUTE_NODE:
8564 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008565 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008566 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008567 else
8568 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008569 xmlXPathCacheNewString(ctxt->context,
8570 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008571 break;
8572 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008573 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008574 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8575 break;
8576 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008577 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008578 }
8579 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008580 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008581}
8582
8583/**
8584 * xmlXPathNamespaceURIFunction:
8585 * @ctxt: the XPath Parser context
8586 * @nargs: the number of arguments
8587 *
8588 * Implement the namespace-uri() XPath function
8589 * string namespace-uri(node-set?)
8590 * The namespace-uri function returns a string containing the
8591 * namespace URI of the expanded name of the node in the argument
8592 * node-set that is first in document order. If the node-set is empty,
8593 * the first node has no name, or the expanded name has no namespace
8594 * URI, an empty string is returned. If the argument is omitted it
8595 * defaults to the context node.
8596 */
8597void
8598xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8599 xmlXPathObjectPtr cur;
8600
Daniel Veillarda82b1822004-11-08 16:24:57 +00008601 if (ctxt == NULL) return;
8602
Owen Taylor3473f882001-02-23 17:55:21 +00008603 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008604 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8605 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008606 nargs = 1;
8607 }
8608 CHECK_ARITY(1);
8609 if ((ctxt->value == NULL) ||
8610 ((ctxt->value->type != XPATH_NODESET) &&
8611 (ctxt->value->type != XPATH_XSLT_TREE)))
8612 XP_ERROR(XPATH_INVALID_TYPE);
8613 cur = valuePop(ctxt);
8614
Daniel Veillard911f49a2001-04-07 15:39:35 +00008615 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008616 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008617 } else {
8618 int i = 0; /* Should be first in document order !!!!! */
8619 switch (cur->nodesetval->nodeTab[i]->type) {
8620 case XML_ELEMENT_NODE:
8621 case XML_ATTRIBUTE_NODE:
8622 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008623 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008624 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008625 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008626 cur->nodesetval->nodeTab[i]->ns->href));
8627 break;
8628 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008629 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008630 }
8631 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008632 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008633}
8634
8635/**
8636 * xmlXPathNameFunction:
8637 * @ctxt: the XPath Parser context
8638 * @nargs: the number of arguments
8639 *
8640 * Implement the name() XPath function
8641 * string name(node-set?)
8642 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008643 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008644 * order. The QName must represent the name with respect to the namespace
8645 * declarations in effect on the node whose name is being represented.
8646 * Typically, this will be the form in which the name occurred in the XML
8647 * source. This need not be the case if there are namespace declarations
8648 * in effect on the node that associate multiple prefixes with the same
8649 * namespace. However, an implementation may include information about
8650 * the original prefix in its representation of nodes; in this case, an
8651 * implementation can ensure that the returned string is always the same
8652 * as the QName used in the XML source. If the argument it omitted it
8653 * defaults to the context node.
8654 * Libxml keep the original prefix so the "real qualified name" used is
8655 * returned.
8656 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008657static void
Daniel Veillard04383752001-07-08 14:27:15 +00008658xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8659{
Owen Taylor3473f882001-02-23 17:55:21 +00008660 xmlXPathObjectPtr cur;
8661
8662 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008663 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8664 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008665 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008666 }
8667
8668 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008669 if ((ctxt->value == NULL) ||
8670 ((ctxt->value->type != XPATH_NODESET) &&
8671 (ctxt->value->type != XPATH_XSLT_TREE)))
8672 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008673 cur = valuePop(ctxt);
8674
Daniel Veillard911f49a2001-04-07 15:39:35 +00008675 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008676 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008677 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008678 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008679
Daniel Veillard04383752001-07-08 14:27:15 +00008680 switch (cur->nodesetval->nodeTab[i]->type) {
8681 case XML_ELEMENT_NODE:
8682 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008683 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008684 valuePush(ctxt,
8685 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008686 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8687 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008688 valuePush(ctxt,
8689 xmlXPathCacheNewString(ctxt->context,
8690 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008691 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008692 xmlChar *fullname;
8693
8694 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8695 cur->nodesetval->nodeTab[i]->ns->prefix,
8696 NULL, 0);
8697 if (fullname == cur->nodesetval->nodeTab[i]->name)
8698 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8699 if (fullname == NULL) {
8700 XP_ERROR(XPATH_MEMORY_ERROR);
8701 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheWrapString(
8703 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008704 }
8705 break;
8706 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008707 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8708 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008709 xmlXPathLocalNameFunction(ctxt, 1);
8710 }
Owen Taylor3473f882001-02-23 17:55:21 +00008711 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008712 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008713}
8714
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008715
8716/**
Owen Taylor3473f882001-02-23 17:55:21 +00008717 * xmlXPathStringFunction:
8718 * @ctxt: the XPath Parser context
8719 * @nargs: the number of arguments
8720 *
8721 * Implement the string() XPath function
8722 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008723 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008724 * - A node-set is converted to a string by returning the value of
8725 * the node in the node-set that is first in document order.
8726 * If the node-set is empty, an empty string is returned.
8727 * - A number is converted to a string as follows
8728 * + NaN is converted to the string NaN
8729 * + positive zero is converted to the string 0
8730 * + negative zero is converted to the string 0
8731 * + positive infinity is converted to the string Infinity
8732 * + negative infinity is converted to the string -Infinity
8733 * + if the number is an integer, the number is represented in
8734 * decimal form as a Number with no decimal point and no leading
8735 * zeros, preceded by a minus sign (-) if the number is negative
8736 * + otherwise, the number is represented in decimal form as a
8737 * Number including a decimal point with at least one digit
8738 * before the decimal point and at least one digit after the
8739 * decimal point, preceded by a minus sign (-) if the number
8740 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008741 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008742 * before the decimal point; beyond the one required digit
8743 * after the decimal point there must be as many, but only as
8744 * many, more digits as are needed to uniquely distinguish the
8745 * number from all other IEEE 754 numeric values.
8746 * - The boolean false value is converted to the string false.
8747 * The boolean true value is converted to the string true.
8748 *
8749 * If the argument is omitted, it defaults to a node-set with the
8750 * context node as its only member.
8751 */
8752void
8753xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8754 xmlXPathObjectPtr cur;
8755
Daniel Veillarda82b1822004-11-08 16:24:57 +00008756 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008757 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008758 valuePush(ctxt,
8759 xmlXPathCacheWrapString(ctxt->context,
8760 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008761 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008762 }
8763
8764 CHECK_ARITY(1);
8765 cur = valuePop(ctxt);
8766 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008767 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008768}
8769
8770/**
8771 * xmlXPathStringLengthFunction:
8772 * @ctxt: the XPath Parser context
8773 * @nargs: the number of arguments
8774 *
8775 * Implement the string-length() XPath function
8776 * number string-length(string?)
8777 * The string-length returns the number of characters in the string
8778 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8779 * the context node converted to a string, in other words the value
8780 * of the context node.
8781 */
8782void
8783xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8784 xmlXPathObjectPtr cur;
8785
8786 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008787 if ((ctxt == NULL) || (ctxt->context == NULL))
8788 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008789 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008791 } else {
8792 xmlChar *content;
8793
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008794 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008795 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8796 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008797 xmlFree(content);
8798 }
8799 return;
8800 }
8801 CHECK_ARITY(1);
8802 CAST_TO_STRING;
8803 CHECK_TYPE(XPATH_STRING);
8804 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008805 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8806 xmlUTF8Strlen(cur->stringval)));
8807 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008808}
8809
8810/**
8811 * xmlXPathConcatFunction:
8812 * @ctxt: the XPath Parser context
8813 * @nargs: the number of arguments
8814 *
8815 * Implement the concat() XPath function
8816 * string concat(string, string, string*)
8817 * The concat function returns the concatenation of its arguments.
8818 */
8819void
8820xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8821 xmlXPathObjectPtr cur, newobj;
8822 xmlChar *tmp;
8823
Daniel Veillarda82b1822004-11-08 16:24:57 +00008824 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008825 if (nargs < 2) {
8826 CHECK_ARITY(2);
8827 }
8828
8829 CAST_TO_STRING;
8830 cur = valuePop(ctxt);
8831 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008832 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008833 return;
8834 }
8835 nargs--;
8836
8837 while (nargs > 0) {
8838 CAST_TO_STRING;
8839 newobj = valuePop(ctxt);
8840 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008841 xmlXPathReleaseObject(ctxt->context, newobj);
8842 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008843 XP_ERROR(XPATH_INVALID_TYPE);
8844 }
8845 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8846 newobj->stringval = cur->stringval;
8847 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008848 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008849 nargs--;
8850 }
8851 valuePush(ctxt, cur);
8852}
8853
8854/**
8855 * xmlXPathContainsFunction:
8856 * @ctxt: the XPath Parser context
8857 * @nargs: the number of arguments
8858 *
8859 * Implement the contains() XPath function
8860 * boolean contains(string, string)
8861 * The contains function returns true if the first argument string
8862 * contains the second argument string, and otherwise returns false.
8863 */
8864void
8865xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8866 xmlXPathObjectPtr hay, needle;
8867
8868 CHECK_ARITY(2);
8869 CAST_TO_STRING;
8870 CHECK_TYPE(XPATH_STRING);
8871 needle = valuePop(ctxt);
8872 CAST_TO_STRING;
8873 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008874
Owen Taylor3473f882001-02-23 17:55:21 +00008875 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008876 xmlXPathReleaseObject(ctxt->context, hay);
8877 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008878 XP_ERROR(XPATH_INVALID_TYPE);
8879 }
8880 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008881 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008882 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008883 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8884 xmlXPathReleaseObject(ctxt->context, hay);
8885 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008886}
8887
8888/**
8889 * xmlXPathStartsWithFunction:
8890 * @ctxt: the XPath Parser context
8891 * @nargs: the number of arguments
8892 *
8893 * Implement the starts-with() XPath function
8894 * boolean starts-with(string, string)
8895 * The starts-with function returns true if the first argument string
8896 * starts with the second argument string, and otherwise returns false.
8897 */
8898void
8899xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900 xmlXPathObjectPtr hay, needle;
8901 int n;
8902
8903 CHECK_ARITY(2);
8904 CAST_TO_STRING;
8905 CHECK_TYPE(XPATH_STRING);
8906 needle = valuePop(ctxt);
8907 CAST_TO_STRING;
8908 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008909
Owen Taylor3473f882001-02-23 17:55:21 +00008910 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008911 xmlXPathReleaseObject(ctxt->context, hay);
8912 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008913 XP_ERROR(XPATH_INVALID_TYPE);
8914 }
8915 n = xmlStrlen(needle->stringval);
8916 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008917 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008918 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008919 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8920 xmlXPathReleaseObject(ctxt->context, hay);
8921 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008922}
8923
8924/**
8925 * xmlXPathSubstringFunction:
8926 * @ctxt: the XPath Parser context
8927 * @nargs: the number of arguments
8928 *
8929 * Implement the substring() XPath function
8930 * string substring(string, number, number?)
8931 * The substring function returns the substring of the first argument
8932 * starting at the position specified in the second argument with
8933 * length specified in the third argument. For example,
8934 * substring("12345",2,3) returns "234". If the third argument is not
8935 * specified, it returns the substring starting at the position specified
8936 * in the second argument and continuing to the end of the string. For
8937 * example, substring("12345",2) returns "2345". More precisely, each
8938 * character in the string (see [3.6 Strings]) is considered to have a
8939 * numeric position: the position of the first character is 1, the position
8940 * of the second character is 2 and so on. The returned substring contains
8941 * those characters for which the position of the character is greater than
8942 * or equal to the second argument and, if the third argument is specified,
8943 * less than the sum of the second and third arguments; the comparisons
8944 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8945 * - substring("12345", 1.5, 2.6) returns "234"
8946 * - substring("12345", 0, 3) returns "12"
8947 * - substring("12345", 0 div 0, 3) returns ""
8948 * - substring("12345", 1, 0 div 0) returns ""
8949 * - substring("12345", -42, 1 div 0) returns "12345"
8950 * - substring("12345", -1 div 0, 1 div 0) returns ""
8951 */
8952void
8953xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8954 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008955 double le=0, in;
8956 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008957 xmlChar *ret;
8958
Owen Taylor3473f882001-02-23 17:55:21 +00008959 if (nargs < 2) {
8960 CHECK_ARITY(2);
8961 }
8962 if (nargs > 3) {
8963 CHECK_ARITY(3);
8964 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008965 /*
8966 * take care of possible last (position) argument
8967 */
Owen Taylor3473f882001-02-23 17:55:21 +00008968 if (nargs == 3) {
8969 CAST_TO_NUMBER;
8970 CHECK_TYPE(XPATH_NUMBER);
8971 len = valuePop(ctxt);
8972 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008973 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008974 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008975
Owen Taylor3473f882001-02-23 17:55:21 +00008976 CAST_TO_NUMBER;
8977 CHECK_TYPE(XPATH_NUMBER);
8978 start = valuePop(ctxt);
8979 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008980 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008981 CAST_TO_STRING;
8982 CHECK_TYPE(XPATH_STRING);
8983 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008984 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008985
Daniel Veillard97ac1312001-05-30 19:14:17 +00008986 /*
8987 * If last pos not present, calculate last position
8988 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008989 if (nargs != 3) {
8990 le = (double)m;
8991 if (in < 1.0)
8992 in = 1.0;
8993 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008994
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008995 /* Need to check for the special cases where either
8996 * the index is NaN, the length is NaN, or both
8997 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008998 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008999 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009000 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00009001 * To meet the requirements of the spec, the arguments
9002 * must be converted to integer format before
9003 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009004 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009005 * First we go to integer form, rounding up
9006 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009007 */
9008 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009009 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009010
Daniel Veillard9e412302002-06-10 15:59:44 +00009011 if (xmlXPathIsInf(le) == 1) {
9012 l = m;
9013 if (i < 1)
9014 i = 1;
9015 }
9016 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9017 l = 0;
9018 else {
9019 l = (int) le;
9020 if (((double)l)+0.5 <= le) l++;
9021 }
9022
9023 /* Now we normalize inidices */
9024 i -= 1;
9025 l += i;
9026 if (i < 0)
9027 i = 0;
9028 if (l > m)
9029 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009030
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009031 /* number of chars to copy */
9032 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009033
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009034 ret = xmlUTF8Strsub(str->stringval, i, l);
9035 }
9036 else {
9037 ret = NULL;
9038 }
Owen Taylor3473f882001-02-23 17:55:21 +00009039 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009040 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009041 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009042 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009043 xmlFree(ret);
9044 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009045 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009046}
9047
9048/**
9049 * xmlXPathSubstringBeforeFunction:
9050 * @ctxt: the XPath Parser context
9051 * @nargs: the number of arguments
9052 *
9053 * Implement the substring-before() XPath function
9054 * string substring-before(string, string)
9055 * The substring-before function returns the substring of the first
9056 * argument string that precedes the first occurrence of the second
9057 * argument string in the first argument string, or the empty string
9058 * if the first argument string does not contain the second argument
9059 * string. For example, substring-before("1999/04/01","/") returns 1999.
9060 */
9061void
9062xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9063 xmlXPathObjectPtr str;
9064 xmlXPathObjectPtr find;
9065 xmlBufferPtr target;
9066 const xmlChar *point;
9067 int offset;
9068
9069 CHECK_ARITY(2);
9070 CAST_TO_STRING;
9071 find = valuePop(ctxt);
9072 CAST_TO_STRING;
9073 str = valuePop(ctxt);
9074
9075 target = xmlBufferCreate();
9076 if (target) {
9077 point = xmlStrstr(str->stringval, find->stringval);
9078 if (point) {
9079 offset = (int)(point - str->stringval);
9080 xmlBufferAdd(target, str->stringval, offset);
9081 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009082 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9083 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009084 xmlBufferFree(target);
9085 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009086 xmlXPathReleaseObject(ctxt->context, str);
9087 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009088}
9089
9090/**
9091 * xmlXPathSubstringAfterFunction:
9092 * @ctxt: the XPath Parser context
9093 * @nargs: the number of arguments
9094 *
9095 * Implement the substring-after() XPath function
9096 * string substring-after(string, string)
9097 * The substring-after function returns the substring of the first
9098 * argument string that follows the first occurrence of the second
9099 * argument string in the first argument string, or the empty stringi
9100 * if the first argument string does not contain the second argument
9101 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9102 * and substring-after("1999/04/01","19") returns 99/04/01.
9103 */
9104void
9105xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9106 xmlXPathObjectPtr str;
9107 xmlXPathObjectPtr find;
9108 xmlBufferPtr target;
9109 const xmlChar *point;
9110 int offset;
9111
9112 CHECK_ARITY(2);
9113 CAST_TO_STRING;
9114 find = valuePop(ctxt);
9115 CAST_TO_STRING;
9116 str = valuePop(ctxt);
9117
9118 target = xmlBufferCreate();
9119 if (target) {
9120 point = xmlStrstr(str->stringval, find->stringval);
9121 if (point) {
9122 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9123 xmlBufferAdd(target, &str->stringval[offset],
9124 xmlStrlen(str->stringval) - offset);
9125 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009126 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9127 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009128 xmlBufferFree(target);
9129 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009130 xmlXPathReleaseObject(ctxt->context, str);
9131 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009132}
9133
9134/**
9135 * xmlXPathNormalizeFunction:
9136 * @ctxt: the XPath Parser context
9137 * @nargs: the number of arguments
9138 *
9139 * Implement the normalize-space() XPath function
9140 * string normalize-space(string?)
9141 * The normalize-space function returns the argument string with white
9142 * space normalized by stripping leading and trailing whitespace
9143 * and replacing sequences of whitespace characters by a single
9144 * space. Whitespace characters are the same allowed by the S production
9145 * in XML. If the argument is omitted, it defaults to the context
9146 * node converted to a string, in other words the value of the context node.
9147 */
9148void
9149xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9150 xmlXPathObjectPtr obj = NULL;
9151 xmlChar *source = NULL;
9152 xmlBufferPtr target;
9153 xmlChar blank;
9154
Daniel Veillarda82b1822004-11-08 16:24:57 +00009155 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009156 if (nargs == 0) {
9157 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009158 valuePush(ctxt,
9159 xmlXPathCacheWrapString(ctxt->context,
9160 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009161 nargs = 1;
9162 }
9163
9164 CHECK_ARITY(1);
9165 CAST_TO_STRING;
9166 CHECK_TYPE(XPATH_STRING);
9167 obj = valuePop(ctxt);
9168 source = obj->stringval;
9169
9170 target = xmlBufferCreate();
9171 if (target && source) {
9172
9173 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009174 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009175 source++;
9176
9177 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9178 blank = 0;
9179 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009180 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009181 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009182 } else {
9183 if (blank) {
9184 xmlBufferAdd(target, &blank, 1);
9185 blank = 0;
9186 }
9187 xmlBufferAdd(target, source, 1);
9188 }
9189 source++;
9190 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009191 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9192 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009193 xmlBufferFree(target);
9194 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009195 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009196}
9197
9198/**
9199 * xmlXPathTranslateFunction:
9200 * @ctxt: the XPath Parser context
9201 * @nargs: the number of arguments
9202 *
9203 * Implement the translate() XPath function
9204 * string translate(string, string, string)
9205 * The translate function returns the first argument string with
9206 * occurrences of characters in the second argument string replaced
9207 * by the character at the corresponding position in the third argument
9208 * string. For example, translate("bar","abc","ABC") returns the string
9209 * BAr. If there is a character in the second argument string with no
9210 * character at a corresponding position in the third argument string
9211 * (because the second argument string is longer than the third argument
9212 * string), then occurrences of that character in the first argument
9213 * string are removed. For example, translate("--aaa--","abc-","ABC")
9214 * returns "AAA". If a character occurs more than once in second
9215 * argument string, then the first occurrence determines the replacement
9216 * character. If the third argument string is longer than the second
9217 * argument string, then excess characters are ignored.
9218 */
9219void
9220xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009221 xmlXPathObjectPtr str;
9222 xmlXPathObjectPtr from;
9223 xmlXPathObjectPtr to;
9224 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009225 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009226 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009227 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009228 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009229
Daniel Veillarde043ee12001-04-16 14:08:07 +00009230 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009231
Daniel Veillarde043ee12001-04-16 14:08:07 +00009232 CAST_TO_STRING;
9233 to = valuePop(ctxt);
9234 CAST_TO_STRING;
9235 from = valuePop(ctxt);
9236 CAST_TO_STRING;
9237 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009238
Daniel Veillarde043ee12001-04-16 14:08:07 +00009239 target = xmlBufferCreate();
9240 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009241 max = xmlUTF8Strlen(to->stringval);
9242 for (cptr = str->stringval; (ch=*cptr); ) {
9243 offset = xmlUTF8Strloc(from->stringval, cptr);
9244 if (offset >= 0) {
9245 if (offset < max) {
9246 point = xmlUTF8Strpos(to->stringval, offset);
9247 if (point)
9248 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9249 }
9250 } else
9251 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9252
9253 /* Step to next character in input */
9254 cptr++;
9255 if ( ch & 0x80 ) {
9256 /* if not simple ascii, verify proper format */
9257 if ( (ch & 0xc0) != 0xc0 ) {
9258 xmlGenericError(xmlGenericErrorContext,
9259 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9260 break;
9261 }
9262 /* then skip over remaining bytes for this char */
9263 while ( (ch <<= 1) & 0x80 )
9264 if ( (*cptr++ & 0xc0) != 0x80 ) {
9265 xmlGenericError(xmlGenericErrorContext,
9266 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9267 break;
9268 }
9269 if (ch & 0x80) /* must have had error encountered */
9270 break;
9271 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009272 }
Owen Taylor3473f882001-02-23 17:55:21 +00009273 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009274 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9275 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009276 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009277 xmlXPathReleaseObject(ctxt->context, str);
9278 xmlXPathReleaseObject(ctxt->context, from);
9279 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009280}
9281
9282/**
9283 * xmlXPathBooleanFunction:
9284 * @ctxt: the XPath Parser context
9285 * @nargs: the number of arguments
9286 *
9287 * Implement the boolean() XPath function
9288 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009289 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009290 * - a number is true if and only if it is neither positive or
9291 * negative zero nor NaN
9292 * - a node-set is true if and only if it is non-empty
9293 * - a string is true if and only if its length is non-zero
9294 */
9295void
9296xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9297 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009298
9299 CHECK_ARITY(1);
9300 cur = valuePop(ctxt);
9301 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009302 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009303 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009304}
9305
9306/**
9307 * xmlXPathNotFunction:
9308 * @ctxt: the XPath Parser context
9309 * @nargs: the number of arguments
9310 *
9311 * Implement the not() XPath function
9312 * boolean not(boolean)
9313 * The not function returns true if its argument is false,
9314 * and false otherwise.
9315 */
9316void
9317xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9318 CHECK_ARITY(1);
9319 CAST_TO_BOOLEAN;
9320 CHECK_TYPE(XPATH_BOOLEAN);
9321 ctxt->value->boolval = ! ctxt->value->boolval;
9322}
9323
9324/**
9325 * xmlXPathTrueFunction:
9326 * @ctxt: the XPath Parser context
9327 * @nargs: the number of arguments
9328 *
9329 * Implement the true() XPath function
9330 * boolean true()
9331 */
9332void
9333xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009335 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009336}
9337
9338/**
9339 * xmlXPathFalseFunction:
9340 * @ctxt: the XPath Parser context
9341 * @nargs: the number of arguments
9342 *
9343 * Implement the false() XPath function
9344 * boolean false()
9345 */
9346void
9347xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9348 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009349 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009350}
9351
9352/**
9353 * xmlXPathLangFunction:
9354 * @ctxt: the XPath Parser context
9355 * @nargs: the number of arguments
9356 *
9357 * Implement the lang() XPath function
9358 * boolean lang(string)
9359 * The lang function returns true or false depending on whether the
9360 * language of the context node as specified by xml:lang attributes
9361 * is the same as or is a sublanguage of the language specified by
9362 * the argument string. The language of the context node is determined
9363 * by the value of the xml:lang attribute on the context node, or, if
9364 * the context node has no xml:lang attribute, by the value of the
9365 * xml:lang attribute on the nearest ancestor of the context node that
9366 * has an xml:lang attribute. If there is no such attribute, then lang
9367 * returns false. If there is such an attribute, then lang returns
9368 * true if the attribute value is equal to the argument ignoring case,
9369 * or if there is some suffix starting with - such that the attribute
9370 * value is equal to the argument ignoring that suffix of the attribute
9371 * value and ignoring case.
9372 */
9373void
9374xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009375 xmlXPathObjectPtr val = NULL;
9376 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009377 const xmlChar *lang;
9378 int ret = 0;
9379 int i;
9380
9381 CHECK_ARITY(1);
9382 CAST_TO_STRING;
9383 CHECK_TYPE(XPATH_STRING);
9384 val = valuePop(ctxt);
9385 lang = val->stringval;
9386 theLang = xmlNodeGetLang(ctxt->context->node);
9387 if ((theLang != NULL) && (lang != NULL)) {
9388 for (i = 0;lang[i] != 0;i++)
9389 if (toupper(lang[i]) != toupper(theLang[i]))
9390 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009391 if ((theLang[i] == 0) || (theLang[i] == '-'))
9392 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009393 }
9394not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009395 if (theLang != NULL)
9396 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009397
9398 xmlXPathReleaseObject(ctxt->context, val);
9399 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009400}
9401
9402/**
9403 * xmlXPathNumberFunction:
9404 * @ctxt: the XPath Parser context
9405 * @nargs: the number of arguments
9406 *
9407 * Implement the number() XPath function
9408 * number number(object?)
9409 */
9410void
9411xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412 xmlXPathObjectPtr cur;
9413 double res;
9414
Daniel Veillarda82b1822004-11-08 16:24:57 +00009415 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009416 if (nargs == 0) {
9417 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009418 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009419 } else {
9420 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9421
9422 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009423 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009424 xmlFree(content);
9425 }
9426 return;
9427 }
9428
9429 CHECK_ARITY(1);
9430 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009431 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009432}
9433
9434/**
9435 * xmlXPathSumFunction:
9436 * @ctxt: the XPath Parser context
9437 * @nargs: the number of arguments
9438 *
9439 * Implement the sum() XPath function
9440 * number sum(node-set)
9441 * The sum function returns the sum of the values of the nodes in
9442 * the argument node-set.
9443 */
9444void
9445xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9446 xmlXPathObjectPtr cur;
9447 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009448 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009449
9450 CHECK_ARITY(1);
9451 if ((ctxt->value == NULL) ||
9452 ((ctxt->value->type != XPATH_NODESET) &&
9453 (ctxt->value->type != XPATH_XSLT_TREE)))
9454 XP_ERROR(XPATH_INVALID_TYPE);
9455 cur = valuePop(ctxt);
9456
William M. Brack08171912003-12-29 02:52:11 +00009457 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009458 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9459 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009460 }
9461 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009462 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9463 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009464}
9465
William M. Brack3d426662005-04-19 14:40:28 +00009466/*
9467 * To assure working code on multiple platforms, we want to only depend
9468 * upon the characteristic truncation of converting a floating point value
9469 * to an integer. Unfortunately, because of the different storage sizes
9470 * of our internal floating point value (double) and integer (int), we
9471 * can't directly convert (see bug 301162). This macro is a messy
9472 * 'workaround'
9473 */
9474#define XTRUNC(f, v) \
9475 f = fmod((v), INT_MAX); \
9476 f = (v) - (f) + (double)((int)(f));
9477
Owen Taylor3473f882001-02-23 17:55:21 +00009478/**
9479 * xmlXPathFloorFunction:
9480 * @ctxt: the XPath Parser context
9481 * @nargs: the number of arguments
9482 *
9483 * Implement the floor() XPath function
9484 * number floor(number)
9485 * The floor function returns the largest (closest to positive infinity)
9486 * number that is not greater than the argument and that is an integer.
9487 */
9488void
9489xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009490 double f;
9491
Owen Taylor3473f882001-02-23 17:55:21 +00009492 CHECK_ARITY(1);
9493 CAST_TO_NUMBER;
9494 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009495
William M. Brack3d426662005-04-19 14:40:28 +00009496 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009497 if (f != ctxt->value->floatval) {
9498 if (ctxt->value->floatval > 0)
9499 ctxt->value->floatval = f;
9500 else
9501 ctxt->value->floatval = f - 1;
9502 }
Owen Taylor3473f882001-02-23 17:55:21 +00009503}
9504
9505/**
9506 * xmlXPathCeilingFunction:
9507 * @ctxt: the XPath Parser context
9508 * @nargs: the number of arguments
9509 *
9510 * Implement the ceiling() XPath function
9511 * number ceiling(number)
9512 * The ceiling function returns the smallest (closest to negative infinity)
9513 * number that is not less than the argument and that is an integer.
9514 */
9515void
9516xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9517 double f;
9518
9519 CHECK_ARITY(1);
9520 CAST_TO_NUMBER;
9521 CHECK_TYPE(XPATH_NUMBER);
9522
9523#if 0
9524 ctxt->value->floatval = ceil(ctxt->value->floatval);
9525#else
William M. Brack3d426662005-04-19 14:40:28 +00009526 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009527 if (f != ctxt->value->floatval) {
9528 if (ctxt->value->floatval > 0)
9529 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009530 else {
9531 if (ctxt->value->floatval < 0 && f == 0)
9532 ctxt->value->floatval = xmlXPathNZERO;
9533 else
9534 ctxt->value->floatval = f;
9535 }
9536
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009537 }
Owen Taylor3473f882001-02-23 17:55:21 +00009538#endif
9539}
9540
9541/**
9542 * xmlXPathRoundFunction:
9543 * @ctxt: the XPath Parser context
9544 * @nargs: the number of arguments
9545 *
9546 * Implement the round() XPath function
9547 * number round(number)
9548 * The round function returns the number that is closest to the
9549 * argument and that is an integer. If there are two such numbers,
9550 * then the one that is even is returned.
9551 */
9552void
9553xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9554 double f;
9555
9556 CHECK_ARITY(1);
9557 CAST_TO_NUMBER;
9558 CHECK_TYPE(XPATH_NUMBER);
9559
Daniel Veillardcda96922001-08-21 10:56:31 +00009560 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9561 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9562 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009563 (ctxt->value->floatval == 0.0))
9564 return;
9565
William M. Brack3d426662005-04-19 14:40:28 +00009566 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009567 if (ctxt->value->floatval < 0) {
9568 if (ctxt->value->floatval < f - 0.5)
9569 ctxt->value->floatval = f - 1;
9570 else
9571 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009572 if (ctxt->value->floatval == 0)
9573 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009574 } else {
9575 if (ctxt->value->floatval < f + 0.5)
9576 ctxt->value->floatval = f;
9577 else
9578 ctxt->value->floatval = f + 1;
9579 }
Owen Taylor3473f882001-02-23 17:55:21 +00009580}
9581
9582/************************************************************************
9583 * *
9584 * The Parser *
9585 * *
9586 ************************************************************************/
9587
9588/*
William M. Brack08171912003-12-29 02:52:11 +00009589 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009590 * implementation.
9591 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009592static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009593static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009594static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009595static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009596static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9597 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009598
9599/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009600 * xmlXPathCurrentChar:
9601 * @ctxt: the XPath parser context
9602 * @cur: pointer to the beginning of the char
9603 * @len: pointer to the length of the char read
9604 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009605 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009606 * bytes in the input buffer.
9607 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009608 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009609 */
9610
9611static int
9612xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9613 unsigned char c;
9614 unsigned int val;
9615 const xmlChar *cur;
9616
9617 if (ctxt == NULL)
9618 return(0);
9619 cur = ctxt->cur;
9620
9621 /*
9622 * We are supposed to handle UTF8, check it's valid
9623 * From rfc2044: encoding of the Unicode values on UTF-8:
9624 *
9625 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9626 * 0000 0000-0000 007F 0xxxxxxx
9627 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9628 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9629 *
9630 * Check for the 0x110000 limit too
9631 */
9632 c = *cur;
9633 if (c & 0x80) {
9634 if ((cur[1] & 0xc0) != 0x80)
9635 goto encoding_error;
9636 if ((c & 0xe0) == 0xe0) {
9637
9638 if ((cur[2] & 0xc0) != 0x80)
9639 goto encoding_error;
9640 if ((c & 0xf0) == 0xf0) {
9641 if (((c & 0xf8) != 0xf0) ||
9642 ((cur[3] & 0xc0) != 0x80))
9643 goto encoding_error;
9644 /* 4-byte code */
9645 *len = 4;
9646 val = (cur[0] & 0x7) << 18;
9647 val |= (cur[1] & 0x3f) << 12;
9648 val |= (cur[2] & 0x3f) << 6;
9649 val |= cur[3] & 0x3f;
9650 } else {
9651 /* 3-byte code */
9652 *len = 3;
9653 val = (cur[0] & 0xf) << 12;
9654 val |= (cur[1] & 0x3f) << 6;
9655 val |= cur[2] & 0x3f;
9656 }
9657 } else {
9658 /* 2-byte code */
9659 *len = 2;
9660 val = (cur[0] & 0x1f) << 6;
9661 val |= cur[1] & 0x3f;
9662 }
9663 if (!IS_CHAR(val)) {
9664 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9665 }
9666 return(val);
9667 } else {
9668 /* 1-byte code */
9669 *len = 1;
9670 return((int) *cur);
9671 }
9672encoding_error:
9673 /*
William M. Brack08171912003-12-29 02:52:11 +00009674 * If we detect an UTF8 error that probably means that the
9675 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009676 * declaration header. Report the error and switch the encoding
9677 * to ISO-Latin-1 (if you don't like this policy, just declare the
9678 * encoding !)
9679 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009680 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009681 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009682}
9683
9684/**
Owen Taylor3473f882001-02-23 17:55:21 +00009685 * xmlXPathParseNCName:
9686 * @ctxt: the XPath Parser context
9687 *
9688 * parse an XML namespace non qualified name.
9689 *
9690 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9691 *
9692 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9693 * CombiningChar | Extender
9694 *
9695 * Returns the namespace name or NULL
9696 */
9697
9698xmlChar *
9699xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009700 const xmlChar *in;
9701 xmlChar *ret;
9702 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009703
Daniel Veillarda82b1822004-11-08 16:24:57 +00009704 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009705 /*
9706 * Accelerator for simple ASCII names
9707 */
9708 in = ctxt->cur;
9709 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9710 ((*in >= 0x41) && (*in <= 0x5A)) ||
9711 (*in == '_')) {
9712 in++;
9713 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9714 ((*in >= 0x41) && (*in <= 0x5A)) ||
9715 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009716 (*in == '_') || (*in == '.') ||
9717 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009718 in++;
9719 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9720 (*in == '[') || (*in == ']') || (*in == ':') ||
9721 (*in == '@') || (*in == '*')) {
9722 count = in - ctxt->cur;
9723 if (count == 0)
9724 return(NULL);
9725 ret = xmlStrndup(ctxt->cur, count);
9726 ctxt->cur = in;
9727 return(ret);
9728 }
9729 }
9730 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009731}
9732
Daniel Veillard2156a562001-04-28 12:24:34 +00009733
Owen Taylor3473f882001-02-23 17:55:21 +00009734/**
9735 * xmlXPathParseQName:
9736 * @ctxt: the XPath Parser context
9737 * @prefix: a xmlChar **
9738 *
9739 * parse an XML qualified name
9740 *
9741 * [NS 5] QName ::= (Prefix ':')? LocalPart
9742 *
9743 * [NS 6] Prefix ::= NCName
9744 *
9745 * [NS 7] LocalPart ::= NCName
9746 *
9747 * Returns the function returns the local part, and prefix is updated
9748 * to get the Prefix if any.
9749 */
9750
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009751static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009752xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9753 xmlChar *ret = NULL;
9754
9755 *prefix = NULL;
9756 ret = xmlXPathParseNCName(ctxt);
9757 if (CUR == ':') {
9758 *prefix = ret;
9759 NEXT;
9760 ret = xmlXPathParseNCName(ctxt);
9761 }
9762 return(ret);
9763}
9764
9765/**
9766 * xmlXPathParseName:
9767 * @ctxt: the XPath Parser context
9768 *
9769 * parse an XML name
9770 *
9771 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9772 * CombiningChar | Extender
9773 *
9774 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9775 *
9776 * Returns the namespace name or NULL
9777 */
9778
9779xmlChar *
9780xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009781 const xmlChar *in;
9782 xmlChar *ret;
9783 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009784
Daniel Veillarda82b1822004-11-08 16:24:57 +00009785 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009786 /*
9787 * Accelerator for simple ASCII names
9788 */
9789 in = ctxt->cur;
9790 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9791 ((*in >= 0x41) && (*in <= 0x5A)) ||
9792 (*in == '_') || (*in == ':')) {
9793 in++;
9794 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9795 ((*in >= 0x41) && (*in <= 0x5A)) ||
9796 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009797 (*in == '_') || (*in == '-') ||
9798 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009799 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009800 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009801 count = in - ctxt->cur;
9802 ret = xmlStrndup(ctxt->cur, count);
9803 ctxt->cur = in;
9804 return(ret);
9805 }
9806 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009807 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009808}
9809
Daniel Veillard61d80a22001-04-27 17:13:01 +00009810static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009811xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009812 xmlChar buf[XML_MAX_NAMELEN + 5];
9813 int len = 0, l;
9814 int c;
9815
9816 /*
9817 * Handler for more complex cases
9818 */
9819 c = CUR_CHAR(l);
9820 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009821 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9822 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009823 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009824 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009825 return(NULL);
9826 }
9827
9828 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9829 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9830 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009831 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009832 (IS_COMBINING(c)) ||
9833 (IS_EXTENDER(c)))) {
9834 COPY_BUF(l,buf,len,c);
9835 NEXTL(l);
9836 c = CUR_CHAR(l);
9837 if (len >= XML_MAX_NAMELEN) {
9838 /*
9839 * Okay someone managed to make a huge name, so he's ready to pay
9840 * for the processing speed.
9841 */
9842 xmlChar *buffer;
9843 int max = len * 2;
9844
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009845 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009846 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009847 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009848 }
9849 memcpy(buffer, buf, len);
9850 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9851 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009852 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009853 (IS_COMBINING(c)) ||
9854 (IS_EXTENDER(c))) {
9855 if (len + 10 > max) {
9856 max *= 2;
9857 buffer = (xmlChar *) xmlRealloc(buffer,
9858 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009859 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009860 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009861 }
9862 }
9863 COPY_BUF(l,buffer,len,c);
9864 NEXTL(l);
9865 c = CUR_CHAR(l);
9866 }
9867 buffer[len] = 0;
9868 return(buffer);
9869 }
9870 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009871 if (len == 0)
9872 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009873 return(xmlStrndup(buf, len));
9874}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009875
9876#define MAX_FRAC 20
9877
William M. Brack372a4452004-02-17 13:09:23 +00009878/*
9879 * These are used as divisors for the fractional part of a number.
9880 * Since the table includes 1.0 (representing '0' fractional digits),
9881 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9882 */
9883static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009884 1.0, 10.0, 100.0, 1000.0, 10000.0,
9885 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9886 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9887 100000000000000.0,
9888 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009889 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009890};
9891
Owen Taylor3473f882001-02-23 17:55:21 +00009892/**
9893 * xmlXPathStringEvalNumber:
9894 * @str: A string to scan
9895 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009896 * [30a] Float ::= Number ('e' Digits?)?
9897 *
Owen Taylor3473f882001-02-23 17:55:21 +00009898 * [30] Number ::= Digits ('.' Digits?)?
9899 * | '.' Digits
9900 * [31] Digits ::= [0-9]+
9901 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009902 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009903 * In complement of the Number expression, this function also handles
9904 * negative values : '-' Number.
9905 *
9906 * Returns the double value.
9907 */
9908double
9909xmlXPathStringEvalNumber(const xmlChar *str) {
9910 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009911 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009912 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009913 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009914 int exponent = 0;
9915 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009916#ifdef __GNUC__
9917 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009918 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009919#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009920 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009921 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009922 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9923 return(xmlXPathNAN);
9924 }
9925 if (*cur == '-') {
9926 isneg = 1;
9927 cur++;
9928 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009929
9930#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009931 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009932 * tmp/temp is a workaround against a gcc compiler bug
9933 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009934 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009935 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009936 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009937 ret = ret * 10;
9938 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009939 ok = 1;
9940 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009941 temp = (double) tmp;
9942 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009943 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009944#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009945 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009946 while ((*cur >= '0') && (*cur <= '9')) {
9947 ret = ret * 10 + (*cur - '0');
9948 ok = 1;
9949 cur++;
9950 }
9951#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009952
Owen Taylor3473f882001-02-23 17:55:21 +00009953 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009954 int v, frac = 0;
9955 double fraction = 0;
9956
Owen Taylor3473f882001-02-23 17:55:21 +00009957 cur++;
9958 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9959 return(xmlXPathNAN);
9960 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009961 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9962 v = (*cur - '0');
9963 fraction = fraction * 10 + v;
9964 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009965 cur++;
9966 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009967 fraction /= my_pow10[frac];
9968 ret = ret + fraction;
9969 while ((*cur >= '0') && (*cur <= '9'))
9970 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009971 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009972 if ((*cur == 'e') || (*cur == 'E')) {
9973 cur++;
9974 if (*cur == '-') {
9975 is_exponent_negative = 1;
9976 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009977 } else if (*cur == '+') {
9978 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009979 }
9980 while ((*cur >= '0') && (*cur <= '9')) {
9981 exponent = exponent * 10 + (*cur - '0');
9982 cur++;
9983 }
9984 }
William M. Brack76e95df2003-10-18 16:20:14 +00009985 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009986 if (*cur != 0) return(xmlXPathNAN);
9987 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009988 if (is_exponent_negative) exponent = -exponent;
9989 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009990 return(ret);
9991}
9992
9993/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009994 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009995 * @ctxt: the XPath Parser context
9996 *
9997 * [30] Number ::= Digits ('.' Digits?)?
9998 * | '.' Digits
9999 * [31] Digits ::= [0-9]+
10000 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010001 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +000010002 *
10003 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010004static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010005xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10006{
Owen Taylor3473f882001-02-23 17:55:21 +000010007 double ret = 0.0;
10008 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +000010009 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010010 int exponent = 0;
10011 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010012#ifdef __GNUC__
10013 unsigned long tmp = 0;
10014 double temp;
10015#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010016
10017 CHECK_ERROR;
10018 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10019 XP_ERROR(XPATH_NUMBER_ERROR);
10020 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010021#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010022 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010023 * tmp/temp is a workaround against a gcc compiler bug
10024 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010025 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010026 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010027 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010028 ret = ret * 10;
10029 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010030 ok = 1;
10031 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010032 temp = (double) tmp;
10033 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010034 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010035#else
10036 ret = 0;
10037 while ((CUR >= '0') && (CUR <= '9')) {
10038 ret = ret * 10 + (CUR - '0');
10039 ok = 1;
10040 NEXT;
10041 }
10042#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010043 if (CUR == '.') {
10044 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010045 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10046 XP_ERROR(XPATH_NUMBER_ERROR);
10047 }
10048 while ((CUR >= '0') && (CUR <= '9')) {
10049 mult /= 10;
10050 ret = ret + (CUR - '0') * mult;
10051 NEXT;
10052 }
Owen Taylor3473f882001-02-23 17:55:21 +000010053 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010054 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010055 NEXT;
10056 if (CUR == '-') {
10057 is_exponent_negative = 1;
10058 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010059 } else if (CUR == '+') {
10060 NEXT;
10061 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010062 while ((CUR >= '0') && (CUR <= '9')) {
10063 exponent = exponent * 10 + (CUR - '0');
10064 NEXT;
10065 }
10066 if (is_exponent_negative)
10067 exponent = -exponent;
10068 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010069 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010070 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010071 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010072}
10073
10074/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010075 * xmlXPathParseLiteral:
10076 * @ctxt: the XPath Parser context
10077 *
10078 * Parse a Literal
10079 *
10080 * [29] Literal ::= '"' [^"]* '"'
10081 * | "'" [^']* "'"
10082 *
10083 * Returns the value found or NULL in case of error
10084 */
10085static xmlChar *
10086xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10087 const xmlChar *q;
10088 xmlChar *ret = NULL;
10089
10090 if (CUR == '"') {
10091 NEXT;
10092 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010093 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010094 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010095 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010096 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010097 } else {
10098 ret = xmlStrndup(q, CUR_PTR - q);
10099 NEXT;
10100 }
10101 } else if (CUR == '\'') {
10102 NEXT;
10103 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010104 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010105 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010106 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010107 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010108 } else {
10109 ret = xmlStrndup(q, CUR_PTR - q);
10110 NEXT;
10111 }
10112 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010113 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010114 }
10115 return(ret);
10116}
10117
10118/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010119 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010120 * @ctxt: the XPath Parser context
10121 *
10122 * Parse a Literal and push it on the stack.
10123 *
10124 * [29] Literal ::= '"' [^"]* '"'
10125 * | "'" [^']* "'"
10126 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010127 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010128 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010129static void
10130xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010131 const xmlChar *q;
10132 xmlChar *ret = NULL;
10133
10134 if (CUR == '"') {
10135 NEXT;
10136 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010137 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010138 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010139 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010140 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10141 } else {
10142 ret = xmlStrndup(q, CUR_PTR - q);
10143 NEXT;
10144 }
10145 } else if (CUR == '\'') {
10146 NEXT;
10147 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010148 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010149 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010150 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010151 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10152 } else {
10153 ret = xmlStrndup(q, CUR_PTR - q);
10154 NEXT;
10155 }
10156 } else {
10157 XP_ERROR(XPATH_START_LITERAL_ERROR);
10158 }
10159 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010160 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010161 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010162 xmlFree(ret);
10163}
10164
10165/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010166 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010167 * @ctxt: the XPath Parser context
10168 *
10169 * Parse a VariableReference, evaluate it and push it on the stack.
10170 *
10171 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010172 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010173 * of any of the types that are possible for the value of an expression,
10174 * and may also be of additional types not specified here.
10175 *
10176 * Early evaluation is possible since:
10177 * The variable bindings [...] used to evaluate a subexpression are
10178 * always the same as those used to evaluate the containing expression.
10179 *
10180 * [36] VariableReference ::= '$' QName
10181 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010182static void
10183xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010184 xmlChar *name;
10185 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010186
10187 SKIP_BLANKS;
10188 if (CUR != '$') {
10189 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10190 }
10191 NEXT;
10192 name = xmlXPathParseQName(ctxt, &prefix);
10193 if (name == NULL) {
10194 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10195 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010196 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010197 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10198 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010199 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010200 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10201 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10202 }
Owen Taylor3473f882001-02-23 17:55:21 +000010203}
10204
10205/**
10206 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010207 * @name: a name string
10208 *
10209 * Is the name given a NodeType one.
10210 *
10211 * [38] NodeType ::= 'comment'
10212 * | 'text'
10213 * | 'processing-instruction'
10214 * | 'node'
10215 *
10216 * Returns 1 if true 0 otherwise
10217 */
10218int
10219xmlXPathIsNodeType(const xmlChar *name) {
10220 if (name == NULL)
10221 return(0);
10222
Daniel Veillard1971ee22002-01-31 20:29:19 +000010223 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010224 return(1);
10225 if (xmlStrEqual(name, BAD_CAST "text"))
10226 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010227 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010228 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010229 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010230 return(1);
10231 return(0);
10232}
10233
10234/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010235 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010236 * @ctxt: the XPath Parser context
10237 *
10238 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10239 * [17] Argument ::= Expr
10240 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010241 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010242 * pushed on the stack
10243 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010244static void
10245xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010246 xmlChar *name;
10247 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010248 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010249 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010250
10251 name = xmlXPathParseQName(ctxt, &prefix);
10252 if (name == NULL) {
10253 XP_ERROR(XPATH_EXPR_ERROR);
10254 }
10255 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010256#ifdef DEBUG_EXPR
10257 if (prefix == NULL)
10258 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10259 name);
10260 else
10261 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10262 prefix, name);
10263#endif
10264
Owen Taylor3473f882001-02-23 17:55:21 +000010265 if (CUR != '(') {
10266 XP_ERROR(XPATH_EXPR_ERROR);
10267 }
10268 NEXT;
10269 SKIP_BLANKS;
10270
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010271 /*
10272 * Optimization for count(): we don't need the node-set to be sorted.
10273 */
10274 if ((prefix == NULL) && (name[0] == 'c') &&
10275 xmlStrEqual(name, BAD_CAST "count"))
10276 {
10277 sort = 0;
10278 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010279 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010280 if (CUR != ')') {
10281 while (CUR != 0) {
10282 int op1 = ctxt->comp->last;
10283 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010284 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010285 CHECK_ERROR;
10286 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10287 nbargs++;
10288 if (CUR == ')') break;
10289 if (CUR != ',') {
10290 XP_ERROR(XPATH_EXPR_ERROR);
10291 }
10292 NEXT;
10293 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010294 }
Owen Taylor3473f882001-02-23 17:55:21 +000010295 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010296 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10297 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010298 NEXT;
10299 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010300}
10301
10302/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010303 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010304 * @ctxt: the XPath Parser context
10305 *
10306 * [15] PrimaryExpr ::= VariableReference
10307 * | '(' Expr ')'
10308 * | Literal
10309 * | Number
10310 * | FunctionCall
10311 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010312 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010313 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010314static void
10315xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010316 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010317 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010318 else if (CUR == '(') {
10319 NEXT;
10320 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010321 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010322 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010323 if (CUR != ')') {
10324 XP_ERROR(XPATH_EXPR_ERROR);
10325 }
10326 NEXT;
10327 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010328 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010329 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010330 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010331 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010332 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010333 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010334 }
10335 SKIP_BLANKS;
10336}
10337
10338/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010339 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010340 * @ctxt: the XPath Parser context
10341 *
10342 * [20] FilterExpr ::= PrimaryExpr
10343 * | FilterExpr Predicate
10344 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010345 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010346 * Square brackets are used to filter expressions in the same way that
10347 * they are used in location paths. It is an error if the expression to
10348 * be filtered does not evaluate to a node-set. The context node list
10349 * used for evaluating the expression in square brackets is the node-set
10350 * to be filtered listed in document order.
10351 */
10352
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010353static void
10354xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10355 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010356 CHECK_ERROR;
10357 SKIP_BLANKS;
10358
10359 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010360 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010361 SKIP_BLANKS;
10362 }
10363
10364
10365}
10366
10367/**
10368 * xmlXPathScanName:
10369 * @ctxt: the XPath Parser context
10370 *
10371 * Trickery: parse an XML name but without consuming the input flow
10372 * Needed to avoid insanity in the parser state.
10373 *
10374 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10375 * CombiningChar | Extender
10376 *
10377 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10378 *
10379 * [6] Names ::= Name (S Name)*
10380 *
10381 * Returns the Name parsed or NULL
10382 */
10383
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010384static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010385xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010386 int len = 0, l;
10387 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010388 const xmlChar *cur;
10389 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010390
Daniel Veillard03226812004-11-01 14:55:21 +000010391 cur = ctxt->cur;
10392
10393 c = CUR_CHAR(l);
10394 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10395 (!IS_LETTER(c) && (c != '_') &&
10396 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010397 return(NULL);
10398 }
10399
Daniel Veillard03226812004-11-01 14:55:21 +000010400 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10401 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10402 (c == '.') || (c == '-') ||
10403 (c == '_') || (c == ':') ||
10404 (IS_COMBINING(c)) ||
10405 (IS_EXTENDER(c)))) {
10406 len += l;
10407 NEXTL(l);
10408 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010409 }
Daniel Veillard03226812004-11-01 14:55:21 +000010410 ret = xmlStrndup(cur, ctxt->cur - cur);
10411 ctxt->cur = cur;
10412 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010413}
10414
10415/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010416 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010417 * @ctxt: the XPath Parser context
10418 *
10419 * [19] PathExpr ::= LocationPath
10420 * | FilterExpr
10421 * | FilterExpr '/' RelativeLocationPath
10422 * | FilterExpr '//' RelativeLocationPath
10423 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010424 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010425 * The / operator and // operators combine an arbitrary expression
10426 * and a relative location path. It is an error if the expression
10427 * does not evaluate to a node-set.
10428 * The / operator does composition in the same way as when / is
10429 * used in a location path. As in location paths, // is short for
10430 * /descendant-or-self::node()/.
10431 */
10432
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010433static void
10434xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010435 int lc = 1; /* Should we branch to LocationPath ? */
10436 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10437
10438 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010439 if ((CUR == '$') || (CUR == '(') ||
10440 (IS_ASCII_DIGIT(CUR)) ||
10441 (CUR == '\'') || (CUR == '"') ||
10442 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010443 lc = 0;
10444 } else if (CUR == '*') {
10445 /* relative or absolute location path */
10446 lc = 1;
10447 } else if (CUR == '/') {
10448 /* relative or absolute location path */
10449 lc = 1;
10450 } else if (CUR == '@') {
10451 /* relative abbreviated attribute location path */
10452 lc = 1;
10453 } else if (CUR == '.') {
10454 /* relative abbreviated attribute location path */
10455 lc = 1;
10456 } else {
10457 /*
10458 * Problem is finding if we have a name here whether it's:
10459 * - a nodetype
10460 * - a function call in which case it's followed by '('
10461 * - an axis in which case it's followed by ':'
10462 * - a element name
10463 * We do an a priori analysis here rather than having to
10464 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010465 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010466 * read/write/debug.
10467 */
10468 SKIP_BLANKS;
10469 name = xmlXPathScanName(ctxt);
10470 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10471#ifdef DEBUG_STEP
10472 xmlGenericError(xmlGenericErrorContext,
10473 "PathExpr: Axis\n");
10474#endif
10475 lc = 1;
10476 xmlFree(name);
10477 } else if (name != NULL) {
10478 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010479
10480
10481 while (NXT(len) != 0) {
10482 if (NXT(len) == '/') {
10483 /* element name */
10484#ifdef DEBUG_STEP
10485 xmlGenericError(xmlGenericErrorContext,
10486 "PathExpr: AbbrRelLocation\n");
10487#endif
10488 lc = 1;
10489 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010490 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010491 /* ignore blanks */
10492 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010493 } else if (NXT(len) == ':') {
10494#ifdef DEBUG_STEP
10495 xmlGenericError(xmlGenericErrorContext,
10496 "PathExpr: AbbrRelLocation\n");
10497#endif
10498 lc = 1;
10499 break;
10500 } else if ((NXT(len) == '(')) {
10501 /* Note Type or Function */
10502 if (xmlXPathIsNodeType(name)) {
10503#ifdef DEBUG_STEP
10504 xmlGenericError(xmlGenericErrorContext,
10505 "PathExpr: Type search\n");
10506#endif
10507 lc = 1;
10508 } else {
10509#ifdef DEBUG_STEP
10510 xmlGenericError(xmlGenericErrorContext,
10511 "PathExpr: function call\n");
10512#endif
10513 lc = 0;
10514 }
10515 break;
10516 } else if ((NXT(len) == '[')) {
10517 /* element name */
10518#ifdef DEBUG_STEP
10519 xmlGenericError(xmlGenericErrorContext,
10520 "PathExpr: AbbrRelLocation\n");
10521#endif
10522 lc = 1;
10523 break;
10524 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10525 (NXT(len) == '=')) {
10526 lc = 1;
10527 break;
10528 } else {
10529 lc = 1;
10530 break;
10531 }
10532 len++;
10533 }
10534 if (NXT(len) == 0) {
10535#ifdef DEBUG_STEP
10536 xmlGenericError(xmlGenericErrorContext,
10537 "PathExpr: AbbrRelLocation\n");
10538#endif
10539 /* element name */
10540 lc = 1;
10541 }
10542 xmlFree(name);
10543 } else {
William M. Brack08171912003-12-29 02:52:11 +000010544 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010545 XP_ERROR(XPATH_EXPR_ERROR);
10546 }
10547 }
10548
10549 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010550 if (CUR == '/') {
10551 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10552 } else {
10553 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010554 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010555 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010556 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010557 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010558 CHECK_ERROR;
10559 if ((CUR == '/') && (NXT(1) == '/')) {
10560 SKIP(2);
10561 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010562
10563 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10564 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10565 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10566
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010567 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010568 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010569 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010570 }
10571 }
10572 SKIP_BLANKS;
10573}
10574
10575/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010576 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010577 * @ctxt: the XPath Parser context
10578 *
10579 * [18] UnionExpr ::= PathExpr
10580 * | UnionExpr '|' PathExpr
10581 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010582 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010583 */
10584
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010585static void
10586xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10587 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010588 CHECK_ERROR;
10589 SKIP_BLANKS;
10590 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591 int op1 = ctxt->comp->last;
10592 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010593
10594 NEXT;
10595 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010596 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010597
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010598 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10599
Owen Taylor3473f882001-02-23 17:55:21 +000010600 SKIP_BLANKS;
10601 }
Owen Taylor3473f882001-02-23 17:55:21 +000010602}
10603
10604/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010605 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010606 * @ctxt: the XPath Parser context
10607 *
10608 * [27] UnaryExpr ::= UnionExpr
10609 * | '-' UnaryExpr
10610 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010611 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010612 */
10613
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010614static void
10615xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010616 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010617 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010618
10619 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010620 while (CUR == '-') {
10621 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010622 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010623 NEXT;
10624 SKIP_BLANKS;
10625 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010626
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010627 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010628 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010629 if (found) {
10630 if (minus)
10631 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10632 else
10633 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010634 }
10635}
10636
10637/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010638 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010639 * @ctxt: the XPath Parser context
10640 *
10641 * [26] MultiplicativeExpr ::= UnaryExpr
10642 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10643 * | MultiplicativeExpr 'div' UnaryExpr
10644 * | MultiplicativeExpr 'mod' UnaryExpr
10645 * [34] MultiplyOperator ::= '*'
10646 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010647 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010648 */
10649
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010650static void
10651xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10652 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010653 CHECK_ERROR;
10654 SKIP_BLANKS;
10655 while ((CUR == '*') ||
10656 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10657 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10658 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010659 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010660
10661 if (CUR == '*') {
10662 op = 0;
10663 NEXT;
10664 } else if (CUR == 'd') {
10665 op = 1;
10666 SKIP(3);
10667 } else if (CUR == 'm') {
10668 op = 2;
10669 SKIP(3);
10670 }
10671 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010672 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010673 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010674 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010675 SKIP_BLANKS;
10676 }
10677}
10678
10679/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010680 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010681 * @ctxt: the XPath Parser context
10682 *
10683 * [25] AdditiveExpr ::= MultiplicativeExpr
10684 * | AdditiveExpr '+' MultiplicativeExpr
10685 * | AdditiveExpr '-' MultiplicativeExpr
10686 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010687 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010688 */
10689
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010690static void
10691xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010692
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010693 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010694 CHECK_ERROR;
10695 SKIP_BLANKS;
10696 while ((CUR == '+') || (CUR == '-')) {
10697 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010699
10700 if (CUR == '+') plus = 1;
10701 else plus = 0;
10702 NEXT;
10703 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010704 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010705 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010706 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010707 SKIP_BLANKS;
10708 }
10709}
10710
10711/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010712 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010713 * @ctxt: the XPath Parser context
10714 *
10715 * [24] RelationalExpr ::= AdditiveExpr
10716 * | RelationalExpr '<' AdditiveExpr
10717 * | RelationalExpr '>' AdditiveExpr
10718 * | RelationalExpr '<=' AdditiveExpr
10719 * | RelationalExpr '>=' AdditiveExpr
10720 *
10721 * A <= B > C is allowed ? Answer from James, yes with
10722 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10723 * which is basically what got implemented.
10724 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010725 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010726 * on the stack
10727 */
10728
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010729static void
10730xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10731 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010732 CHECK_ERROR;
10733 SKIP_BLANKS;
10734 while ((CUR == '<') ||
10735 (CUR == '>') ||
10736 ((CUR == '<') && (NXT(1) == '=')) ||
10737 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010738 int inf, strict;
10739 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010740
10741 if (CUR == '<') inf = 1;
10742 else inf = 0;
10743 if (NXT(1) == '=') strict = 0;
10744 else strict = 1;
10745 NEXT;
10746 if (!strict) NEXT;
10747 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010748 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010749 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010750 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010751 SKIP_BLANKS;
10752 }
10753}
10754
10755/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010756 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010757 * @ctxt: the XPath Parser context
10758 *
10759 * [23] EqualityExpr ::= RelationalExpr
10760 * | EqualityExpr '=' RelationalExpr
10761 * | EqualityExpr '!=' RelationalExpr
10762 *
10763 * A != B != C is allowed ? Answer from James, yes with
10764 * (RelationalExpr = RelationalExpr) = RelationalExpr
10765 * (RelationalExpr != RelationalExpr) != RelationalExpr
10766 * which is basically what got implemented.
10767 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010768 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010769 *
10770 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010771static void
10772xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10773 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010774 CHECK_ERROR;
10775 SKIP_BLANKS;
10776 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010777 int eq;
10778 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010779
10780 if (CUR == '=') eq = 1;
10781 else eq = 0;
10782 NEXT;
10783 if (!eq) NEXT;
10784 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010785 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010786 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010787 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010788 SKIP_BLANKS;
10789 }
10790}
10791
10792/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010793 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010794 * @ctxt: the XPath Parser context
10795 *
10796 * [22] AndExpr ::= EqualityExpr
10797 * | AndExpr 'and' EqualityExpr
10798 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010799 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010800 *
10801 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010802static void
10803xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10804 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010805 CHECK_ERROR;
10806 SKIP_BLANKS;
10807 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010808 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010809 SKIP(3);
10810 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010811 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010812 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010813 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010814 SKIP_BLANKS;
10815 }
10816}
10817
10818/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010819 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010820 * @ctxt: the XPath Parser context
10821 *
10822 * [14] Expr ::= OrExpr
10823 * [21] OrExpr ::= AndExpr
10824 * | OrExpr 'or' AndExpr
10825 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010827 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010828static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010829xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010830 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010831 CHECK_ERROR;
10832 SKIP_BLANKS;
10833 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010834 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010835 SKIP(2);
10836 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010837 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010838 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010839 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10840 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010841 SKIP_BLANKS;
10842 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010843 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010844 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010845 /*
10846 * This is the main place to eliminate sorting for
10847 * operations which don't require a sorted node-set.
10848 * E.g. count().
10849 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010850 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10851 }
Owen Taylor3473f882001-02-23 17:55:21 +000010852}
10853
10854/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010855 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010856 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010857 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010858 *
10859 * [8] Predicate ::= '[' PredicateExpr ']'
10860 * [9] PredicateExpr ::= Expr
10861 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010862 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010863 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010864static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010865xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010866 int op1 = ctxt->comp->last;
10867
10868 SKIP_BLANKS;
10869 if (CUR != '[') {
10870 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10871 }
10872 NEXT;
10873 SKIP_BLANKS;
10874
10875 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010876 /*
10877 * This call to xmlXPathCompileExpr() will deactivate sorting
10878 * of the predicate result.
10879 * TODO: Sorting is still activated for filters, since I'm not
10880 * sure if needed. Normally sorting should not be needed, since
10881 * a filter can only diminish the number of items in a sequence,
10882 * but won't change its order; so if the initial sequence is sorted,
10883 * subsequent sorting is not needed.
10884 */
10885 if (! filter)
10886 xmlXPathCompileExpr(ctxt, 0);
10887 else
10888 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010889 CHECK_ERROR;
10890
10891 if (CUR != ']') {
10892 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10893 }
10894
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010895 if (filter)
10896 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10897 else
10898 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010899
10900 NEXT;
10901 SKIP_BLANKS;
10902}
10903
10904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010905 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010906 * @ctxt: the XPath Parser context
10907 * @test: pointer to a xmlXPathTestVal
10908 * @type: pointer to a xmlXPathTypeVal
10909 * @prefix: placeholder for a possible name prefix
10910 *
10911 * [7] NodeTest ::= NameTest
10912 * | NodeType '(' ')'
10913 * | 'processing-instruction' '(' Literal ')'
10914 *
10915 * [37] NameTest ::= '*'
10916 * | NCName ':' '*'
10917 * | QName
10918 * [38] NodeType ::= 'comment'
10919 * | 'text'
10920 * | 'processing-instruction'
10921 * | 'node'
10922 *
William M. Brack08171912003-12-29 02:52:11 +000010923 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010924 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010925static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010926xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10927 xmlXPathTypeVal *type, const xmlChar **prefix,
10928 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010929 int blanks;
10930
10931 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10932 STRANGE;
10933 return(NULL);
10934 }
William M. Brack78637da2003-07-31 14:47:38 +000010935 *type = (xmlXPathTypeVal) 0;
10936 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010937 *prefix = NULL;
10938 SKIP_BLANKS;
10939
10940 if ((name == NULL) && (CUR == '*')) {
10941 /*
10942 * All elements
10943 */
10944 NEXT;
10945 *test = NODE_TEST_ALL;
10946 return(NULL);
10947 }
10948
10949 if (name == NULL)
10950 name = xmlXPathParseNCName(ctxt);
10951 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010952 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010953 }
10954
William M. Brack76e95df2003-10-18 16:20:14 +000010955 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010956 SKIP_BLANKS;
10957 if (CUR == '(') {
10958 NEXT;
10959 /*
10960 * NodeType or PI search
10961 */
10962 if (xmlStrEqual(name, BAD_CAST "comment"))
10963 *type = NODE_TYPE_COMMENT;
10964 else if (xmlStrEqual(name, BAD_CAST "node"))
10965 *type = NODE_TYPE_NODE;
10966 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10967 *type = NODE_TYPE_PI;
10968 else if (xmlStrEqual(name, BAD_CAST "text"))
10969 *type = NODE_TYPE_TEXT;
10970 else {
10971 if (name != NULL)
10972 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010973 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010974 }
10975
10976 *test = NODE_TEST_TYPE;
10977
10978 SKIP_BLANKS;
10979 if (*type == NODE_TYPE_PI) {
10980 /*
10981 * Specific case: search a PI by name.
10982 */
Owen Taylor3473f882001-02-23 17:55:21 +000010983 if (name != NULL)
10984 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010985 name = NULL;
10986 if (CUR != ')') {
10987 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010988 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010989 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010990 SKIP_BLANKS;
10991 }
Owen Taylor3473f882001-02-23 17:55:21 +000010992 }
10993 if (CUR != ')') {
10994 if (name != NULL)
10995 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010996 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010997 }
10998 NEXT;
10999 return(name);
11000 }
11001 *test = NODE_TEST_NAME;
11002 if ((!blanks) && (CUR == ':')) {
11003 NEXT;
11004
11005 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011006 * Since currently the parser context don't have a
11007 * namespace list associated:
11008 * The namespace name for this prefix can be computed
11009 * only at evaluation time. The compilation is done
11010 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011011 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011012#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011013 *prefix = xmlXPathNsLookup(ctxt->context, name);
11014 if (name != NULL)
11015 xmlFree(name);
11016 if (*prefix == NULL) {
11017 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11018 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011019#else
11020 *prefix = name;
11021#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011022
11023 if (CUR == '*') {
11024 /*
11025 * All elements
11026 */
11027 NEXT;
11028 *test = NODE_TEST_ALL;
11029 return(NULL);
11030 }
11031
11032 name = xmlXPathParseNCName(ctxt);
11033 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011034 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011035 }
11036 }
11037 return(name);
11038}
11039
11040/**
11041 * xmlXPathIsAxisName:
11042 * @name: a preparsed name token
11043 *
11044 * [6] AxisName ::= 'ancestor'
11045 * | 'ancestor-or-self'
11046 * | 'attribute'
11047 * | 'child'
11048 * | 'descendant'
11049 * | 'descendant-or-self'
11050 * | 'following'
11051 * | 'following-sibling'
11052 * | 'namespace'
11053 * | 'parent'
11054 * | 'preceding'
11055 * | 'preceding-sibling'
11056 * | 'self'
11057 *
11058 * Returns the axis or 0
11059 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011060static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011061xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011062 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011063 switch (name[0]) {
11064 case 'a':
11065 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11066 ret = AXIS_ANCESTOR;
11067 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11068 ret = AXIS_ANCESTOR_OR_SELF;
11069 if (xmlStrEqual(name, BAD_CAST "attribute"))
11070 ret = AXIS_ATTRIBUTE;
11071 break;
11072 case 'c':
11073 if (xmlStrEqual(name, BAD_CAST "child"))
11074 ret = AXIS_CHILD;
11075 break;
11076 case 'd':
11077 if (xmlStrEqual(name, BAD_CAST "descendant"))
11078 ret = AXIS_DESCENDANT;
11079 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11080 ret = AXIS_DESCENDANT_OR_SELF;
11081 break;
11082 case 'f':
11083 if (xmlStrEqual(name, BAD_CAST "following"))
11084 ret = AXIS_FOLLOWING;
11085 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11086 ret = AXIS_FOLLOWING_SIBLING;
11087 break;
11088 case 'n':
11089 if (xmlStrEqual(name, BAD_CAST "namespace"))
11090 ret = AXIS_NAMESPACE;
11091 break;
11092 case 'p':
11093 if (xmlStrEqual(name, BAD_CAST "parent"))
11094 ret = AXIS_PARENT;
11095 if (xmlStrEqual(name, BAD_CAST "preceding"))
11096 ret = AXIS_PRECEDING;
11097 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11098 ret = AXIS_PRECEDING_SIBLING;
11099 break;
11100 case 's':
11101 if (xmlStrEqual(name, BAD_CAST "self"))
11102 ret = AXIS_SELF;
11103 break;
11104 }
11105 return(ret);
11106}
11107
11108/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011109 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011110 * @ctxt: the XPath Parser context
11111 *
11112 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11113 * | AbbreviatedStep
11114 *
11115 * [12] AbbreviatedStep ::= '.' | '..'
11116 *
11117 * [5] AxisSpecifier ::= AxisName '::'
11118 * | AbbreviatedAxisSpecifier
11119 *
11120 * [13] AbbreviatedAxisSpecifier ::= '@'?
11121 *
11122 * Modified for XPtr range support as:
11123 *
11124 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11125 * | AbbreviatedStep
11126 * | 'range-to' '(' Expr ')' Predicate*
11127 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011128 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011129 * A location step of . is short for self::node(). This is
11130 * particularly useful in conjunction with //. For example, the
11131 * location path .//para is short for
11132 * self::node()/descendant-or-self::node()/child::para
11133 * and so will select all para descendant elements of the context
11134 * node.
11135 * Similarly, a location step of .. is short for parent::node().
11136 * For example, ../title is short for parent::node()/child::title
11137 * and so will select the title children of the parent of the context
11138 * node.
11139 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011140static void
11141xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011142#ifdef LIBXML_XPTR_ENABLED
11143 int rangeto = 0;
11144 int op2 = -1;
11145#endif
11146
Owen Taylor3473f882001-02-23 17:55:21 +000011147 SKIP_BLANKS;
11148 if ((CUR == '.') && (NXT(1) == '.')) {
11149 SKIP(2);
11150 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011151 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11152 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011153 } else if (CUR == '.') {
11154 NEXT;
11155 SKIP_BLANKS;
11156 } else {
11157 xmlChar *name = NULL;
11158 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011159 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011160 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011161 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011162 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011163
11164 /*
11165 * The modification needed for XPointer change to the production
11166 */
11167#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011168 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011169 name = xmlXPathParseNCName(ctxt);
11170 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011171 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011172 xmlFree(name);
11173 SKIP_BLANKS;
11174 if (CUR != '(') {
11175 XP_ERROR(XPATH_EXPR_ERROR);
11176 }
11177 NEXT;
11178 SKIP_BLANKS;
11179
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011180 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011181 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011182 CHECK_ERROR;
11183
11184 SKIP_BLANKS;
11185 if (CUR != ')') {
11186 XP_ERROR(XPATH_EXPR_ERROR);
11187 }
11188 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011189 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011190 goto eval_predicates;
11191 }
11192 }
11193#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011194 if (CUR == '*') {
11195 axis = AXIS_CHILD;
11196 } else {
11197 if (name == NULL)
11198 name = xmlXPathParseNCName(ctxt);
11199 if (name != NULL) {
11200 axis = xmlXPathIsAxisName(name);
11201 if (axis != 0) {
11202 SKIP_BLANKS;
11203 if ((CUR == ':') && (NXT(1) == ':')) {
11204 SKIP(2);
11205 xmlFree(name);
11206 name = NULL;
11207 } else {
11208 /* an element name can conflict with an axis one :-\ */
11209 axis = AXIS_CHILD;
11210 }
Owen Taylor3473f882001-02-23 17:55:21 +000011211 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011212 axis = AXIS_CHILD;
11213 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011214 } else if (CUR == '@') {
11215 NEXT;
11216 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011217 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011218 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011219 }
Owen Taylor3473f882001-02-23 17:55:21 +000011220 }
11221
11222 CHECK_ERROR;
11223
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011224 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011225 if (test == 0)
11226 return;
11227
Daniel Veillarded6c5492005-07-23 15:00:22 +000011228 if ((prefix != NULL) && (ctxt->context != NULL) &&
11229 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11230 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11231 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11232 }
11233 }
Owen Taylor3473f882001-02-23 17:55:21 +000011234#ifdef DEBUG_STEP
11235 xmlGenericError(xmlGenericErrorContext,
11236 "Basis : computing new set\n");
11237#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011238
Owen Taylor3473f882001-02-23 17:55:21 +000011239#ifdef DEBUG_STEP
11240 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011241 if (ctxt->value == NULL)
11242 xmlGenericError(xmlGenericErrorContext, "no value\n");
11243 else if (ctxt->value->nodesetval == NULL)
11244 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11245 else
11246 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011247#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011248
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011249#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011250eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011251#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011252 op1 = ctxt->comp->last;
11253 ctxt->comp->last = -1;
11254
Owen Taylor3473f882001-02-23 17:55:21 +000011255 SKIP_BLANKS;
11256 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011257 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011258 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011259
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011260#ifdef LIBXML_XPTR_ENABLED
11261 if (rangeto) {
11262 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11263 } else
11264#endif
11265 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11266 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011267
Owen Taylor3473f882001-02-23 17:55:21 +000011268 }
11269#ifdef DEBUG_STEP
11270 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011271 if (ctxt->value == NULL)
11272 xmlGenericError(xmlGenericErrorContext, "no value\n");
11273 else if (ctxt->value->nodesetval == NULL)
11274 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11275 else
11276 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11277 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011278#endif
11279}
11280
11281/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011282 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011283 * @ctxt: the XPath Parser context
11284 *
11285 * [3] RelativeLocationPath ::= Step
11286 * | RelativeLocationPath '/' Step
11287 * | AbbreviatedRelativeLocationPath
11288 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11289 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011290 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011291 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011292static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011293xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011294(xmlXPathParserContextPtr ctxt) {
11295 SKIP_BLANKS;
11296 if ((CUR == '/') && (NXT(1) == '/')) {
11297 SKIP(2);
11298 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011299 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11300 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011301 } else if (CUR == '/') {
11302 NEXT;
11303 SKIP_BLANKS;
11304 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011305 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011306 SKIP_BLANKS;
11307 while (CUR == '/') {
11308 if ((CUR == '/') && (NXT(1) == '/')) {
11309 SKIP(2);
11310 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011311 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011312 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011313 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011314 } else if (CUR == '/') {
11315 NEXT;
11316 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011317 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011318 }
11319 SKIP_BLANKS;
11320 }
11321}
11322
11323/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011324 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011325 * @ctxt: the XPath Parser context
11326 *
11327 * [1] LocationPath ::= RelativeLocationPath
11328 * | AbsoluteLocationPath
11329 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11330 * | AbbreviatedAbsoluteLocationPath
11331 * [10] AbbreviatedAbsoluteLocationPath ::=
11332 * '//' RelativeLocationPath
11333 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011334 * Compile a location path
11335 *
Owen Taylor3473f882001-02-23 17:55:21 +000011336 * // is short for /descendant-or-self::node()/. For example,
11337 * //para is short for /descendant-or-self::node()/child::para and
11338 * so will select any para element in the document (even a para element
11339 * that is a document element will be selected by //para since the
11340 * document element node is a child of the root node); div//para is
11341 * short for div/descendant-or-self::node()/child::para and so will
11342 * select all para descendants of div children.
11343 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011344static void
11345xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011346 SKIP_BLANKS;
11347 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011348 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011349 } else {
11350 while (CUR == '/') {
11351 if ((CUR == '/') && (NXT(1) == '/')) {
11352 SKIP(2);
11353 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011354 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11355 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011356 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011357 } else if (CUR == '/') {
11358 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011359 SKIP_BLANKS;
11360 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011361 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011362 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011363 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011364 }
11365 }
11366 }
11367}
11368
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011369/************************************************************************
11370 * *
11371 * XPath precompiled expression evaluation *
11372 * *
11373 ************************************************************************/
11374
Daniel Veillardf06307e2001-07-03 10:35:50 +000011375static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011376xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11377
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011378#ifdef DEBUG_STEP
11379static void
11380xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11381 xmlXPathTestVal test,
11382 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011384 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011385 switch (axis) {
11386 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011387 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011388 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011389 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 xmlGenericError(xmlGenericErrorContext,
11391 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011392 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011393 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011394 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011395 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011396 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011397 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011399 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011400 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011401 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011402 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011403 xmlGenericError(xmlGenericErrorContext,
11404 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011405 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011406 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011407 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011408 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011409 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 xmlGenericError(xmlGenericErrorContext,
11411 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011412 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011413 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011414 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011415 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011416 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011417 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011418 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011419 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011420 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011421 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011422 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011423 xmlGenericError(xmlGenericErrorContext,
11424 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011425 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011426 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011427 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011428 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011429 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011430 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011431 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011432 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011433 case NODE_TEST_NONE:
11434 xmlGenericError(xmlGenericErrorContext,
11435 " searching for none !!!\n");
11436 break;
11437 case NODE_TEST_TYPE:
11438 xmlGenericError(xmlGenericErrorContext,
11439 " searching for type %d\n", type);
11440 break;
11441 case NODE_TEST_PI:
11442 xmlGenericError(xmlGenericErrorContext,
11443 " searching for PI !!!\n");
11444 break;
11445 case NODE_TEST_ALL:
11446 xmlGenericError(xmlGenericErrorContext,
11447 " searching for *\n");
11448 break;
11449 case NODE_TEST_NS:
11450 xmlGenericError(xmlGenericErrorContext,
11451 " searching for namespace %s\n",
11452 prefix);
11453 break;
11454 case NODE_TEST_NAME:
11455 xmlGenericError(xmlGenericErrorContext,
11456 " searching for name %s\n", name);
11457 if (prefix != NULL)
11458 xmlGenericError(xmlGenericErrorContext,
11459 " with namespace %s\n", prefix);
11460 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011461 }
11462 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011463}
11464#endif /* DEBUG_STEP */
11465
11466static int
11467xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11468 xmlXPathStepOpPtr op,
11469 xmlNodeSetPtr set,
11470 int contextSize,
11471 int hasNsNodes)
11472{
11473 if (op->ch1 != -1) {
11474 xmlXPathCompExprPtr comp = ctxt->comp;
11475 /*
11476 * Process inner predicates first.
11477 */
11478 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11479 /*
11480 * TODO: raise an internal error.
11481 */
11482 }
11483 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11484 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11485 CHECK_ERROR0;
11486 if (contextSize <= 0)
11487 return(0);
11488 }
11489 if (op->ch2 != -1) {
11490 xmlXPathContextPtr xpctxt = ctxt->context;
11491 xmlNodePtr contextNode, oldContextNode;
11492 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011493 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011494 xmlXPathStepOpPtr exprOp;
11495 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11496
11497#ifdef LIBXML_XPTR_ENABLED
11498 /*
11499 * URGENT TODO: Check the following:
11500 * We don't expect location sets if evaluating prediates, right?
11501 * Only filters should expect location sets, right?
11502 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011503#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011504 /*
11505 * SPEC XPath 1.0:
11506 * "For each node in the node-set to be filtered, the
11507 * PredicateExpr is evaluated with that node as the
11508 * context node, with the number of nodes in the
11509 * node-set as the context size, and with the proximity
11510 * position of the node in the node-set with respect to
11511 * the axis as the context position;"
11512 * @oldset is the node-set" to be filtered.
11513 *
11514 * SPEC XPath 1.0:
11515 * "only predicates change the context position and
11516 * context size (see [2.4 Predicates])."
11517 * Example:
11518 * node-set context pos
11519 * nA 1
11520 * nB 2
11521 * nC 3
11522 * After applying predicate [position() > 1] :
11523 * node-set context pos
11524 * nB 1
11525 * nC 2
11526 */
11527 oldContextNode = xpctxt->node;
11528 oldContextDoc = xpctxt->doc;
11529 /*
11530 * Get the expression of this predicate.
11531 */
11532 exprOp = &ctxt->comp->steps[op->ch2];
11533 newContextSize = 0;
11534 for (i = 0; i < set->nodeNr; i++) {
11535 if (set->nodeTab[i] == NULL)
11536 continue;
11537
11538 contextNode = set->nodeTab[i];
11539 xpctxt->node = contextNode;
11540 xpctxt->contextSize = contextSize;
11541 xpctxt->proximityPosition = ++contextPos;
11542
11543 /*
11544 * Also set the xpath document in case things like
11545 * key() are evaluated in the predicate.
11546 */
11547 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11548 (contextNode->doc != NULL))
11549 xpctxt->doc = contextNode->doc;
11550 /*
11551 * Evaluate the predicate expression with 1 context node
11552 * at a time; this node is packaged into a node set; this
11553 * node set is handed over to the evaluation mechanism.
11554 */
11555 if (contextObj == NULL)
11556 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11557 else
11558 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11559 contextNode);
11560
11561 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011562
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011563 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011564
William M. Brack0bcec062007-02-14 02:15:19 +000011565 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11566 xmlXPathNodeSetClear(set, hasNsNodes);
11567 newContextSize = 0;
11568 goto evaluation_exit;
11569 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011570
11571 if (res != 0) {
11572 newContextSize++;
11573 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011574 /*
11575 * Remove the entry from the initial node set.
11576 */
11577 set->nodeTab[i] = NULL;
11578 if (contextNode->type == XML_NAMESPACE_DECL)
11579 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011580 }
11581 if (ctxt->value == contextObj) {
11582 /*
11583 * Don't free the temporary XPath object holding the
11584 * context node, in order to avoid massive recreation
11585 * inside this loop.
11586 */
11587 valuePop(ctxt);
11588 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11589 } else {
11590 /*
11591 * TODO: The object was lost in the evaluation machinery.
11592 * Can this happen? Maybe in internal-error cases.
11593 */
11594 contextObj = NULL;
11595 }
11596 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011597
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011598 if (contextObj != NULL) {
11599 if (ctxt->value == contextObj)
11600 valuePop(ctxt);
11601 xmlXPathReleaseObject(xpctxt, contextObj);
11602 }
William M. Brack0bcec062007-02-14 02:15:19 +000011603evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011604 if (exprRes != NULL)
11605 xmlXPathReleaseObject(ctxt->context, exprRes);
11606 /*
11607 * Reset/invalidate the context.
11608 */
11609 xpctxt->node = oldContextNode;
11610 xpctxt->doc = oldContextDoc;
11611 xpctxt->contextSize = -1;
11612 xpctxt->proximityPosition = -1;
11613 return(newContextSize);
11614 }
11615 return(contextSize);
11616}
11617
11618static int
11619xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11620 xmlXPathStepOpPtr op,
11621 xmlNodeSetPtr set,
11622 int contextSize,
11623 int minPos,
11624 int maxPos,
11625 int hasNsNodes)
11626{
11627 if (op->ch1 != -1) {
11628 xmlXPathCompExprPtr comp = ctxt->comp;
11629 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11630 /*
11631 * TODO: raise an internal error.
11632 */
11633 }
11634 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11635 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11636 CHECK_ERROR0;
11637 if (contextSize <= 0)
11638 return(0);
11639 }
11640 /*
11641 * Check if the node set contains a sufficient number of nodes for
11642 * the requested range.
11643 */
11644 if (contextSize < minPos) {
11645 xmlXPathNodeSetClear(set, hasNsNodes);
11646 return(0);
11647 }
11648 if (op->ch2 == -1) {
11649 /*
11650 * TODO: Can this ever happen?
11651 */
11652 return (contextSize);
11653 } else {
11654 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011655 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011656 xmlXPathStepOpPtr exprOp;
11657 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11658 xmlNodePtr oldContextNode, contextNode = NULL;
11659 xmlXPathContextPtr xpctxt = ctxt->context;
11660
11661#ifdef LIBXML_XPTR_ENABLED
11662 /*
11663 * URGENT TODO: Check the following:
11664 * We don't expect location sets if evaluating prediates, right?
11665 * Only filters should expect location sets, right?
11666 */
11667#endif /* LIBXML_XPTR_ENABLED */
11668
11669 /*
11670 * Save old context.
11671 */
11672 oldContextNode = xpctxt->node;
11673 oldContextDoc = xpctxt->doc;
11674 /*
11675 * Get the expression of this predicate.
11676 */
11677 exprOp = &ctxt->comp->steps[op->ch2];
11678 for (i = 0; i < set->nodeNr; i++) {
11679 if (set->nodeTab[i] == NULL)
11680 continue;
11681
11682 contextNode = set->nodeTab[i];
11683 xpctxt->node = contextNode;
11684 xpctxt->contextSize = contextSize;
11685 xpctxt->proximityPosition = ++contextPos;
11686
11687 /*
11688 * Initialize the new set.
11689 * Also set the xpath document in case things like
11690 * key() evaluation are attempted on the predicate
11691 */
11692 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11693 (contextNode->doc != NULL))
11694 xpctxt->doc = contextNode->doc;
11695 /*
11696 * Evaluate the predicate expression with 1 context node
11697 * at a time; this node is packaged into a node set; this
11698 * node set is handed over to the evaluation mechanism.
11699 */
11700 if (contextObj == NULL)
11701 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11702 else
11703 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11704 contextNode);
11705
11706 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011707 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011708
11709 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011710 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011711
11712 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011713 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011714
11715 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011716 /*
11717 * Fits in the requested range.
11718 */
11719 newContextSize++;
11720 if (minPos == maxPos) {
11721 /*
11722 * Only 1 node was requested.
11723 */
11724 if (contextNode->type == XML_NAMESPACE_DECL) {
11725 /*
11726 * As always: take care of those nasty
11727 * namespace nodes.
11728 */
11729 set->nodeTab[i] = NULL;
11730 }
11731 xmlXPathNodeSetClear(set, hasNsNodes);
11732 set->nodeNr = 1;
11733 set->nodeTab[0] = contextNode;
11734 goto evaluation_exit;
11735 }
11736 if (pos == maxPos) {
11737 /*
11738 * We are done.
11739 */
11740 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11741 goto evaluation_exit;
11742 }
11743 } else {
11744 /*
11745 * Remove the entry from the initial node set.
11746 */
11747 set->nodeTab[i] = NULL;
11748 if (contextNode->type == XML_NAMESPACE_DECL)
11749 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11750 }
11751 if (exprRes != NULL) {
11752 xmlXPathReleaseObject(ctxt->context, exprRes);
11753 exprRes = NULL;
11754 }
11755 if (ctxt->value == contextObj) {
11756 /*
11757 * Don't free the temporary XPath object holding the
11758 * context node, in order to avoid massive recreation
11759 * inside this loop.
11760 */
11761 valuePop(ctxt);
11762 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11763 } else {
11764 /*
11765 * The object was lost in the evaluation machinery.
11766 * Can this happen? Maybe in case of internal-errors.
11767 */
11768 contextObj = NULL;
11769 }
11770 }
11771 goto evaluation_exit;
11772
11773evaluation_error:
11774 xmlXPathNodeSetClear(set, hasNsNodes);
11775 newContextSize = 0;
11776
11777evaluation_exit:
11778 if (contextObj != NULL) {
11779 if (ctxt->value == contextObj)
11780 valuePop(ctxt);
11781 xmlXPathReleaseObject(xpctxt, contextObj);
11782 }
11783 if (exprRes != NULL)
11784 xmlXPathReleaseObject(ctxt->context, exprRes);
11785 /*
11786 * Reset/invalidate the context.
11787 */
11788 xpctxt->node = oldContextNode;
11789 xpctxt->doc = oldContextDoc;
11790 xpctxt->contextSize = -1;
11791 xpctxt->proximityPosition = -1;
11792 return(newContextSize);
11793 }
11794 return(contextSize);
11795}
11796
11797static int
11798xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11799 xmlXPathStepOpPtr op,
11800 int *maxPos)
11801{
11802
11803 xmlXPathStepOpPtr exprOp;
11804
11805 /*
11806 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11807 */
11808
11809 /*
11810 * If not -1, then ch1 will point to:
11811 * 1) For predicates (XPATH_OP_PREDICATE):
11812 * - an inner predicate operator
11813 * 2) For filters (XPATH_OP_FILTER):
11814 * - an inner filter operater OR
11815 * - an expression selecting the node set.
11816 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11817 */
11818 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11819 return(0);
11820
11821 if (op->ch2 != -1) {
11822 exprOp = &ctxt->comp->steps[op->ch2];
11823 } else
11824 return(0);
11825
11826 if ((exprOp != NULL) &&
11827 (exprOp->op == XPATH_OP_VALUE) &&
11828 (exprOp->value4 != NULL) &&
11829 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11830 {
11831 /*
11832 * We have a "[n]" predicate here.
11833 * TODO: Unfortunately this simplistic test here is not
11834 * able to detect a position() predicate in compound
11835 * expressions like "[@attr = 'a" and position() = 1],
11836 * and even not the usage of position() in
11837 * "[position() = 1]"; thus - obviously - a position-range,
11838 * like it "[position() < 5]", is also not detected.
11839 * Maybe we could rewrite the AST to ease the optimization.
11840 */
11841 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11842
11843 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11844 (float) *maxPos)
11845 {
11846 return(1);
11847 }
11848 }
11849 return(0);
11850}
11851
11852static int
11853xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11854 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011855 xmlNodePtr * first, xmlNodePtr * last,
11856 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011857{
11858
11859#define XP_TEST_HIT \
11860 if (hasAxisRange != 0) { \
11861 if (++pos == maxPos) { \
11862 addNode(seq, cur); \
11863 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011864 } else { \
11865 addNode(seq, cur); \
11866 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011867
11868#define XP_TEST_HIT_NS \
11869 if (hasAxisRange != 0) { \
11870 if (++pos == maxPos) { \
11871 hasNsNodes = 1; \
11872 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11873 goto axis_range_end; } \
11874 } else { \
11875 hasNsNodes = 1; \
11876 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011877 xpctxt->node, (xmlNsPtr) cur); \
11878 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011879
11880 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11881 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11882 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11883 const xmlChar *prefix = op->value4;
11884 const xmlChar *name = op->value5;
11885 const xmlChar *URI = NULL;
11886
11887#ifdef DEBUG_STEP
11888 int nbMatches = 0, prevMatches = 0;
11889#endif
11890 int total = 0, hasNsNodes = 0;
11891 /* The popped object holding the context nodes */
11892 xmlXPathObjectPtr obj;
11893 /* The set of context nodes for the node tests */
11894 xmlNodeSetPtr contextSeq;
11895 int contextIdx;
11896 xmlNodePtr contextNode;
11897 /* The context node for a compound traversal */
11898 xmlNodePtr outerContextNode;
11899 /* The final resulting node set wrt to all context nodes */
11900 xmlNodeSetPtr outSeq;
11901 /*
11902 * The temporary resulting node set wrt 1 context node.
11903 * Used to feed predicate evaluation.
11904 */
11905 xmlNodeSetPtr seq;
11906 xmlNodePtr cur;
11907 /* First predicate operator */
11908 xmlXPathStepOpPtr predOp;
11909 int maxPos; /* The requested position() (when a "[n]" predicate) */
11910 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011911 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011912
11913 xmlXPathTraversalFunction next = NULL;
11914 /* compound axis traversal */
11915 xmlXPathTraversalFunctionExt outerNext = NULL;
11916 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11917 xmlXPathNodeSetMergeFunction mergeAndClear;
11918 xmlNodePtr oldContextNode;
11919 xmlXPathContextPtr xpctxt = ctxt->context;
11920
11921
11922 CHECK_TYPE0(XPATH_NODESET);
11923 obj = valuePop(ctxt);
11924 /*
11925 * Setup namespaces.
11926 */
11927 if (prefix != NULL) {
11928 URI = xmlXPathNsLookup(xpctxt, prefix);
11929 if (URI == NULL) {
11930 xmlXPathReleaseObject(xpctxt, obj);
11931 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11932 }
11933 }
11934 /*
11935 * Setup axis.
11936 *
11937 * MAYBE FUTURE TODO: merging optimizations:
11938 * - If the nodes to be traversed wrt to the initial nodes and
11939 * the current axis cannot overlap, then we could avoid searching
11940 * for duplicates during the merge.
11941 * But the question is how/when to evaluate if they cannot overlap.
11942 * Example: if we know that for two initial nodes, the one is
11943 * not in the ancestor-or-self axis of the other, then we could safely
11944 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11945 * the descendant-or-self axis.
11946 */
11947 addNode = xmlXPathNodeSetAdd;
11948 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11949 switch (axis) {
11950 case AXIS_ANCESTOR:
11951 first = NULL;
11952 next = xmlXPathNextAncestor;
11953 break;
11954 case AXIS_ANCESTOR_OR_SELF:
11955 first = NULL;
11956 next = xmlXPathNextAncestorOrSelf;
11957 break;
11958 case AXIS_ATTRIBUTE:
11959 first = NULL;
11960 last = NULL;
11961 next = xmlXPathNextAttribute;
11962 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11963 break;
11964 case AXIS_CHILD:
11965 last = NULL;
11966 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11967 /*
11968 * This iterator will give us only nodes which can
11969 * hold element nodes.
11970 */
11971 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11972 }
11973 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11974 (type == NODE_TYPE_NODE))
11975 {
11976 /*
11977 * Optimization if an element node type is 'element'.
11978 */
11979 next = xmlXPathNextChildElement;
11980 } else
11981 next = xmlXPathNextChild;
11982 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11983 break;
11984 case AXIS_DESCENDANT:
11985 last = NULL;
11986 next = xmlXPathNextDescendant;
11987 break;
11988 case AXIS_DESCENDANT_OR_SELF:
11989 last = NULL;
11990 next = xmlXPathNextDescendantOrSelf;
11991 break;
11992 case AXIS_FOLLOWING:
11993 last = NULL;
11994 next = xmlXPathNextFollowing;
11995 break;
11996 case AXIS_FOLLOWING_SIBLING:
11997 last = NULL;
11998 next = xmlXPathNextFollowingSibling;
11999 break;
12000 case AXIS_NAMESPACE:
12001 first = NULL;
12002 last = NULL;
12003 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12004 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12005 break;
12006 case AXIS_PARENT:
12007 first = NULL;
12008 next = xmlXPathNextParent;
12009 break;
12010 case AXIS_PRECEDING:
12011 first = NULL;
12012 next = xmlXPathNextPrecedingInternal;
12013 break;
12014 case AXIS_PRECEDING_SIBLING:
12015 first = NULL;
12016 next = xmlXPathNextPrecedingSibling;
12017 break;
12018 case AXIS_SELF:
12019 first = NULL;
12020 last = NULL;
12021 next = xmlXPathNextSelf;
12022 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12023 break;
12024 }
12025
12026#ifdef DEBUG_STEP
12027 xmlXPathDebugDumpStepAxis(axis, test,
12028 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12029#endif
12030
12031 if (next == NULL) {
12032 xmlXPathReleaseObject(xpctxt, obj);
12033 return(0);
12034 }
12035 contextSeq = obj->nodesetval;
12036 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12037 xmlXPathReleaseObject(xpctxt, obj);
12038 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12039 return(0);
12040 }
12041 /*
12042 * Predicate optimization ---------------------------------------------
12043 * If this step has a last predicate, which contains a position(),
12044 * then we'll optimize (although not exactly "position()", but only
12045 * the short-hand form, i.e., "[n]".
12046 *
12047 * Example - expression "/foo[parent::bar][1]":
12048 *
12049 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12050 * ROOT -- op->ch1
12051 * PREDICATE -- op->ch2 (predOp)
12052 * PREDICATE -- predOp->ch1 = [parent::bar]
12053 * SORT
12054 * COLLECT 'parent' 'name' 'node' bar
12055 * NODE
12056 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12057 *
12058 */
12059 maxPos = 0;
12060 predOp = NULL;
12061 hasPredicateRange = 0;
12062 hasAxisRange = 0;
12063 if (op->ch2 != -1) {
12064 /*
12065 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12066 */
12067 predOp = &ctxt->comp->steps[op->ch2];
12068 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12069 if (predOp->ch1 != -1) {
12070 /*
12071 * Use the next inner predicate operator.
12072 */
12073 predOp = &ctxt->comp->steps[predOp->ch1];
12074 hasPredicateRange = 1;
12075 } else {
12076 /*
12077 * There's no other predicate than the [n] predicate.
12078 */
12079 predOp = NULL;
12080 hasAxisRange = 1;
12081 }
12082 }
12083 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012084 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012085 /*
12086 * Axis traversal -----------------------------------------------------
12087 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012088 /*
12089 * 2.3 Node Tests
12090 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012091 * - For the namespace axis, the principal node type is namespace.
12092 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012093 *
12094 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012095 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012096 * select all element children of the context node
12097 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012098 oldContextNode = xpctxt->node;
12099 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012100 outSeq = NULL;
12101 seq = NULL;
12102 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012103 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012104 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012105
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012106
12107 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12108 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012109 /*
12110 * This is a compound traversal.
12111 */
12112 if (contextNode == NULL) {
12113 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012115 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012116 outerContextNode = contextSeq->nodeTab[contextIdx++];
12117 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012118 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012119 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012120 if (contextNode == NULL)
12121 continue;
12122 /*
12123 * Set the context for the main traversal.
12124 */
12125 xpctxt->node = contextNode;
12126 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012127 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012128
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012129 if (seq == NULL) {
12130 seq = xmlXPathNodeSetCreate(NULL);
12131 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012132 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012133 goto error;
12134 }
12135 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012136 /*
12137 * Traverse the axis and test the nodes.
12138 */
12139 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012140 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012141 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012142 do {
12143 cur = next(ctxt, cur);
12144 if (cur == NULL)
12145 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012146
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012147 /*
12148 * QUESTION TODO: What does the "first" and "last" stuff do?
12149 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012150 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012151 if (*first == cur)
12152 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012153 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012154#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012155 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012156#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012157 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012158#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012159 {
12160 break;
12161 }
12162 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012163 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012164 if (*last == cur)
12165 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012166 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012167#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012168 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012169#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012170 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012171#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012172 {
12173 break;
12174 }
12175 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012176
12177 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012178
Daniel Veillardf06307e2001-07-03 10:35:50 +000012179#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012180 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12181#endif
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012182
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012183 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012184 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012185 total = 0;
12186 STRANGE
12187 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012188 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012189 /*
12190 * TODO: Don't we need to use
12191 * xmlXPathNodeSetAddNs() for namespace nodes here?
12192 * Surprisingly, some c14n tests fail, if we do this.
12193 */
12194 if (type == NODE_TYPE_NODE) {
12195 switch (cur->type) {
12196 case XML_DOCUMENT_NODE:
12197 case XML_HTML_DOCUMENT_NODE:
12198#ifdef LIBXML_DOCB_ENABLED
12199 case XML_DOCB_DOCUMENT_NODE:
12200#endif
12201 case XML_ELEMENT_NODE:
12202 case XML_ATTRIBUTE_NODE:
12203 case XML_PI_NODE:
12204 case XML_COMMENT_NODE:
12205 case XML_CDATA_SECTION_NODE:
12206 case XML_TEXT_NODE:
12207 case XML_NAMESPACE_DECL:
12208 XP_TEST_HIT
12209 break;
12210 default:
12211 break;
12212 }
12213 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012214 if (type == XML_NAMESPACE_DECL)
12215 XP_TEST_HIT_NS
12216 else
12217 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012218 } else if ((type == NODE_TYPE_TEXT) &&
12219 (cur->type == XML_CDATA_SECTION_NODE))
12220 {
12221 XP_TEST_HIT
12222 }
12223 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012224 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012225 if ((cur->type == XML_PI_NODE) &&
12226 ((name == NULL) || xmlStrEqual(name, cur->name)))
12227 {
12228 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012229 }
12230 break;
12231 case NODE_TEST_ALL:
12232 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012233 if (cur->type == XML_ATTRIBUTE_NODE)
12234 {
12235 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012236 }
12237 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012238 if (cur->type == XML_NAMESPACE_DECL)
12239 {
12240 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012241 }
12242 } else {
12243 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012244 if (prefix == NULL)
12245 {
12246 XP_TEST_HIT
12247
Daniel Veillardf06307e2001-07-03 10:35:50 +000012248 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012249 (xmlStrEqual(URI, cur->ns->href)))
12250 {
12251 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012252 }
12253 }
12254 }
12255 break;
12256 case NODE_TEST_NS:{
12257 TODO;
12258 break;
12259 }
12260 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012261 if (axis == AXIS_ATTRIBUTE) {
12262 if (cur->type != XML_ATTRIBUTE_NODE)
12263 break;
12264 } else if (axis == AXIS_NAMESPACE) {
12265 if (cur->type != XML_NAMESPACE_DECL)
12266 break;
12267 } else {
12268 if (cur->type != XML_ELEMENT_NODE)
12269 break;
12270 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012271 switch (cur->type) {
12272 case XML_ELEMENT_NODE:
12273 if (xmlStrEqual(name, cur->name)) {
12274 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012275 if (cur->ns == NULL)
12276 {
12277 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012278 }
12279 } else {
12280 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012281 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012282 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012283 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012284 }
12285 }
12286 }
12287 break;
12288 case XML_ATTRIBUTE_NODE:{
12289 xmlAttrPtr attr = (xmlAttrPtr) cur;
12290
12291 if (xmlStrEqual(name, attr->name)) {
12292 if (prefix == NULL) {
12293 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012294 (attr->ns->prefix == NULL))
12295 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012296 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012297 }
12298 } else {
12299 if ((attr->ns != NULL) &&
12300 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012301 attr->ns->href)))
12302 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012303 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012304 }
12305 }
12306 }
12307 break;
12308 }
12309 case XML_NAMESPACE_DECL:
12310 if (cur->type == XML_NAMESPACE_DECL) {
12311 xmlNsPtr ns = (xmlNsPtr) cur;
12312
12313 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012314 && (xmlStrEqual(ns->prefix, name)))
12315 {
12316 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012317 }
12318 }
12319 break;
12320 default:
12321 break;
12322 }
12323 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012324 } /* switch(test) */
12325 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012326
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012327 goto apply_predicates;
12328
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012329axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012330 /*
12331 * We have a "/foo[n]", and position() = n was reached.
12332 * Note that we can have as well "/foo/::parent::foo[1]", so
12333 * a duplicate-aware merge is still needed.
12334 * Merge with the result.
12335 */
12336 if (outSeq == NULL) {
12337 outSeq = seq;
12338 seq = NULL;
12339 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012340 outSeq = mergeAndClear(outSeq, seq, 0);
12341 /*
12342 * Break if only a true/false result was requested.
12343 */
12344 if (toBool)
12345 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012346 continue;
12347
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012348first_hit: /* ---------------------------------------------------------- */
12349 /*
12350 * Break if only a true/false result was requested and
12351 * no predicates existed and a node test succeeded.
12352 */
12353 if (outSeq == NULL) {
12354 outSeq = seq;
12355 seq = NULL;
12356 } else
12357 outSeq = mergeAndClear(outSeq, seq, 0);
12358 break;
12359
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012360#ifdef DEBUG_STEP
12361 if (seq != NULL)
12362 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012363#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012364
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012365apply_predicates: /* --------------------------------------------------- */
12366 /*
12367 * Apply predicates.
12368 */
12369 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12370 /*
12371 * E.g. when we have a "/foo[some expression][n]".
12372 */
12373 /*
12374 * QUESTION TODO: The old predicate evaluation took into
12375 * account location-sets.
12376 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12377 * Do we expect such a set here?
12378 * All what I learned now from the evaluation semantics
12379 * does not indicate that a location-set will be processed
12380 * here, so this looks OK.
12381 */
12382 /*
12383 * Iterate over all predicates, starting with the outermost
12384 * predicate.
12385 * TODO: Problem: we cannot execute the inner predicates first
12386 * since we cannot go back *up* the operator tree!
12387 * Options we have:
12388 * 1) Use of recursive functions (like is it currently done
12389 * via xmlXPathCompOpEval())
12390 * 2) Add a predicate evaluation information stack to the
12391 * context struct
12392 * 3) Change the way the operators are linked; we need a
12393 * "parent" field on xmlXPathStepOp
12394 *
12395 * For the moment, I'll try to solve this with a recursive
12396 * function: xmlXPathCompOpEvalPredicate().
12397 */
12398 size = seq->nodeNr;
12399 if (hasPredicateRange != 0)
12400 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12401 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12402 else
12403 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12404 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012405
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012406 if (ctxt->error != XPATH_EXPRESSION_OK) {
12407 total = 0;
12408 goto error;
12409 }
12410 /*
12411 * Add the filtered set of nodes to the result node set.
12412 */
12413 if (newSize == 0) {
12414 /*
12415 * The predicates filtered all nodes out.
12416 */
12417 xmlXPathNodeSetClear(seq, hasNsNodes);
12418 } else if (seq->nodeNr > 0) {
12419 /*
12420 * Add to result set.
12421 */
12422 if (outSeq == NULL) {
12423 if (size != newSize) {
12424 /*
12425 * We need to merge and clear here, since
12426 * the sequence will contained NULLed entries.
12427 */
12428 outSeq = mergeAndClear(NULL, seq, 1);
12429 } else {
12430 outSeq = seq;
12431 seq = NULL;
12432 }
12433 } else
12434 outSeq = mergeAndClear(outSeq, seq,
12435 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012436 /*
12437 * Break if only a true/false result was requested.
12438 */
12439 if (toBool)
12440 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012441 }
12442 } else if (seq->nodeNr > 0) {
12443 /*
12444 * Add to result set.
12445 */
12446 if (outSeq == NULL) {
12447 outSeq = seq;
12448 seq = NULL;
12449 } else {
12450 outSeq = mergeAndClear(outSeq, seq, 0);
12451 }
12452 }
12453 }
12454
12455error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012456 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012457 /*
12458 * QUESTION TODO: What does this do and why?
12459 * TODO: Do we have to do this also for the "error"
12460 * cleanup further down?
12461 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012462 ctxt->value->boolval = 1;
12463 ctxt->value->user = obj->user;
12464 obj->user = NULL;
12465 obj->boolval = 0;
12466 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012467 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012468
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012469 /*
12470 * Ensure we return at least an emtpy set.
12471 */
12472 if (outSeq == NULL) {
12473 if ((seq != NULL) && (seq->nodeNr == 0))
12474 outSeq = seq;
12475 else
12476 outSeq = xmlXPathNodeSetCreate(NULL);
12477 }
12478 if ((seq != NULL) && (seq != outSeq)) {
12479 xmlXPathFreeNodeSet(seq);
12480 }
12481 /*
12482 * Hand over the result. Better to push the set also in
12483 * case of errors.
12484 */
12485 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12486 /*
12487 * Reset the context node.
12488 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012489 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012490
12491#ifdef DEBUG_STEP
12492 xmlGenericError(xmlGenericErrorContext,
12493 "\nExamined %d nodes, found %d nodes at that step\n",
12494 total, nbMatches);
12495#endif
12496
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012497 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012498}
12499
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012500static int
12501xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12502 xmlXPathStepOpPtr op, xmlNodePtr * first);
12503
Daniel Veillardf06307e2001-07-03 10:35:50 +000012504/**
12505 * xmlXPathCompOpEvalFirst:
12506 * @ctxt: the XPath parser context with the compiled expression
12507 * @op: an XPath compiled operation
12508 * @first: the first elem found so far
12509 *
12510 * Evaluate the Precompiled XPath operation searching only the first
12511 * element in document order
12512 *
12513 * Returns the number of examined objects.
12514 */
12515static int
12516xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12517 xmlXPathStepOpPtr op, xmlNodePtr * first)
12518{
12519 int total = 0, cur;
12520 xmlXPathCompExprPtr comp;
12521 xmlXPathObjectPtr arg1, arg2;
12522
Daniel Veillard556c6682001-10-06 09:59:51 +000012523 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012524 comp = ctxt->comp;
12525 switch (op->op) {
12526 case XPATH_OP_END:
12527 return (0);
12528 case XPATH_OP_UNION:
12529 total =
12530 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12531 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012532 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012533 if ((ctxt->value != NULL)
12534 && (ctxt->value->type == XPATH_NODESET)
12535 && (ctxt->value->nodesetval != NULL)
12536 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12537 /*
12538 * limit tree traversing to first node in the result
12539 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012540 /*
12541 * OPTIMIZE TODO: This implicitely sorts
12542 * the result, even if not needed. E.g. if the argument
12543 * of the count() function, no sorting is needed.
12544 * OPTIMIZE TODO: How do we know if the node-list wasn't
12545 * aready sorted?
12546 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012547 if (ctxt->value->nodesetval->nodeNr > 1)
12548 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012549 *first = ctxt->value->nodesetval->nodeTab[0];
12550 }
12551 cur =
12552 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12553 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012554 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012555 CHECK_TYPE0(XPATH_NODESET);
12556 arg2 = valuePop(ctxt);
12557
12558 CHECK_TYPE0(XPATH_NODESET);
12559 arg1 = valuePop(ctxt);
12560
12561 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12562 arg2->nodesetval);
12563 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012564 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012565 /* optimizer */
12566 if (total > cur)
12567 xmlXPathCompSwap(op);
12568 return (total + cur);
12569 case XPATH_OP_ROOT:
12570 xmlXPathRoot(ctxt);
12571 return (0);
12572 case XPATH_OP_NODE:
12573 if (op->ch1 != -1)
12574 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012575 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012576 if (op->ch2 != -1)
12577 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012578 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012579 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12580 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012581 return (total);
12582 case XPATH_OP_RESET:
12583 if (op->ch1 != -1)
12584 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012585 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012586 if (op->ch2 != -1)
12587 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012588 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012589 ctxt->context->node = NULL;
12590 return (total);
12591 case XPATH_OP_COLLECT:{
12592 if (op->ch1 == -1)
12593 return (total);
12594
12595 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012596 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012597
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012598 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012599 return (total);
12600 }
12601 case XPATH_OP_VALUE:
12602 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012603 xmlXPathCacheObjectCopy(ctxt->context,
12604 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012605 return (0);
12606 case XPATH_OP_SORT:
12607 if (op->ch1 != -1)
12608 total +=
12609 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12610 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012611 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012612 if ((ctxt->value != NULL)
12613 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012614 && (ctxt->value->nodesetval != NULL)
12615 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012616 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12617 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012618#ifdef XP_OPTIMIZED_FILTER_FIRST
12619 case XPATH_OP_FILTER:
12620 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12621 return (total);
12622#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012623 default:
12624 return (xmlXPathCompOpEval(ctxt, op));
12625 }
12626}
12627
12628/**
12629 * xmlXPathCompOpEvalLast:
12630 * @ctxt: the XPath parser context with the compiled expression
12631 * @op: an XPath compiled operation
12632 * @last: the last elem found so far
12633 *
12634 * Evaluate the Precompiled XPath operation searching only the last
12635 * element in document order
12636 *
William M. Brack08171912003-12-29 02:52:11 +000012637 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012638 */
12639static int
12640xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12641 xmlNodePtr * last)
12642{
12643 int total = 0, cur;
12644 xmlXPathCompExprPtr comp;
12645 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012646 xmlNodePtr bak;
12647 xmlDocPtr bakd;
12648 int pp;
12649 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012650
Daniel Veillard556c6682001-10-06 09:59:51 +000012651 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012652 comp = ctxt->comp;
12653 switch (op->op) {
12654 case XPATH_OP_END:
12655 return (0);
12656 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012657 bakd = ctxt->context->doc;
12658 bak = ctxt->context->node;
12659 pp = ctxt->context->proximityPosition;
12660 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012661 total =
12662 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012663 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012664 if ((ctxt->value != NULL)
12665 && (ctxt->value->type == XPATH_NODESET)
12666 && (ctxt->value->nodesetval != NULL)
12667 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12668 /*
12669 * limit tree traversing to first node in the result
12670 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012671 if (ctxt->value->nodesetval->nodeNr > 1)
12672 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012673 *last =
12674 ctxt->value->nodesetval->nodeTab[ctxt->value->
12675 nodesetval->nodeNr -
12676 1];
12677 }
William M. Brackce4fc562004-01-22 02:47:18 +000012678 ctxt->context->doc = bakd;
12679 ctxt->context->node = bak;
12680 ctxt->context->proximityPosition = pp;
12681 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012682 cur =
12683 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 if ((ctxt->value != NULL)
12686 && (ctxt->value->type == XPATH_NODESET)
12687 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012688 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012689 }
12690 CHECK_TYPE0(XPATH_NODESET);
12691 arg2 = valuePop(ctxt);
12692
12693 CHECK_TYPE0(XPATH_NODESET);
12694 arg1 = valuePop(ctxt);
12695
12696 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12697 arg2->nodesetval);
12698 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012699 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012700 /* optimizer */
12701 if (total > cur)
12702 xmlXPathCompSwap(op);
12703 return (total + cur);
12704 case XPATH_OP_ROOT:
12705 xmlXPathRoot(ctxt);
12706 return (0);
12707 case XPATH_OP_NODE:
12708 if (op->ch1 != -1)
12709 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012710 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012711 if (op->ch2 != -1)
12712 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012713 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012714 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12715 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012716 return (total);
12717 case XPATH_OP_RESET:
12718 if (op->ch1 != -1)
12719 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012720 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012721 if (op->ch2 != -1)
12722 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012723 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012724 ctxt->context->node = NULL;
12725 return (total);
12726 case XPATH_OP_COLLECT:{
12727 if (op->ch1 == -1)
12728 return (0);
12729
12730 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012731 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012732
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012733 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012734 return (total);
12735 }
12736 case XPATH_OP_VALUE:
12737 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012738 xmlXPathCacheObjectCopy(ctxt->context,
12739 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012740 return (0);
12741 case XPATH_OP_SORT:
12742 if (op->ch1 != -1)
12743 total +=
12744 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12745 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012746 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012747 if ((ctxt->value != NULL)
12748 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012749 && (ctxt->value->nodesetval != NULL)
12750 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012751 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12752 return (total);
12753 default:
12754 return (xmlXPathCompOpEval(ctxt, op));
12755 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012756}
12757
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012758#ifdef XP_OPTIMIZED_FILTER_FIRST
12759static int
12760xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12761 xmlXPathStepOpPtr op, xmlNodePtr * first)
12762{
12763 int total = 0;
12764 xmlXPathCompExprPtr comp;
12765 xmlXPathObjectPtr res;
12766 xmlXPathObjectPtr obj;
12767 xmlNodeSetPtr oldset;
12768 xmlNodePtr oldnode;
12769 xmlDocPtr oldDoc;
12770 int i;
12771
12772 CHECK_ERROR0;
12773 comp = ctxt->comp;
12774 /*
12775 * Optimization for ()[last()] selection i.e. the last elem
12776 */
12777 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12778 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12779 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12780 int f = comp->steps[op->ch2].ch1;
12781
12782 if ((f != -1) &&
12783 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12784 (comp->steps[f].value5 == NULL) &&
12785 (comp->steps[f].value == 0) &&
12786 (comp->steps[f].value4 != NULL) &&
12787 (xmlStrEqual
12788 (comp->steps[f].value4, BAD_CAST "last"))) {
12789 xmlNodePtr last = NULL;
12790
12791 total +=
12792 xmlXPathCompOpEvalLast(ctxt,
12793 &comp->steps[op->ch1],
12794 &last);
12795 CHECK_ERROR0;
12796 /*
12797 * The nodeset should be in document order,
12798 * Keep only the last value
12799 */
12800 if ((ctxt->value != NULL) &&
12801 (ctxt->value->type == XPATH_NODESET) &&
12802 (ctxt->value->nodesetval != NULL) &&
12803 (ctxt->value->nodesetval->nodeTab != NULL) &&
12804 (ctxt->value->nodesetval->nodeNr > 1)) {
12805 ctxt->value->nodesetval->nodeTab[0] =
12806 ctxt->value->nodesetval->nodeTab[ctxt->
12807 value->
12808 nodesetval->
12809 nodeNr -
12810 1];
12811 ctxt->value->nodesetval->nodeNr = 1;
12812 *first = *(ctxt->value->nodesetval->nodeTab);
12813 }
12814 return (total);
12815 }
12816 }
12817
12818 if (op->ch1 != -1)
12819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12820 CHECK_ERROR0;
12821 if (op->ch2 == -1)
12822 return (total);
12823 if (ctxt->value == NULL)
12824 return (total);
12825
12826#ifdef LIBXML_XPTR_ENABLED
12827 oldnode = ctxt->context->node;
12828 /*
12829 * Hum are we filtering the result of an XPointer expression
12830 */
12831 if (ctxt->value->type == XPATH_LOCATIONSET) {
12832 xmlXPathObjectPtr tmp = NULL;
12833 xmlLocationSetPtr newlocset = NULL;
12834 xmlLocationSetPtr oldlocset;
12835
12836 /*
12837 * Extract the old locset, and then evaluate the result of the
12838 * expression for all the element in the locset. use it to grow
12839 * up a new locset.
12840 */
12841 CHECK_TYPE0(XPATH_LOCATIONSET);
12842 obj = valuePop(ctxt);
12843 oldlocset = obj->user;
12844 ctxt->context->node = NULL;
12845
12846 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12847 ctxt->context->contextSize = 0;
12848 ctxt->context->proximityPosition = 0;
12849 if (op->ch2 != -1)
12850 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12851 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012852 if (res != NULL) {
12853 xmlXPathReleaseObject(ctxt->context, res);
12854 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012855 valuePush(ctxt, obj);
12856 CHECK_ERROR0;
12857 return (total);
12858 }
12859 newlocset = xmlXPtrLocationSetCreate(NULL);
12860
12861 for (i = 0; i < oldlocset->locNr; i++) {
12862 /*
12863 * Run the evaluation with a node list made of a
12864 * single item in the nodelocset.
12865 */
12866 ctxt->context->node = oldlocset->locTab[i]->user;
12867 ctxt->context->contextSize = oldlocset->locNr;
12868 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012869 if (tmp == NULL) {
12870 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12871 ctxt->context->node);
12872 } else {
12873 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12874 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012875 }
12876 valuePush(ctxt, tmp);
12877 if (op->ch2 != -1)
12878 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12879 if (ctxt->error != XPATH_EXPRESSION_OK) {
12880 xmlXPathFreeObject(obj);
12881 return(0);
12882 }
12883 /*
12884 * The result of the evaluation need to be tested to
12885 * decided whether the filter succeeded or not
12886 */
12887 res = valuePop(ctxt);
12888 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12889 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012890 xmlXPathCacheObjectCopy(ctxt->context,
12891 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012892 }
12893 /*
12894 * Cleanup
12895 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012896 if (res != NULL) {
12897 xmlXPathReleaseObject(ctxt->context, res);
12898 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012899 if (ctxt->value == tmp) {
12900 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012901 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012902 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012903 * REVISIT TODO: Don't create a temporary nodeset
12904 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012905 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012906 /* OLD: xmlXPathFreeObject(res); */
12907 } else
12908 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012909 ctxt->context->node = NULL;
12910 /*
12911 * Only put the first node in the result, then leave.
12912 */
12913 if (newlocset->locNr > 0) {
12914 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12915 break;
12916 }
12917 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012918 if (tmp != NULL) {
12919 xmlXPathReleaseObject(ctxt->context, tmp);
12920 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012921 /*
12922 * The result is used as the new evaluation locset.
12923 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012924 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012925 ctxt->context->node = NULL;
12926 ctxt->context->contextSize = -1;
12927 ctxt->context->proximityPosition = -1;
12928 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12929 ctxt->context->node = oldnode;
12930 return (total);
12931 }
12932#endif /* LIBXML_XPTR_ENABLED */
12933
12934 /*
12935 * Extract the old set, and then evaluate the result of the
12936 * expression for all the element in the set. use it to grow
12937 * up a new set.
12938 */
12939 CHECK_TYPE0(XPATH_NODESET);
12940 obj = valuePop(ctxt);
12941 oldset = obj->nodesetval;
12942
12943 oldnode = ctxt->context->node;
12944 oldDoc = ctxt->context->doc;
12945 ctxt->context->node = NULL;
12946
12947 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12948 ctxt->context->contextSize = 0;
12949 ctxt->context->proximityPosition = 0;
12950 /* QUESTION TODO: Why was this code commented out?
12951 if (op->ch2 != -1)
12952 total +=
12953 xmlXPathCompOpEval(ctxt,
12954 &comp->steps[op->ch2]);
12955 CHECK_ERROR0;
12956 res = valuePop(ctxt);
12957 if (res != NULL)
12958 xmlXPathFreeObject(res);
12959 */
12960 valuePush(ctxt, obj);
12961 ctxt->context->node = oldnode;
12962 CHECK_ERROR0;
12963 } else {
12964 xmlNodeSetPtr newset;
12965 xmlXPathObjectPtr tmp = NULL;
12966 /*
12967 * Initialize the new set.
12968 * Also set the xpath document in case things like
12969 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012970 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012971 newset = xmlXPathNodeSetCreate(NULL);
12972
12973 for (i = 0; i < oldset->nodeNr; i++) {
12974 /*
12975 * Run the evaluation with a node list made of
12976 * a single item in the nodeset.
12977 */
12978 ctxt->context->node = oldset->nodeTab[i];
12979 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12980 (oldset->nodeTab[i]->doc != NULL))
12981 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012982 if (tmp == NULL) {
12983 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12984 ctxt->context->node);
12985 } else {
12986 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12987 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012988 }
12989 valuePush(ctxt, tmp);
12990 ctxt->context->contextSize = oldset->nodeNr;
12991 ctxt->context->proximityPosition = i + 1;
12992 if (op->ch2 != -1)
12993 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12994 if (ctxt->error != XPATH_EXPRESSION_OK) {
12995 xmlXPathFreeNodeSet(newset);
12996 xmlXPathFreeObject(obj);
12997 return(0);
12998 }
12999 /*
13000 * The result of the evaluation needs to be tested to
13001 * decide whether the filter succeeded or not
13002 */
13003 res = valuePop(ctxt);
13004 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13005 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13006 }
13007 /*
13008 * Cleanup
13009 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013010 if (res != NULL) {
13011 xmlXPathReleaseObject(ctxt->context, res);
13012 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013013 if (ctxt->value == tmp) {
13014 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013015 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013016 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013017 * in order to avoid massive recreation inside this
13018 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013019 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013020 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013021 } else
13022 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013023 ctxt->context->node = NULL;
13024 /*
13025 * Only put the first node in the result, then leave.
13026 */
13027 if (newset->nodeNr > 0) {
13028 *first = *(newset->nodeTab);
13029 break;
13030 }
13031 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013032 if (tmp != NULL) {
13033 xmlXPathReleaseObject(ctxt->context, tmp);
13034 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013035 /*
13036 * The result is used as the new evaluation set.
13037 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013038 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013039 ctxt->context->node = NULL;
13040 ctxt->context->contextSize = -1;
13041 ctxt->context->proximityPosition = -1;
13042 /* may want to move this past the '}' later */
13043 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013044 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013045 }
13046 ctxt->context->node = oldnode;
13047 return(total);
13048}
13049#endif /* XP_OPTIMIZED_FILTER_FIRST */
13050
Owen Taylor3473f882001-02-23 17:55:21 +000013051/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013052 * xmlXPathCompOpEval:
13053 * @ctxt: the XPath parser context with the compiled expression
13054 * @op: an XPath compiled operation
13055 *
13056 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013057 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013058 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013059static int
13060xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13061{
13062 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013063 int equal, ret;
13064 xmlXPathCompExprPtr comp;
13065 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013066 xmlNodePtr bak;
13067 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013068 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013069 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013070
Daniel Veillard556c6682001-10-06 09:59:51 +000013071 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013072 comp = ctxt->comp;
13073 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013074 case XPATH_OP_END:
13075 return (0);
13076 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013077 bakd = ctxt->context->doc;
13078 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013079 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013080 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013081 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013083 xmlXPathBooleanFunction(ctxt, 1);
13084 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13085 return (total);
13086 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013087 ctxt->context->doc = bakd;
13088 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013089 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013090 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013092 if (ctxt->error) {
13093 xmlXPathFreeObject(arg2);
13094 return(0);
13095 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013096 xmlXPathBooleanFunction(ctxt, 1);
13097 arg1 = valuePop(ctxt);
13098 arg1->boolval &= arg2->boolval;
13099 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013100 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013101 return (total);
13102 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013103 bakd = ctxt->context->doc;
13104 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013105 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013106 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013107 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013108 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013109 xmlXPathBooleanFunction(ctxt, 1);
13110 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13111 return (total);
13112 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013113 ctxt->context->doc = bakd;
13114 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013115 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013116 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013118 if (ctxt->error) {
13119 xmlXPathFreeObject(arg2);
13120 return(0);
13121 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013122 xmlXPathBooleanFunction(ctxt, 1);
13123 arg1 = valuePop(ctxt);
13124 arg1->boolval |= arg2->boolval;
13125 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013126 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013127 return (total);
13128 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013129 bakd = ctxt->context->doc;
13130 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013131 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013132 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013133 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013134 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013135 ctxt->context->doc = bakd;
13136 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013137 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013138 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013139 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013140 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013141 if (op->value)
13142 equal = xmlXPathEqualValues(ctxt);
13143 else
13144 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013145 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013146 return (total);
13147 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013148 bakd = ctxt->context->doc;
13149 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013150 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013151 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013152 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013153 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013154 ctxt->context->doc = bakd;
13155 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013156 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013157 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013159 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013160 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013161 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013162 return (total);
13163 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013164 bakd = ctxt->context->doc;
13165 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013166 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013167 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013168 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013169 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013170 if (op->ch2 != -1) {
13171 ctxt->context->doc = bakd;
13172 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013173 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013174 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013175 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013176 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013177 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013178 if (op->value == 0)
13179 xmlXPathSubValues(ctxt);
13180 else if (op->value == 1)
13181 xmlXPathAddValues(ctxt);
13182 else if (op->value == 2)
13183 xmlXPathValueFlipSign(ctxt);
13184 else if (op->value == 3) {
13185 CAST_TO_NUMBER;
13186 CHECK_TYPE0(XPATH_NUMBER);
13187 }
13188 return (total);
13189 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013190 bakd = ctxt->context->doc;
13191 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013192 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013193 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013195 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013196 ctxt->context->doc = bakd;
13197 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013198 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013199 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013200 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013201 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013202 if (op->value == 0)
13203 xmlXPathMultValues(ctxt);
13204 else if (op->value == 1)
13205 xmlXPathDivValues(ctxt);
13206 else if (op->value == 2)
13207 xmlXPathModValues(ctxt);
13208 return (total);
13209 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013210 bakd = ctxt->context->doc;
13211 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013212 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013213 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013214 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013215 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013216 ctxt->context->doc = bakd;
13217 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013218 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013219 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013221 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013222 CHECK_TYPE0(XPATH_NODESET);
13223 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013224
Daniel Veillardf06307e2001-07-03 10:35:50 +000013225 CHECK_TYPE0(XPATH_NODESET);
13226 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013227
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013228 if ((arg1->nodesetval == NULL) ||
13229 ((arg2->nodesetval != NULL) &&
13230 (arg2->nodesetval->nodeNr != 0)))
13231 {
13232 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13233 arg2->nodesetval);
13234 }
13235
Daniel Veillardf06307e2001-07-03 10:35:50 +000013236 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013237 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013238 return (total);
13239 case XPATH_OP_ROOT:
13240 xmlXPathRoot(ctxt);
13241 return (total);
13242 case XPATH_OP_NODE:
13243 if (op->ch1 != -1)
13244 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013245 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013246 if (op->ch2 != -1)
13247 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013248 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013249 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13250 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013251 return (total);
13252 case XPATH_OP_RESET:
13253 if (op->ch1 != -1)
13254 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013255 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013256 if (op->ch2 != -1)
13257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013258 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013259 ctxt->context->node = NULL;
13260 return (total);
13261 case XPATH_OP_COLLECT:{
13262 if (op->ch1 == -1)
13263 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013264
Daniel Veillardf06307e2001-07-03 10:35:50 +000013265 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013266 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013267
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013268 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013269 return (total);
13270 }
13271 case XPATH_OP_VALUE:
13272 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013273 xmlXPathCacheObjectCopy(ctxt->context,
13274 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013275 return (total);
13276 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013277 xmlXPathObjectPtr val;
13278
Daniel Veillardf06307e2001-07-03 10:35:50 +000013279 if (op->ch1 != -1)
13280 total +=
13281 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013282 if (op->value5 == NULL) {
13283 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13284 if (val == NULL) {
13285 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13286 return(0);
13287 }
13288 valuePush(ctxt, val);
13289 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013290 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013291
Daniel Veillardf06307e2001-07-03 10:35:50 +000013292 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13293 if (URI == NULL) {
13294 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013295 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013296 op->value4, op->value5);
13297 return (total);
13298 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013299 val = xmlXPathVariableLookupNS(ctxt->context,
13300 op->value4, URI);
13301 if (val == NULL) {
13302 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13303 return(0);
13304 }
13305 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013306 }
13307 return (total);
13308 }
13309 case XPATH_OP_FUNCTION:{
13310 xmlXPathFunction func;
13311 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013312 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013313
13314 if (op->ch1 != -1)
13315 total +=
13316 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013317 if (ctxt->valueNr < op->value) {
13318 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013319 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013320 ctxt->error = XPATH_INVALID_OPERAND;
13321 return (total);
13322 }
13323 for (i = 0; i < op->value; i++)
13324 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13325 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013326 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013327 ctxt->error = XPATH_INVALID_OPERAND;
13328 return (total);
13329 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013330 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013331 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013332 else {
13333 const xmlChar *URI = NULL;
13334
13335 if (op->value5 == NULL)
13336 func =
13337 xmlXPathFunctionLookup(ctxt->context,
13338 op->value4);
13339 else {
13340 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13341 if (URI == NULL) {
13342 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013343 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013344 op->value4, op->value5);
13345 return (total);
13346 }
13347 func = xmlXPathFunctionLookupNS(ctxt->context,
13348 op->value4, URI);
13349 }
13350 if (func == NULL) {
13351 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013352 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013353 op->value4);
13354 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013356 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 op->cacheURI = (void *) URI;
13358 }
13359 oldFunc = ctxt->context->function;
13360 oldFuncURI = ctxt->context->functionURI;
13361 ctxt->context->function = op->value4;
13362 ctxt->context->functionURI = op->cacheURI;
13363 func(ctxt, op->value);
13364 ctxt->context->function = oldFunc;
13365 ctxt->context->functionURI = oldFuncURI;
13366 return (total);
13367 }
13368 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013369 bakd = ctxt->context->doc;
13370 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013371 pp = ctxt->context->proximityPosition;
13372 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 if (op->ch1 != -1)
13374 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013375 ctxt->context->contextSize = cs;
13376 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013377 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013378 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013379 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013380 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013381 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013382 ctxt->context->doc = bakd;
13383 ctxt->context->node = bak;
13384 CHECK_ERROR0;
13385 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013386 return (total);
13387 case XPATH_OP_PREDICATE:
13388 case XPATH_OP_FILTER:{
13389 xmlXPathObjectPtr res;
13390 xmlXPathObjectPtr obj, tmp;
13391 xmlNodeSetPtr newset = NULL;
13392 xmlNodeSetPtr oldset;
13393 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013394 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013395 int i;
13396
13397 /*
13398 * Optimization for ()[1] selection i.e. the first elem
13399 */
13400 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013401#ifdef XP_OPTIMIZED_FILTER_FIRST
13402 /*
13403 * FILTER TODO: Can we assume that the inner processing
13404 * will result in an ordered list if we have an
13405 * XPATH_OP_FILTER?
13406 * What about an additional field or flag on
13407 * xmlXPathObject like @sorted ? This way we wouln'd need
13408 * to assume anything, so it would be more robust and
13409 * easier to optimize.
13410 */
13411 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13412 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13413#else
13414 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13415#endif
13416 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013417 xmlXPathObjectPtr val;
13418
13419 val = comp->steps[op->ch2].value4;
13420 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13421 (val->floatval == 1.0)) {
13422 xmlNodePtr first = NULL;
13423
13424 total +=
13425 xmlXPathCompOpEvalFirst(ctxt,
13426 &comp->steps[op->ch1],
13427 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013428 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013429 /*
13430 * The nodeset should be in document order,
13431 * Keep only the first value
13432 */
13433 if ((ctxt->value != NULL) &&
13434 (ctxt->value->type == XPATH_NODESET) &&
13435 (ctxt->value->nodesetval != NULL) &&
13436 (ctxt->value->nodesetval->nodeNr > 1))
13437 ctxt->value->nodesetval->nodeNr = 1;
13438 return (total);
13439 }
13440 }
13441 /*
13442 * Optimization for ()[last()] selection i.e. the last elem
13443 */
13444 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13445 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13446 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13447 int f = comp->steps[op->ch2].ch1;
13448
13449 if ((f != -1) &&
13450 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13451 (comp->steps[f].value5 == NULL) &&
13452 (comp->steps[f].value == 0) &&
13453 (comp->steps[f].value4 != NULL) &&
13454 (xmlStrEqual
13455 (comp->steps[f].value4, BAD_CAST "last"))) {
13456 xmlNodePtr last = NULL;
13457
13458 total +=
13459 xmlXPathCompOpEvalLast(ctxt,
13460 &comp->steps[op->ch1],
13461 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013462 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013463 /*
13464 * The nodeset should be in document order,
13465 * Keep only the last value
13466 */
13467 if ((ctxt->value != NULL) &&
13468 (ctxt->value->type == XPATH_NODESET) &&
13469 (ctxt->value->nodesetval != NULL) &&
13470 (ctxt->value->nodesetval->nodeTab != NULL) &&
13471 (ctxt->value->nodesetval->nodeNr > 1)) {
13472 ctxt->value->nodesetval->nodeTab[0] =
13473 ctxt->value->nodesetval->nodeTab[ctxt->
13474 value->
13475 nodesetval->
13476 nodeNr -
13477 1];
13478 ctxt->value->nodesetval->nodeNr = 1;
13479 }
13480 return (total);
13481 }
13482 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013483 /*
13484 * Process inner predicates first.
13485 * Example "index[parent::book][1]":
13486 * ...
13487 * PREDICATE <-- we are here "[1]"
13488 * PREDICATE <-- process "[parent::book]" first
13489 * SORT
13490 * COLLECT 'parent' 'name' 'node' book
13491 * NODE
13492 * ELEM Object is a number : 1
13493 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013494 if (op->ch1 != -1)
13495 total +=
13496 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013497 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013498 if (op->ch2 == -1)
13499 return (total);
13500 if (ctxt->value == NULL)
13501 return (total);
13502
13503 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013504
13505#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013506 /*
13507 * Hum are we filtering the result of an XPointer expression
13508 */
13509 if (ctxt->value->type == XPATH_LOCATIONSET) {
13510 xmlLocationSetPtr newlocset = NULL;
13511 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013512
Daniel Veillardf06307e2001-07-03 10:35:50 +000013513 /*
13514 * Extract the old locset, and then evaluate the result of the
13515 * expression for all the element in the locset. use it to grow
13516 * up a new locset.
13517 */
13518 CHECK_TYPE0(XPATH_LOCATIONSET);
13519 obj = valuePop(ctxt);
13520 oldlocset = obj->user;
13521 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013522
Daniel Veillardf06307e2001-07-03 10:35:50 +000013523 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13524 ctxt->context->contextSize = 0;
13525 ctxt->context->proximityPosition = 0;
13526 if (op->ch2 != -1)
13527 total +=
13528 xmlXPathCompOpEval(ctxt,
13529 &comp->steps[op->ch2]);
13530 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013531 if (res != NULL) {
13532 xmlXPathReleaseObject(ctxt->context, res);
13533 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013534 valuePush(ctxt, obj);
13535 CHECK_ERROR0;
13536 return (total);
13537 }
13538 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013539
Daniel Veillardf06307e2001-07-03 10:35:50 +000013540 for (i = 0; i < oldlocset->locNr; i++) {
13541 /*
13542 * Run the evaluation with a node list made of a
13543 * single item in the nodelocset.
13544 */
13545 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013546 ctxt->context->contextSize = oldlocset->locNr;
13547 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013548 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13549 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013550 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013551
Daniel Veillardf06307e2001-07-03 10:35:50 +000013552 if (op->ch2 != -1)
13553 total +=
13554 xmlXPathCompOpEval(ctxt,
13555 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013556 if (ctxt->error != XPATH_EXPRESSION_OK) {
13557 xmlXPathFreeObject(obj);
13558 return(0);
13559 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013560
Daniel Veillardf06307e2001-07-03 10:35:50 +000013561 /*
13562 * The result of the evaluation need to be tested to
13563 * decided whether the filter succeeded or not
13564 */
13565 res = valuePop(ctxt);
13566 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13567 xmlXPtrLocationSetAdd(newlocset,
13568 xmlXPathObjectCopy
13569 (oldlocset->locTab[i]));
13570 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013571
Daniel Veillardf06307e2001-07-03 10:35:50 +000013572 /*
13573 * Cleanup
13574 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013575 if (res != NULL) {
13576 xmlXPathReleaseObject(ctxt->context, res);
13577 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013578 if (ctxt->value == tmp) {
13579 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013580 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013581 }
13582
13583 ctxt->context->node = NULL;
13584 }
13585
13586 /*
13587 * The result is used as the new evaluation locset.
13588 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013589 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013590 ctxt->context->node = NULL;
13591 ctxt->context->contextSize = -1;
13592 ctxt->context->proximityPosition = -1;
13593 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13594 ctxt->context->node = oldnode;
13595 return (total);
13596 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013597#endif /* LIBXML_XPTR_ENABLED */
13598
Daniel Veillardf06307e2001-07-03 10:35:50 +000013599 /*
13600 * Extract the old set, and then evaluate the result of the
13601 * expression for all the element in the set. use it to grow
13602 * up a new set.
13603 */
13604 CHECK_TYPE0(XPATH_NODESET);
13605 obj = valuePop(ctxt);
13606 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013607
Daniel Veillardf06307e2001-07-03 10:35:50 +000013608 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013609 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013610 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013611
Daniel Veillardf06307e2001-07-03 10:35:50 +000013612 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13613 ctxt->context->contextSize = 0;
13614 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013615/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013616 if (op->ch2 != -1)
13617 total +=
13618 xmlXPathCompOpEval(ctxt,
13619 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013620 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013621 res = valuePop(ctxt);
13622 if (res != NULL)
13623 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013624*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013625 valuePush(ctxt, obj);
13626 ctxt->context->node = oldnode;
13627 CHECK_ERROR0;
13628 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013629 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013630 /*
13631 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013632 * Also set the xpath document in case things like
13633 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013634 */
13635 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013636 /*
13637 * SPEC XPath 1.0:
13638 * "For each node in the node-set to be filtered, the
13639 * PredicateExpr is evaluated with that node as the
13640 * context node, with the number of nodes in the
13641 * node-set as the context size, and with the proximity
13642 * position of the node in the node-set with respect to
13643 * the axis as the context position;"
13644 * @oldset is the node-set" to be filtered.
13645 *
13646 * SPEC XPath 1.0:
13647 * "only predicates change the context position and
13648 * context size (see [2.4 Predicates])."
13649 * Example:
13650 * node-set context pos
13651 * nA 1
13652 * nB 2
13653 * nC 3
13654 * After applying predicate [position() > 1] :
13655 * node-set context pos
13656 * nB 1
13657 * nC 2
13658 *
13659 * removed the first node in the node-set, then
13660 * the context position of the
13661 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013662 for (i = 0; i < oldset->nodeNr; i++) {
13663 /*
13664 * Run the evaluation with a node list made of
13665 * a single item in the nodeset.
13666 */
13667 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013668 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13669 (oldset->nodeTab[i]->doc != NULL))
13670 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013671 if (tmp == NULL) {
13672 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13673 ctxt->context->node);
13674 } else {
13675 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13676 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013677 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013678 valuePush(ctxt, tmp);
13679 ctxt->context->contextSize = oldset->nodeNr;
13680 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013681 /*
13682 * Evaluate the predicate against the context node.
13683 * Can/should we optimize position() predicates
13684 * here (e.g. "[1]")?
13685 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013686 if (op->ch2 != -1)
13687 total +=
13688 xmlXPathCompOpEval(ctxt,
13689 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013690 if (ctxt->error != XPATH_EXPRESSION_OK) {
13691 xmlXPathFreeNodeSet(newset);
13692 xmlXPathFreeObject(obj);
13693 return(0);
13694 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013695
Daniel Veillardf06307e2001-07-03 10:35:50 +000013696 /*
William M. Brack08171912003-12-29 02:52:11 +000013697 * The result of the evaluation needs to be tested to
13698 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013699 */
13700 /*
13701 * OPTIMIZE TODO: Can we use
13702 * xmlXPathNodeSetAdd*Unique()* instead?
13703 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013704 res = valuePop(ctxt);
13705 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13706 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13707 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013708
Daniel Veillardf06307e2001-07-03 10:35:50 +000013709 /*
13710 * Cleanup
13711 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013712 if (res != NULL) {
13713 xmlXPathReleaseObject(ctxt->context, res);
13714 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013715 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013716 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013717 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013718 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013719 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013720 * in order to avoid massive recreation inside this
13721 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013722 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013723 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013724 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013725 ctxt->context->node = NULL;
13726 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013727 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013728 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013729 /*
13730 * The result is used as the new evaluation set.
13731 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013732 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013733 ctxt->context->node = NULL;
13734 ctxt->context->contextSize = -1;
13735 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013736 /* may want to move this past the '}' later */
13737 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013738 valuePush(ctxt,
13739 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013740 }
13741 ctxt->context->node = oldnode;
13742 return (total);
13743 }
13744 case XPATH_OP_SORT:
13745 if (op->ch1 != -1)
13746 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013747 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013748 if ((ctxt->value != NULL) &&
13749 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013750 (ctxt->value->nodesetval != NULL) &&
13751 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013752 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013753 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013754 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013755 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013756#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013757 case XPATH_OP_RANGETO:{
13758 xmlXPathObjectPtr range;
13759 xmlXPathObjectPtr res, obj;
13760 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013761 xmlLocationSetPtr newlocset = NULL;
13762 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013763 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013764 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013765
Daniel Veillardf06307e2001-07-03 10:35:50 +000013766 if (op->ch1 != -1)
13767 total +=
13768 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13769 if (op->ch2 == -1)
13770 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013771
William M. Brack08171912003-12-29 02:52:11 +000013772 if (ctxt->value->type == XPATH_LOCATIONSET) {
13773 /*
13774 * Extract the old locset, and then evaluate the result of the
13775 * expression for all the element in the locset. use it to grow
13776 * up a new locset.
13777 */
13778 CHECK_TYPE0(XPATH_LOCATIONSET);
13779 obj = valuePop(ctxt);
13780 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013781
William M. Brack08171912003-12-29 02:52:11 +000013782 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013783 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013784 ctxt->context->contextSize = 0;
13785 ctxt->context->proximityPosition = 0;
13786 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13787 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013788 if (res != NULL) {
13789 xmlXPathReleaseObject(ctxt->context, res);
13790 }
William M. Brack08171912003-12-29 02:52:11 +000013791 valuePush(ctxt, obj);
13792 CHECK_ERROR0;
13793 return (total);
13794 }
13795 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013796
William M. Brack08171912003-12-29 02:52:11 +000013797 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013798 /*
William M. Brack08171912003-12-29 02:52:11 +000013799 * Run the evaluation with a node list made of a
13800 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013801 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013802 ctxt->context->node = oldlocset->locTab[i]->user;
13803 ctxt->context->contextSize = oldlocset->locNr;
13804 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013805 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13806 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013807 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013808
Daniel Veillardf06307e2001-07-03 10:35:50 +000013809 if (op->ch2 != -1)
13810 total +=
13811 xmlXPathCompOpEval(ctxt,
13812 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013813 if (ctxt->error != XPATH_EXPRESSION_OK) {
13814 xmlXPathFreeObject(obj);
13815 return(0);
13816 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013817
Daniel Veillardf06307e2001-07-03 10:35:50 +000013818 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013819 if (res->type == XPATH_LOCATIONSET) {
13820 xmlLocationSetPtr rloc =
13821 (xmlLocationSetPtr)res->user;
13822 for (j=0; j<rloc->locNr; j++) {
13823 range = xmlXPtrNewRange(
13824 oldlocset->locTab[i]->user,
13825 oldlocset->locTab[i]->index,
13826 rloc->locTab[j]->user2,
13827 rloc->locTab[j]->index2);
13828 if (range != NULL) {
13829 xmlXPtrLocationSetAdd(newlocset, range);
13830 }
13831 }
13832 } else {
13833 range = xmlXPtrNewRangeNodeObject(
13834 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13835 if (range != NULL) {
13836 xmlXPtrLocationSetAdd(newlocset,range);
13837 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013838 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013839
Daniel Veillardf06307e2001-07-03 10:35:50 +000013840 /*
13841 * Cleanup
13842 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013843 if (res != NULL) {
13844 xmlXPathReleaseObject(ctxt->context, res);
13845 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013846 if (ctxt->value == tmp) {
13847 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013848 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013849 }
13850
13851 ctxt->context->node = NULL;
13852 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013853 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013854 CHECK_TYPE0(XPATH_NODESET);
13855 obj = valuePop(ctxt);
13856 oldset = obj->nodesetval;
13857 ctxt->context->node = NULL;
13858
13859 newlocset = xmlXPtrLocationSetCreate(NULL);
13860
13861 if (oldset != NULL) {
13862 for (i = 0; i < oldset->nodeNr; i++) {
13863 /*
13864 * Run the evaluation with a node list made of a single item
13865 * in the nodeset.
13866 */
13867 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013868 /*
13869 * OPTIMIZE TODO: Avoid recreation for every iteration.
13870 */
13871 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13872 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013873 valuePush(ctxt, tmp);
13874
13875 if (op->ch2 != -1)
13876 total +=
13877 xmlXPathCompOpEval(ctxt,
13878 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013879 if (ctxt->error != XPATH_EXPRESSION_OK) {
13880 xmlXPathFreeObject(obj);
13881 return(0);
13882 }
William M. Brack08171912003-12-29 02:52:11 +000013883
William M. Brack08171912003-12-29 02:52:11 +000013884 res = valuePop(ctxt);
13885 range =
13886 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13887 res);
13888 if (range != NULL) {
13889 xmlXPtrLocationSetAdd(newlocset, range);
13890 }
13891
13892 /*
13893 * Cleanup
13894 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013895 if (res != NULL) {
13896 xmlXPathReleaseObject(ctxt->context, res);
13897 }
William M. Brack08171912003-12-29 02:52:11 +000013898 if (ctxt->value == tmp) {
13899 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013900 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013901 }
13902
13903 ctxt->context->node = NULL;
13904 }
13905 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013906 }
13907
13908 /*
13909 * The result is used as the new evaluation set.
13910 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013911 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013912 ctxt->context->node = NULL;
13913 ctxt->context->contextSize = -1;
13914 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013915 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013916 return (total);
13917 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013918#endif /* LIBXML_XPTR_ENABLED */
13919 }
13920 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013921 "XPath: unknown precompiled operation %d\n", op->op);
13922 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013923}
13924
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013925/**
13926 * xmlXPathCompOpEvalToBoolean:
13927 * @ctxt: the XPath parser context
13928 *
13929 * Evaluates if the expression evaluates to true.
13930 *
13931 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13932 */
13933static int
13934xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013935 xmlXPathStepOpPtr op,
13936 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013937{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013938 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013939
13940start:
13941 /* comp = ctxt->comp; */
13942 switch (op->op) {
13943 case XPATH_OP_END:
13944 return (0);
13945 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013946 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013947 if (isPredicate)
13948 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13949 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013950 case XPATH_OP_SORT:
13951 /*
13952 * We don't need sorting for boolean results. Skip this one.
13953 */
13954 if (op->ch1 != -1) {
13955 op = &ctxt->comp->steps[op->ch1];
13956 goto start;
13957 }
13958 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013959 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013960 if (op->ch1 == -1)
13961 return(0);
13962
13963 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13964 if (ctxt->error != XPATH_EXPRESSION_OK)
13965 return(-1);
13966
13967 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13968 if (ctxt->error != XPATH_EXPRESSION_OK)
13969 return(-1);
13970
13971 resObj = valuePop(ctxt);
13972 if (resObj == NULL)
13973 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013974 break;
13975 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013976 /*
13977 * Fallback to call xmlXPathCompOpEval().
13978 */
13979 xmlXPathCompOpEval(ctxt, op);
13980 if (ctxt->error != XPATH_EXPRESSION_OK)
13981 return(-1);
13982
13983 resObj = valuePop(ctxt);
13984 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013985 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013986 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013987 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013988
13989 if (resObj) {
13990 int res;
13991
13992 if (resObj->type == XPATH_BOOLEAN) {
13993 res = resObj->boolval;
13994 } else if (isPredicate) {
13995 /*
13996 * For predicates a result of type "number" is handled
13997 * differently:
13998 * SPEC XPath 1.0:
13999 * "If the result is a number, the result will be converted
14000 * to true if the number is equal to the context position
14001 * and will be converted to false otherwise;"
14002 */
14003 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14004 } else {
14005 res = xmlXPathCastToBoolean(resObj);
14006 }
14007 xmlXPathReleaseObject(ctxt->context, resObj);
14008 return(res);
14009 }
14010
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014011 return(0);
14012}
14013
Daniel Veillard56de87e2005-02-16 00:22:29 +000014014#ifdef XPATH_STREAMING
14015/**
14016 * xmlXPathRunStreamEval:
14017 * @ctxt: the XPath parser context with the compiled expression
14018 *
14019 * Evaluate the Precompiled Streamable XPath expression in the given context.
14020 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014021static int
14022xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14023 xmlXPathObjectPtr *resultSeq, int toBool)
14024{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014025 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014026 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014027 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014028 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014029 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014030 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014031
14032 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014033
14034 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014035 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014036 max_depth = xmlPatternMaxDepth(comp);
14037 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014038 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014039 if (max_depth == -2)
14040 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014041 min_depth = xmlPatternMinDepth(comp);
14042 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014043 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014044 from_root = xmlPatternFromRoot(comp);
14045 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014046 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014047#if 0
14048 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14049#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014050
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014051 if (! toBool) {
14052 if (resultSeq == NULL)
14053 return(-1);
14054 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14055 if (*resultSeq == NULL)
14056 return(-1);
14057 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014058
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014059 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014060 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014061 */
14062 if (min_depth == 0) {
14063 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014064 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014065 if (toBool)
14066 return(1);
14067 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14068 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014069 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014070 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014071 if (toBool)
14072 return(1);
14073 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014074 }
14075 }
14076 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014077 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014078 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014079
Daniel Veillard56de87e2005-02-16 00:22:29 +000014080 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014081 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014082 } else if (ctxt->node != NULL) {
14083 switch (ctxt->node->type) {
14084 case XML_ELEMENT_NODE:
14085 case XML_DOCUMENT_NODE:
14086 case XML_DOCUMENT_FRAG_NODE:
14087 case XML_HTML_DOCUMENT_NODE:
14088#ifdef LIBXML_DOCB_ENABLED
14089 case XML_DOCB_DOCUMENT_NODE:
14090#endif
14091 cur = ctxt->node;
14092 break;
14093 case XML_ATTRIBUTE_NODE:
14094 case XML_TEXT_NODE:
14095 case XML_CDATA_SECTION_NODE:
14096 case XML_ENTITY_REF_NODE:
14097 case XML_ENTITY_NODE:
14098 case XML_PI_NODE:
14099 case XML_COMMENT_NODE:
14100 case XML_NOTATION_NODE:
14101 case XML_DTD_NODE:
14102 case XML_DOCUMENT_TYPE_NODE:
14103 case XML_ELEMENT_DECL:
14104 case XML_ATTRIBUTE_DECL:
14105 case XML_ENTITY_DECL:
14106 case XML_NAMESPACE_DECL:
14107 case XML_XINCLUDE_START:
14108 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014109 break;
14110 }
14111 limit = cur;
14112 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014113 if (cur == NULL) {
14114 return(0);
14115 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014116
14117 patstream = xmlPatternGetStreamCtxt(comp);
14118 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014119 /*
14120 * QUESTION TODO: Is this an error?
14121 */
14122 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014123 }
14124
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014125 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014126
Daniel Veillard56de87e2005-02-16 00:22:29 +000014127 if (from_root) {
14128 ret = xmlStreamPush(patstream, NULL, NULL);
14129 if (ret < 0) {
14130 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014131 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014132 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014133 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014134 }
14135 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014136 depth = 0;
14137 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014138next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014139 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014140 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014141
14142 switch (cur->type) {
14143 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014144 case XML_TEXT_NODE:
14145 case XML_CDATA_SECTION_NODE:
14146 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014147 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014148 if (cur->type == XML_ELEMENT_NODE) {
14149 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014150 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014151 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014152 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14153 else
14154 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014155
14156 if (ret < 0) {
14157 /* NOP. */
14158 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014159 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014160 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014161 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014162 }
14163 if ((cur->children == NULL) || (depth >= max_depth)) {
14164 ret = xmlStreamPop(patstream);
14165 while (cur->next != NULL) {
14166 cur = cur->next;
14167 if ((cur->type != XML_ENTITY_DECL) &&
14168 (cur->type != XML_DTD_NODE))
14169 goto next_node;
14170 }
14171 }
14172 default:
14173 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014174 }
14175
Daniel Veillard56de87e2005-02-16 00:22:29 +000014176scan_children:
14177 if ((cur->children != NULL) && (depth < max_depth)) {
14178 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014179 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014180 */
14181 if (cur->children->type != XML_ENTITY_DECL) {
14182 cur = cur->children;
14183 depth++;
14184 /*
14185 * Skip DTDs
14186 */
14187 if (cur->type != XML_DTD_NODE)
14188 continue;
14189 }
14190 }
14191
14192 if (cur == limit)
14193 break;
14194
14195 while (cur->next != NULL) {
14196 cur = cur->next;
14197 if ((cur->type != XML_ENTITY_DECL) &&
14198 (cur->type != XML_DTD_NODE))
14199 goto next_node;
14200 }
14201
14202 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014203 cur = cur->parent;
14204 depth--;
14205 if ((cur == NULL) || (cur == limit))
14206 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014207 if (cur->type == XML_ELEMENT_NODE) {
14208 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014209 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014210 ((cur->type == XML_TEXT_NODE) ||
14211 (cur->type == XML_CDATA_SECTION_NODE) ||
14212 (cur->type == XML_COMMENT_NODE) ||
14213 (cur->type == XML_PI_NODE)))
14214 {
14215 ret = xmlStreamPop(patstream);
14216 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014217 if (cur->next != NULL) {
14218 cur = cur->next;
14219 break;
14220 }
14221 } while (cur != NULL);
14222
14223 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014224
Daniel Veillard56de87e2005-02-16 00:22:29 +000014225done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014226
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014227#if 0
14228 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014229 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014230#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014231
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014232 if (patstream)
14233 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014234 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014235
14236return_1:
14237 if (patstream)
14238 xmlFreeStreamCtxt(patstream);
14239 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014240}
14241#endif /* XPATH_STREAMING */
14242
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014243/**
14244 * xmlXPathRunEval:
14245 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014246 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014247 *
14248 * Evaluate the Precompiled XPath expression in the given context.
14249 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014250static int
14251xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14252{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014253 xmlXPathCompExprPtr comp;
14254
14255 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014256 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014257
14258 if (ctxt->valueTab == NULL) {
14259 /* Allocate the value stack */
14260 ctxt->valueTab = (xmlXPathObjectPtr *)
14261 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14262 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014263 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014264 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014265 }
14266 ctxt->valueNr = 0;
14267 ctxt->valueMax = 10;
14268 ctxt->value = NULL;
14269 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014270#ifdef XPATH_STREAMING
14271 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014272 int res;
14273
14274 if (toBool) {
14275 /*
14276 * Evaluation to boolean result.
14277 */
14278 res = xmlXPathRunStreamEval(ctxt->context,
14279 ctxt->comp->stream, NULL, 1);
14280 if (res != -1)
14281 return(res);
14282 } else {
14283 xmlXPathObjectPtr resObj = NULL;
14284
14285 /*
14286 * Evaluation to a sequence.
14287 */
14288 res = xmlXPathRunStreamEval(ctxt->context,
14289 ctxt->comp->stream, &resObj, 0);
14290
14291 if ((res != -1) && (resObj != NULL)) {
14292 valuePush(ctxt, resObj);
14293 return(0);
14294 }
14295 if (resObj != NULL)
14296 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014297 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014298 /*
14299 * QUESTION TODO: This falls back to normal XPath evaluation
14300 * if res == -1. Is this intended?
14301 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014302 }
14303#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014304 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014305 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014306 xmlGenericError(xmlGenericErrorContext,
14307 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014308 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014309 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014310 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014311 return(xmlXPathCompOpEvalToBoolean(ctxt,
14312 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014313 else
14314 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14315
14316 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014317}
14318
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014319/************************************************************************
14320 * *
14321 * Public interfaces *
14322 * *
14323 ************************************************************************/
14324
14325/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014326 * xmlXPathEvalPredicate:
14327 * @ctxt: the XPath context
14328 * @res: the Predicate Expression evaluation result
14329 *
14330 * Evaluate a predicate result for the current node.
14331 * A PredicateExpr is evaluated by evaluating the Expr and converting
14332 * the result to a boolean. If the result is a number, the result will
14333 * be converted to true if the number is equal to the position of the
14334 * context node in the context node list (as returned by the position
14335 * function) and will be converted to false otherwise; if the result
14336 * is not a number, then the result will be converted as if by a call
14337 * to the boolean function.
14338 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014339 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014340 */
14341int
14342xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014343 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014344 switch (res->type) {
14345 case XPATH_BOOLEAN:
14346 return(res->boolval);
14347 case XPATH_NUMBER:
14348 return(res->floatval == ctxt->proximityPosition);
14349 case XPATH_NODESET:
14350 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014351 if (res->nodesetval == NULL)
14352 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014353 return(res->nodesetval->nodeNr != 0);
14354 case XPATH_STRING:
14355 return((res->stringval != NULL) &&
14356 (xmlStrlen(res->stringval) != 0));
14357 default:
14358 STRANGE
14359 }
14360 return(0);
14361}
14362
14363/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014364 * xmlXPathEvaluatePredicateResult:
14365 * @ctxt: the XPath Parser context
14366 * @res: the Predicate Expression evaluation result
14367 *
14368 * Evaluate a predicate result for the current node.
14369 * A PredicateExpr is evaluated by evaluating the Expr and converting
14370 * the result to a boolean. If the result is a number, the result will
14371 * be converted to true if the number is equal to the position of the
14372 * context node in the context node list (as returned by the position
14373 * function) and will be converted to false otherwise; if the result
14374 * is not a number, then the result will be converted as if by a call
14375 * to the boolean function.
14376 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014377 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014378 */
14379int
14380xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14381 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014382 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014383 switch (res->type) {
14384 case XPATH_BOOLEAN:
14385 return(res->boolval);
14386 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014387#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014388 return((res->floatval == ctxt->context->proximityPosition) &&
14389 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014390#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014391 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014392#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014393 case XPATH_NODESET:
14394 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014395 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014396 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014397 return(res->nodesetval->nodeNr != 0);
14398 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014399 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014400#ifdef LIBXML_XPTR_ENABLED
14401 case XPATH_LOCATIONSET:{
14402 xmlLocationSetPtr ptr = res->user;
14403 if (ptr == NULL)
14404 return(0);
14405 return (ptr->locNr != 0);
14406 }
14407#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014408 default:
14409 STRANGE
14410 }
14411 return(0);
14412}
14413
Daniel Veillard56de87e2005-02-16 00:22:29 +000014414#ifdef XPATH_STREAMING
14415/**
14416 * xmlXPathTryStreamCompile:
14417 * @ctxt: an XPath context
14418 * @str: the XPath expression
14419 *
14420 * Try to compile the XPath expression as a streamable subset.
14421 *
14422 * Returns the compiled expression or NULL if failed to compile.
14423 */
14424static xmlXPathCompExprPtr
14425xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14426 /*
14427 * Optimization: use streaming patterns when the XPath expression can
14428 * be compiled to a stream lookup
14429 */
14430 xmlPatternPtr stream;
14431 xmlXPathCompExprPtr comp;
14432 xmlDictPtr dict = NULL;
14433 const xmlChar **namespaces = NULL;
14434 xmlNsPtr ns;
14435 int i, j;
14436
14437 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14438 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014439 const xmlChar *tmp;
14440
14441 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014442 * We don't try to handle expressions using the verbose axis
14443 * specifiers ("::"), just the simplied form at this point.
14444 * Additionally, if there is no list of namespaces available and
14445 * there's a ":" in the expression, indicating a prefixed QName,
14446 * then we won't try to compile either. xmlPatterncompile() needs
14447 * to have a list of namespaces at compilation time in order to
14448 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014449 */
14450 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014451 if ((tmp != NULL) &&
14452 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14453 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014454
Daniel Veillard56de87e2005-02-16 00:22:29 +000014455 if (ctxt != NULL) {
14456 dict = ctxt->dict;
14457 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014458 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014459 if (namespaces == NULL) {
14460 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14461 return(NULL);
14462 }
14463 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14464 ns = ctxt->namespaces[j];
14465 namespaces[i++] = ns->href;
14466 namespaces[i++] = ns->prefix;
14467 }
14468 namespaces[i++] = NULL;
14469 namespaces[i++] = NULL;
14470 }
14471 }
14472
William M. Brackea152c02005-06-09 18:12:28 +000014473 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14474 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014475 if (namespaces != NULL) {
14476 xmlFree((xmlChar **)namespaces);
14477 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014478 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14479 comp = xmlXPathNewCompExpr();
14480 if (comp == NULL) {
14481 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14482 return(NULL);
14483 }
14484 comp->stream = stream;
14485 comp->dict = dict;
14486 if (comp->dict)
14487 xmlDictReference(comp->dict);
14488 return(comp);
14489 }
14490 xmlFreePattern(stream);
14491 }
14492 return(NULL);
14493}
14494#endif /* XPATH_STREAMING */
14495
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014496static int
14497xmlXPathCanRewriteDosExpression(xmlChar *expr)
14498{
14499 if (expr == NULL)
14500 return(0);
14501 do {
14502 if ((*expr == '/') && (*(++expr) == '/'))
14503 return(1);
14504 } while (*expr++);
14505 return(0);
14506}
14507static void
14508xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14509{
14510 /*
14511 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14512 * internal representation.
14513 */
14514 if (op->ch1 != -1) {
14515 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14516 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14517 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14518 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14519 {
14520 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014521 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014522 */
14523 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14524
14525 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14526 (prevop->ch1 != -1) &&
14527 ((xmlXPathAxisVal) prevop->value ==
14528 AXIS_DESCENDANT_OR_SELF) &&
14529 (prevop->ch2 == -1) &&
14530 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014531 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14532 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014533 {
14534 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014535 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014536 * Eliminate it.
14537 */
14538 op->ch1 = prevop->ch1;
14539 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14540 }
14541 }
14542 if (op->ch1 != -1)
14543 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14544 }
14545 if (op->ch2 != -1)
14546 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14547}
14548
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014549/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014550 * xmlXPathCtxtCompile:
14551 * @ctxt: an XPath context
14552 * @str: the XPath expression
14553 *
14554 * Compile an XPath expression
14555 *
14556 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14557 * the caller has to free the object.
14558 */
14559xmlXPathCompExprPtr
14560xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14561 xmlXPathParserContextPtr pctxt;
14562 xmlXPathCompExprPtr comp;
14563
Daniel Veillard56de87e2005-02-16 00:22:29 +000014564#ifdef XPATH_STREAMING
14565 comp = xmlXPathTryStreamCompile(ctxt, str);
14566 if (comp != NULL)
14567 return(comp);
14568#endif
14569
Daniel Veillard4773df22004-01-23 13:15:13 +000014570 xmlXPathInit();
14571
14572 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014573 if (pctxt == NULL)
14574 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014575 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014576
14577 if( pctxt->error != XPATH_EXPRESSION_OK )
14578 {
14579 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014580 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014581 }
14582
14583 if (*pctxt->cur != 0) {
14584 /*
14585 * aleksey: in some cases this line prints *second* error message
14586 * (see bug #78858) and probably this should be fixed.
14587 * However, we are not sure that all error messages are printed
14588 * out in other places. It's not critical so we leave it as-is for now
14589 */
14590 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14591 comp = NULL;
14592 } else {
14593 comp = pctxt->comp;
14594 pctxt->comp = NULL;
14595 }
14596 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014597
Daniel Veillard4773df22004-01-23 13:15:13 +000014598 if (comp != NULL) {
14599 comp->expr = xmlStrdup(str);
14600#ifdef DEBUG_EVAL_COUNTS
14601 comp->string = xmlStrdup(str);
14602 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014603#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014604 if ((comp->expr != NULL) &&
14605 (comp->nbStep > 2) &&
14606 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014607 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14608 {
14609 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014610 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014611 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014612 return(comp);
14613}
14614
14615/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014616 * xmlXPathCompile:
14617 * @str: the XPath expression
14618 *
14619 * Compile an XPath expression
14620 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014621 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014622 * the caller has to free the object.
14623 */
14624xmlXPathCompExprPtr
14625xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014626 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014627}
14628
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014629/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014630 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014631 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014632 * @ctxt: the XPath context
14633 * @resObj: the resulting XPath object or NULL
14634 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014635 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014636 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014637 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014638 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014639 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014640 * the caller has to free the object.
14641 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014642static int
14643xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14644 xmlXPathContextPtr ctxt,
14645 xmlXPathObjectPtr *resObj,
14646 int toBool)
14647{
14648 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014649#ifndef LIBXML_THREAD_ENABLED
14650 static int reentance = 0;
14651#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014652 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014653
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014654 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014655
14656 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014657 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014658 xmlXPathInit();
14659
Daniel Veillard81463942001-10-16 12:34:39 +000014660#ifndef LIBXML_THREAD_ENABLED
14661 reentance++;
14662 if (reentance > 1)
14663 xmlXPathDisableOptimizer = 1;
14664#endif
14665
Daniel Veillardf06307e2001-07-03 10:35:50 +000014666#ifdef DEBUG_EVAL_COUNTS
14667 comp->nb++;
14668 if ((comp->string != NULL) && (comp->nb > 100)) {
14669 fprintf(stderr, "100 x %s\n", comp->string);
14670 comp->nb = 0;
14671 }
14672#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014673 pctxt = xmlXPathCompParserContext(comp, ctxt);
14674 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014675
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014676 if (resObj) {
14677 if (pctxt->value == NULL) {
14678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014679 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014680 *resObj = NULL;
14681 } else {
14682 *resObj = valuePop(pctxt);
14683 }
Owen Taylor3473f882001-02-23 17:55:21 +000014684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014685
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014686 /*
14687 * Pop all remaining objects from the stack.
14688 */
14689 if (pctxt->valueNr > 0) {
14690 xmlXPathObjectPtr tmp;
14691 int stack = 0;
14692
14693 do {
14694 tmp = valuePop(pctxt);
14695 if (tmp != NULL) {
William M. Brackd2f682a2007-05-15 19:42:08 +000014696 stack++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014697 xmlXPathReleaseObject(ctxt, tmp);
14698 }
14699 } while (tmp != NULL);
14700 if ((stack != 0) &&
14701 ((toBool) || ((resObj) && (*resObj))))
14702 {
14703 xmlGenericError(xmlGenericErrorContext,
14704 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14705 stack);
14706 }
Owen Taylor3473f882001-02-23 17:55:21 +000014707 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014708
14709 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14710 xmlXPathFreeObject(*resObj);
14711 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014712 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014713 pctxt->comp = NULL;
14714 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014715#ifndef LIBXML_THREAD_ENABLED
14716 reentance--;
14717#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014718
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014719 return(res);
14720}
14721
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014722/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014723 * xmlXPathCompiledEval:
14724 * @comp: the compiled XPath expression
14725 * @ctx: the XPath context
14726 *
14727 * Evaluate the Precompiled XPath expression in the given context.
14728 *
14729 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14730 * the caller has to free the object.
14731 */
14732xmlXPathObjectPtr
14733xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14734{
14735 xmlXPathObjectPtr res = NULL;
14736
14737 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14738 return(res);
14739}
14740
14741/**
14742 * xmlXPathCompiledEvalToBoolean:
14743 * @comp: the compiled XPath expression
14744 * @ctxt: the XPath context
14745 *
14746 * Applies the XPath boolean() function on the result of the given
14747 * compiled expression.
14748 *
14749 * Returns 1 if the expression evaluated to true, 0 if to false and
14750 * -1 in API and internal errors.
14751 */
14752int
14753xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14754 xmlXPathContextPtr ctxt)
14755{
14756 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14757}
14758
14759/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014760 * xmlXPathEvalExpr:
14761 * @ctxt: the XPath Parser context
14762 *
14763 * Parse and evaluate an XPath expression in the given context,
14764 * then push the result on the context stack
14765 */
14766void
14767xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014768#ifdef XPATH_STREAMING
14769 xmlXPathCompExprPtr comp;
14770#endif
14771
Daniel Veillarda82b1822004-11-08 16:24:57 +000014772 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014773
14774#ifdef XPATH_STREAMING
14775 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14776 if (comp != NULL) {
14777 if (ctxt->comp != NULL)
14778 xmlXPathFreeCompExpr(ctxt->comp);
14779 ctxt->comp = comp;
14780 if (ctxt->cur != NULL)
14781 while (*ctxt->cur != 0) ctxt->cur++;
14782 } else
14783#endif
14784 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014785 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014786 /*
14787 * In this scenario the expression string will sit in ctxt->base.
14788 */
14789 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14790 (ctxt->comp != NULL) &&
14791 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014792 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014793 (ctxt->comp->last >= 0) &&
14794 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014795 {
14796 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014797 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014798 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014799 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014800 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014801 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014802}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014803
14804/**
14805 * xmlXPathEval:
14806 * @str: the XPath expression
14807 * @ctx: the XPath context
14808 *
14809 * Evaluate the XPath Location Path in the given context.
14810 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014811 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014812 * the caller has to free the object.
14813 */
14814xmlXPathObjectPtr
14815xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14816 xmlXPathParserContextPtr ctxt;
14817 xmlXPathObjectPtr res, tmp, init = NULL;
14818 int stack = 0;
14819
William M. Brackf13f77f2004-11-12 16:03:48 +000014820 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014821
William M. Brackf13f77f2004-11-12 16:03:48 +000014822 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014823
14824 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014825 if (ctxt == NULL)
14826 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014827 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014828
14829 if (ctxt->value == NULL) {
14830 xmlGenericError(xmlGenericErrorContext,
14831 "xmlXPathEval: evaluation failed\n");
14832 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014833 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14834#ifdef XPATH_STREAMING
14835 && (ctxt->comp->stream == NULL)
14836#endif
14837 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014838 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14839 res = NULL;
14840 } else {
14841 res = valuePop(ctxt);
14842 }
14843
14844 do {
14845 tmp = valuePop(ctxt);
14846 if (tmp != NULL) {
14847 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014848 stack++;
14849 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014850 }
14851 } while (tmp != NULL);
14852 if ((stack != 0) && (res != NULL)) {
14853 xmlGenericError(xmlGenericErrorContext,
14854 "xmlXPathEval: %d object left on the stack\n",
14855 stack);
14856 }
14857 if (ctxt->error != XPATH_EXPRESSION_OK) {
14858 xmlXPathFreeObject(res);
14859 res = NULL;
14860 }
14861
Owen Taylor3473f882001-02-23 17:55:21 +000014862 xmlXPathFreeParserContext(ctxt);
14863 return(res);
14864}
14865
14866/**
14867 * xmlXPathEvalExpression:
14868 * @str: the XPath expression
14869 * @ctxt: the XPath context
14870 *
14871 * Evaluate the XPath expression in the given context.
14872 *
14873 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14874 * the caller has to free the object.
14875 */
14876xmlXPathObjectPtr
14877xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14878 xmlXPathParserContextPtr pctxt;
14879 xmlXPathObjectPtr res, tmp;
14880 int stack = 0;
14881
William M. Brackf13f77f2004-11-12 16:03:48 +000014882 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014883
William M. Brackf13f77f2004-11-12 16:03:48 +000014884 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014885
14886 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014887 if (pctxt == NULL)
14888 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014889 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014890
Daniel Veillardc465ffc2006-10-17 19:39:33 +000014891 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000014892 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14893 res = NULL;
14894 } else {
14895 res = valuePop(pctxt);
14896 }
14897 do {
14898 tmp = valuePop(pctxt);
14899 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014900 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014901 stack++;
14902 }
14903 } while (tmp != NULL);
14904 if ((stack != 0) && (res != NULL)) {
14905 xmlGenericError(xmlGenericErrorContext,
14906 "xmlXPathEvalExpression: %d object left on the stack\n",
14907 stack);
14908 }
14909 xmlXPathFreeParserContext(pctxt);
14910 return(res);
14911}
14912
Daniel Veillard42766c02002-08-22 20:52:17 +000014913/************************************************************************
14914 * *
14915 * Extra functions not pertaining to the XPath spec *
14916 * *
14917 ************************************************************************/
14918/**
14919 * xmlXPathEscapeUriFunction:
14920 * @ctxt: the XPath Parser context
14921 * @nargs: the number of arguments
14922 *
14923 * Implement the escape-uri() XPath function
14924 * string escape-uri(string $str, bool $escape-reserved)
14925 *
14926 * This function applies the URI escaping rules defined in section 2 of [RFC
14927 * 2396] to the string supplied as $uri-part, which typically represents all
14928 * or part of a URI. The effect of the function is to replace any special
14929 * character in the string by an escape sequence of the form %xx%yy...,
14930 * where xxyy... is the hexadecimal representation of the octets used to
14931 * represent the character in UTF-8.
14932 *
14933 * The set of characters that are escaped depends on the setting of the
14934 * boolean argument $escape-reserved.
14935 *
14936 * If $escape-reserved is true, all characters are escaped other than lower
14937 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14938 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14939 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14940 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14941 * A-F).
14942 *
14943 * If $escape-reserved is false, the behavior differs in that characters
14944 * referred to in [RFC 2396] as reserved characters are not escaped. These
14945 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14946 *
14947 * [RFC 2396] does not define whether escaped URIs should use lower case or
14948 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14949 * compared using string comparison functions, this function must always use
14950 * the upper-case letters A-F.
14951 *
14952 * Generally, $escape-reserved should be set to true when escaping a string
14953 * that is to form a single part of a URI, and to false when escaping an
14954 * entire URI or URI reference.
14955 *
14956 * In the case of non-ascii characters, the string is encoded according to
14957 * utf-8 and then converted according to RFC 2396.
14958 *
14959 * Examples
14960 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14961 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14962 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14963 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14964 *
14965 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014966static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014967xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14968 xmlXPathObjectPtr str;
14969 int escape_reserved;
14970 xmlBufferPtr target;
14971 xmlChar *cptr;
14972 xmlChar escape[4];
14973
14974 CHECK_ARITY(2);
14975
14976 escape_reserved = xmlXPathPopBoolean(ctxt);
14977
14978 CAST_TO_STRING;
14979 str = valuePop(ctxt);
14980
14981 target = xmlBufferCreate();
14982
14983 escape[0] = '%';
14984 escape[3] = 0;
14985
14986 if (target) {
14987 for (cptr = str->stringval; *cptr; cptr++) {
14988 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14989 (*cptr >= 'a' && *cptr <= 'z') ||
14990 (*cptr >= '0' && *cptr <= '9') ||
14991 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14992 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14993 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14994 (*cptr == '%' &&
14995 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14996 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14997 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14998 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14999 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15000 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15001 (!escape_reserved &&
15002 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15003 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15004 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15005 *cptr == ','))) {
15006 xmlBufferAdd(target, cptr, 1);
15007 } else {
15008 if ((*cptr >> 4) < 10)
15009 escape[1] = '0' + (*cptr >> 4);
15010 else
15011 escape[1] = 'A' - 10 + (*cptr >> 4);
15012 if ((*cptr & 0xF) < 10)
15013 escape[2] = '0' + (*cptr & 0xF);
15014 else
15015 escape[2] = 'A' - 10 + (*cptr & 0xF);
15016
15017 xmlBufferAdd(target, &escape[0], 3);
15018 }
15019 }
15020 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015021 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15022 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015023 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015024 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015025}
15026
Owen Taylor3473f882001-02-23 17:55:21 +000015027/**
15028 * xmlXPathRegisterAllFunctions:
15029 * @ctxt: the XPath context
15030 *
15031 * Registers all default XPath functions in this context
15032 */
15033void
15034xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15035{
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15037 xmlXPathBooleanFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15039 xmlXPathCeilingFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15041 xmlXPathCountFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15043 xmlXPathConcatFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15045 xmlXPathContainsFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15047 xmlXPathIdFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15049 xmlXPathFalseFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15051 xmlXPathFloorFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15053 xmlXPathLastFunction);
15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15055 xmlXPathLangFunction);
15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15057 xmlXPathLocalNameFunction);
15058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15059 xmlXPathNotFunction);
15060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15061 xmlXPathNameFunction);
15062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15063 xmlXPathNamespaceURIFunction);
15064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15065 xmlXPathNormalizeFunction);
15066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15067 xmlXPathNumberFunction);
15068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15069 xmlXPathPositionFunction);
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15071 xmlXPathRoundFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15073 xmlXPathStringFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15075 xmlXPathStringLengthFunction);
15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15077 xmlXPathStartsWithFunction);
15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15079 xmlXPathSubstringFunction);
15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15081 xmlXPathSubstringBeforeFunction);
15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15083 xmlXPathSubstringAfterFunction);
15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15085 xmlXPathSumFunction);
15086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15087 xmlXPathTrueFunction);
15088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15089 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015090
15091 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15092 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15093 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015094}
15095
15096#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015097#define bottom_xpath
15098#include "elfgcchack.h"