blob: 20ab2734996e8b921d2f4087e67fa2d297c750d2 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005 *f
Owen Taylor3473f882001-02-23 17:55:21 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011 * See Copyright for the status of this software
Owen Taylor3473f882001-02-23 17:55:21 +000012 *
Daniel Veillardc5d64342001-06-24 12:13:24 +000013 * Author: daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +000014 *
Owen Taylor3473f882001-02-23 17:55:21 +000015 */
16
Daniel Veillard34ce8be2002-03-18 19:37:11 +000017#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000018#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000019
Owen Taylor3473f882001-02-23 17:55:21 +000020#include <string.h>
21
22#ifdef HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#ifdef HAVE_MATH_H
26#include <math.h>
27#endif
28#ifdef HAVE_FLOAT_H
29#include <float.h>
30#endif
Owen Taylor3473f882001-02-23 17:55:21 +000031#ifdef HAVE_CTYPE_H
32#include <ctype.h>
33#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000034#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000035#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000036#endif
Owen Taylor3473f882001-02-23 17:55:21 +000037
38#include <libxml/xmlmemory.h>
39#include <libxml/tree.h>
40#include <libxml/valid.h>
41#include <libxml/xpath.h>
42#include <libxml/xpathInternals.h>
43#include <libxml/parserInternals.h>
44#include <libxml/hash.h>
45#ifdef LIBXML_XPTR_ENABLED
46#include <libxml/xpointer.h>
47#endif
48#ifdef LIBXML_DEBUG_ENABLED
49#include <libxml/debugXML.h>
50#endif
51#include <libxml/xmlerror.h>
Daniel Veillard81463942001-10-16 12:34:39 +000052#include <libxml/threads.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000053#include <libxml/globals.h>
Daniel Veillard56de87e2005-02-16 00:22:29 +000054#ifdef LIBXML_PATTERN_ENABLED
55#include <libxml/pattern.h>
56#endif
57
58#ifdef LIBXML_PATTERN_ENABLED
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000059#define XPATH_STREAMING
Daniel Veillard56de87e2005-02-16 00:22:29 +000060#endif
Owen Taylor3473f882001-02-23 17:55:21 +000061
Daniel Veillardd96f6d32003-10-07 21:25:12 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
William M. Brackd1757ab2004-10-02 22:07:48 +000067/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000068* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000069* If defined, this will use xmlXPathCmpNodesExt() instead of
70* xmlXPathCmpNodes(). The new function is optimized comparison of
71* non-element nodes; actually it will speed up comparison only if
72* xmlXPathOrderDocElems() was called in order to index the elements of
73* a tree in document order; Libxslt does such an indexing, thus it will
74* benefit from this optimization.
75*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000076#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78/*
79* XP_OPTIMIZED_FILTER_FIRST:
80* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81* in a way, that it stop evaluation at the first node.
82*/
83#define XP_OPTIMIZED_FILTER_FIRST
84
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000085/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000086* XP_DEBUG_OBJ_USAGE:
87* Internal flag to enable tracking of how much XPath objects have been
88* created.
89*/
90/* #define XP_DEBUG_OBJ_USAGE */
91
92/*
William M. Brackd1757ab2004-10-02 22:07:48 +000093 * TODO:
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
97 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000098
William M. Brack21e4ef22005-01-02 09:53:13 +000099#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000100
101/************************************************************************
102 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000103 * Floating point stuff *
104 * *
105 ************************************************************************/
106
Daniel Veillardc0631a62001-09-20 13:56:06 +0000107#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000108#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000109#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000110#include "trionan.c"
111
Owen Taylor3473f882001-02-23 17:55:21 +0000112/*
Owen Taylor3473f882001-02-23 17:55:21 +0000113 * The lack of portability of this section of the libc is annoying !
114 */
115double xmlXPathNAN = 0;
116double xmlXPathPINF = 1;
117double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000118static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000119static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000120
Owen Taylor3473f882001-02-23 17:55:21 +0000121/**
122 * xmlXPathInit:
123 *
124 * Initialize the XPath environment
125 */
126void
127xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000128 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Bjorn Reese45029602001-08-21 09:23:53 +0000130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000133 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000134
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000135 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000136}
137
Daniel Veillardcda96922001-08-21 10:56:31 +0000138/**
139 * xmlXPathIsNaN:
140 * @val: a double value
141 *
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
145 *
146 * Returns 1 if the value is a NaN, 0 otherwise
147 */
148int
149xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
151}
152
153/**
154 * xmlXPathIsInf:
155 * @val: a double value
156 *
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
160 *
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
162 */
163int
164xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
166}
167
Daniel Veillard4432df22003-09-28 18:58:27 +0000168#endif /* SCHEMAS or XPATH */
169#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000170/**
171 * xmlXPathGetSign:
172 * @val: a double value
173 *
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
177 *
178 * Returns 1 if the value is Negative, 0 if positive
179 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000180static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000181xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000182 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000183}
184
185
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000186/*
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
189 */
190/* #define DEBUG */
191/* #define DEBUG_STEP */
192/* #define DEBUG_STEP_NTH */
193/* #define DEBUG_EXPR */
194/* #define DEBUG_EVAL_COUNTS */
195
196static xmlNs xmlXPathXMLNamespaceStruct = {
197 NULL,
198 XML_NAMESPACE_DECL,
199 XML_XML_NAMESPACE,
200 BAD_CAST "xml",
William M. Brackee0b9822007-03-07 08:15:01 +0000201 NULL,
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000202 NULL
203};
204static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205#ifndef LIBXML_THREAD_ENABLED
206/*
207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
209 */
210static int xmlXPathDisableOptimizer = 0;
211#endif
212
Owen Taylor3473f882001-02-23 17:55:21 +0000213/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000214 * *
215 * Error handling routines *
216 * *
217 ************************************************************************/
218
Daniel Veillard24505b02005-07-28 23:49:35 +0000219/**
220 * XP_ERRORNULL:
221 * @X: the error code
222 *
223 * Macro to raise an XPath error and return NULL.
224 */
225#define XP_ERRORNULL(X) \
226 { xmlXPathErr(ctxt, X); return(NULL); }
227
William M. Brack08171912003-12-29 02:52:11 +0000228/*
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000231static const char *xmlXPathErrorMessages[] = {
232 "Ok\n",
233 "Number encoding\n",
234 "Unfinished literal\n",
235 "Start of literal\n",
236 "Expected $ for variable reference\n",
237 "Undefined variable\n",
238 "Invalid predicate\n",
239 "Invalid expression\n",
240 "Missing closing curly brace\n",
241 "Unregistered function\n",
242 "Invalid operand\n",
243 "Invalid type\n",
244 "Invalid number of arguments\n",
245 "Invalid context size\n",
246 "Invalid context position\n",
247 "Memory allocation error\n",
248 "Syntax error\n",
249 "Resource error\n",
250 "Sub resource error\n",
251 "Undefined namespace prefix\n",
252 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000253 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000254 "Invalid or incomplete context\n",
255 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000256};
William M. Brackcd65bc92005-01-06 09:39:18 +0000257#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
258 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259/**
260 * xmlXPathErrMemory:
261 * @ctxt: an XPath context
262 * @extra: extra informations
263 *
264 * Handle a redefinition of attribute error
265 */
266static void
267xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
268{
269 if (ctxt != NULL) {
270 if (extra) {
271 xmlChar buf[200];
272
273 xmlStrPrintf(buf, 200,
274 BAD_CAST "Memory allocation failed : %s\n",
275 extra);
276 ctxt->lastError.message = (char *) xmlStrdup(buf);
277 } else {
278 ctxt->lastError.message = (char *)
279 xmlStrdup(BAD_CAST "Memory allocation failed\n");
280 }
281 ctxt->lastError.domain = XML_FROM_XPATH;
282 ctxt->lastError.code = XML_ERR_NO_MEMORY;
283 if (ctxt->error != NULL)
284 ctxt->error(ctxt->userData, &ctxt->lastError);
285 } else {
286 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000287 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 NULL, NULL, XML_FROM_XPATH,
289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290 extra, NULL, NULL, 0, 0,
291 "Memory allocation failed : %s\n", extra);
292 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000293 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000294 NULL, NULL, XML_FROM_XPATH,
295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296 NULL, NULL, NULL, 0, 0,
297 "Memory allocation failed\n");
298 }
299}
300
301/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000302 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000303 * @ctxt: an XPath parser context
304 * @extra: extra informations
305 *
306 * Handle a redefinition of attribute error
307 */
308static void
309xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
310{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000311 if (ctxt == NULL)
312 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000313 else {
314 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000315 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000316 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000317}
318
319/**
320 * xmlXPathErr:
321 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000322 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000324 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000325 */
326void
327xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328{
William M. Brackcd65bc92005-01-06 09:39:18 +0000329 if ((error < 0) || (error > MAXERRNO))
330 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000331 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000332 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000333 NULL, NULL, XML_FROM_XPATH,
334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335 XML_ERR_ERROR, NULL, 0,
336 NULL, NULL, NULL, 0, 0,
337 xmlXPathErrorMessages[error]);
338 return;
339 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000340 ctxt->error = error;
341 if (ctxt->context == NULL) {
342 __xmlRaiseError(NULL, NULL, NULL,
343 NULL, NULL, XML_FROM_XPATH,
344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345 XML_ERR_ERROR, NULL, 0,
346 (const char *) ctxt->base, NULL, NULL,
347 ctxt->cur - ctxt->base, 0,
348 xmlXPathErrorMessages[error]);
349 return;
350 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000351
352 /* cleanup current last error */
353 xmlResetError(&ctxt->context->lastError);
354
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000355 ctxt->context->lastError.domain = XML_FROM_XPATH;
356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000358 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361 ctxt->context->lastError.node = ctxt->context->debugNode;
362 if (ctxt->context->error != NULL) {
363 ctxt->context->error(ctxt->context->userData,
364 &ctxt->context->lastError);
365 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000366 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000367 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369 XML_ERR_ERROR, NULL, 0,
370 (const char *) ctxt->base, NULL, NULL,
371 ctxt->cur - ctxt->base, 0,
372 xmlXPathErrorMessages[error]);
373 }
374
375}
376
377/**
378 * xmlXPatherror:
379 * @ctxt: the XPath Parser context
380 * @file: the file name
381 * @line: the line number
382 * @no: the error number
383 *
384 * Formats an error message.
385 */
386void
387xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388 int line ATTRIBUTE_UNUSED, int no) {
389 xmlXPathErr(ctxt, no);
390}
391
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000392/************************************************************************
393 * *
394 * Utilities *
395 * *
396 ************************************************************************/
397
398/**
399 * xsltPointerList:
400 *
401 * Pointer-list for various purposes.
402 */
403typedef struct _xmlPointerList xmlPointerList;
404typedef xmlPointerList *xmlPointerListPtr;
405struct _xmlPointerList {
406 void **items;
407 int number;
408 int size;
409};
410/*
411* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412* and here, we should make the functions public.
413*/
414static int
415xmlPointerListAddSize(xmlPointerListPtr list,
416 void *item,
417 int initialSize)
418{
419 if (list->items == NULL) {
420 if (initialSize <= 0)
421 initialSize = 1;
422 list->items = (void **) xmlMalloc(
423 initialSize * sizeof(void *));
424 if (list->items == NULL) {
425 xmlXPathErrMemory(NULL,
426 "xmlPointerListCreate: allocating item\n");
427 return(-1);
428 }
429 list->number = 0;
430 list->size = initialSize;
431 } else if (list->size <= list->number) {
432 list->size *= 2;
433 list->items = (void **) xmlRealloc(list->items,
434 list->size * sizeof(void *));
435 if (list->items == NULL) {
436 xmlXPathErrMemory(NULL,
437 "xmlPointerListCreate: re-allocating item\n");
438 list->size = 0;
439 return(-1);
440 }
441 }
442 list->items[list->number++] = item;
443 return(0);
444}
445
446/**
447 * xsltPointerListCreate:
448 *
449 * Creates an xsltPointerList structure.
450 *
451 * Returns a xsltPointerList structure or NULL in case of an error.
452 */
453static xmlPointerListPtr
454xmlPointerListCreate(int initialSize)
455{
456 xmlPointerListPtr ret;
457
458 ret = xmlMalloc(sizeof(xmlPointerList));
459 if (ret == NULL) {
460 xmlXPathErrMemory(NULL,
461 "xmlPointerListCreate: allocating item\n");
462 return (NULL);
463 }
464 memset(ret, 0, sizeof(xmlPointerList));
465 if (initialSize > 0) {
466 xmlPointerListAddSize(ret, NULL, initialSize);
467 ret->number = 0;
468 }
469 return (ret);
470}
471
472/**
473 * xsltPointerListFree:
474 *
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
477 */
478static void
479xmlPointerListFree(xmlPointerListPtr list)
480{
481 if (list == NULL)
482 return;
483 if (list->items != NULL)
484 xmlFree(list->items);
485 xmlFree(list);
486}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000487
488/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489 * *
490 * Parser Types *
491 * *
492 ************************************************************************/
493
494/*
495 * Types are private:
496 */
497
498typedef enum {
499 XPATH_OP_END=0,
500 XPATH_OP_AND,
501 XPATH_OP_OR,
502 XPATH_OP_EQUAL,
503 XPATH_OP_CMP,
504 XPATH_OP_PLUS,
505 XPATH_OP_MULT,
506 XPATH_OP_UNION,
507 XPATH_OP_ROOT,
508 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000509 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000510 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000511 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000512 XPATH_OP_VARIABLE,
513 XPATH_OP_FUNCTION,
514 XPATH_OP_ARG,
515 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000516 XPATH_OP_FILTER, /* 17 */
517 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000518#ifdef LIBXML_XPTR_ENABLED
519 ,XPATH_OP_RANGETO
520#endif
521} xmlXPathOp;
522
523typedef enum {
524 AXIS_ANCESTOR = 1,
525 AXIS_ANCESTOR_OR_SELF,
526 AXIS_ATTRIBUTE,
527 AXIS_CHILD,
528 AXIS_DESCENDANT,
529 AXIS_DESCENDANT_OR_SELF,
530 AXIS_FOLLOWING,
531 AXIS_FOLLOWING_SIBLING,
532 AXIS_NAMESPACE,
533 AXIS_PARENT,
534 AXIS_PRECEDING,
535 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000536 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000537} xmlXPathAxisVal;
538
539typedef enum {
540 NODE_TEST_NONE = 0,
541 NODE_TEST_TYPE = 1,
542 NODE_TEST_PI = 2,
543 NODE_TEST_ALL = 3,
544 NODE_TEST_NS = 4,
545 NODE_TEST_NAME = 5
546} xmlXPathTestVal;
547
548typedef enum {
549 NODE_TYPE_NODE = 0,
550 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000552 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553} xmlXPathTypeVal;
554
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000555#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000556
557typedef struct _xmlXPathStepOp xmlXPathStepOp;
558typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000560 xmlXPathOp op; /* The identifier of the operation */
561 int ch1; /* First child */
562 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000563 int value;
564 int value2;
565 int value3;
566 void *value4;
567 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000568 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000569 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000570 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000571};
572
573struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000574 int nbStep; /* Number of steps in this expression */
575 int maxStep; /* Maximum number of steps allocated */
576 xmlXPathStepOp *steps; /* ops for computation of this expression */
577 int last; /* index of last step in expression */
578 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000579 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000580#ifdef DEBUG_EVAL_COUNTS
581 int nb;
582 xmlChar *string;
583#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000584#ifdef XPATH_STREAMING
585 xmlPatternPtr stream;
586#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000587};
588
589/************************************************************************
590 * *
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000591 * Forward declarations *
592 * *
593 ************************************************************************/
594static void
595xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596static void
597xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598static int
599xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600 xmlXPathStepOpPtr op, xmlNodePtr *first);
601static int
602xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +0000603 xmlXPathStepOpPtr op,
604 int isPredicate);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +0000605
606/************************************************************************
607 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000608 * Parser Type functions *
609 * *
610 ************************************************************************/
611
612/**
613 * xmlXPathNewCompExpr:
614 *
615 * Create a new Xpath component
616 *
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000619static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000620xmlXPathNewCompExpr(void) {
621 xmlXPathCompExprPtr cur;
622
623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000625 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626 return(NULL);
627 }
628 memset(cur, 0, sizeof(xmlXPathCompExpr));
629 cur->maxStep = 10;
630 cur->nbStep = 0;
631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632 sizeof(xmlXPathStepOp));
633 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000634 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000635 xmlFree(cur);
636 return(NULL);
637 }
638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000640#ifdef DEBUG_EVAL_COUNTS
641 cur->nb = 0;
642#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000643 return(cur);
644}
645
646/**
647 * xmlXPathFreeCompExpr:
648 * @comp: an XPATH comp
649 *
650 * Free up the memory allocated by @comp
651 */
652void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000653xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000655 xmlXPathStepOpPtr op;
656 int i;
657
658 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000659 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000660 if (comp->dict == NULL) {
661 for (i = 0; i < comp->nbStep; i++) {
662 op = &comp->steps[i];
663 if (op->value4 != NULL) {
664 if (op->op == XPATH_OP_VALUE)
665 xmlXPathFreeObject(op->value4);
666 else
667 xmlFree(op->value4);
668 }
669 if (op->value5 != NULL)
670 xmlFree(op->value5);
671 }
672 } else {
673 for (i = 0; i < comp->nbStep; i++) {
674 op = &comp->steps[i];
675 if (op->value4 != NULL) {
676 if (op->op == XPATH_OP_VALUE)
677 xmlXPathFreeObject(op->value4);
678 }
679 }
680 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000681 }
682 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000683 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000685#ifdef DEBUG_EVAL_COUNTS
686 if (comp->string != NULL) {
687 xmlFree(comp->string);
688 }
689#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000690#ifdef XPATH_STREAMING
691 if (comp->stream != NULL) {
692 xmlFreePatternList(comp->stream);
693 }
694#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000695 if (comp->expr != NULL) {
696 xmlFree(comp->expr);
697 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000698
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000699 xmlFree(comp);
700}
701
702/**
703 * xmlXPathCompExprAdd:
704 * @comp: the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
707 * @op: an op
708 * @value: the first int value
709 * @value2: the second int value
710 * @value3: the third int value
711 * @value4: the first string value
712 * @value5: the second string value
713 *
William M. Brack08171912003-12-29 02:52:11 +0000714 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000715 *
716 * Returns -1 in case of failure, the index otherwise
717 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000718static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000719xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720 xmlXPathOp op, int value,
721 int value2, int value3, void *value4, void *value5) {
722 if (comp->nbStep >= comp->maxStep) {
723 xmlXPathStepOp *real;
724
725 comp->maxStep *= 2;
726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727 comp->maxStep * sizeof(xmlXPathStepOp));
728 if (real == NULL) {
729 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000730 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000731 return(-1);
732 }
733 comp->steps = real;
734 }
735 comp->last = comp->nbStep;
Kasimier T. Buchcik6422d912006-06-26 14:31:53 +0000736 comp->steps[comp->nbStep].rewriteType = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000737 comp->steps[comp->nbStep].ch1 = ch1;
738 comp->steps[comp->nbStep].ch2 = ch2;
739 comp->steps[comp->nbStep].op = op;
740 comp->steps[comp->nbStep].value = value;
741 comp->steps[comp->nbStep].value2 = value2;
742 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000743 if ((comp->dict != NULL) &&
744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745 (op == XPATH_OP_COLLECT))) {
746 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000747 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000748 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000749 xmlFree(value4);
750 } else
751 comp->steps[comp->nbStep].value4 = NULL;
752 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000753 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000754 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000755 xmlFree(value5);
756 } else
757 comp->steps[comp->nbStep].value5 = NULL;
758 } else {
759 comp->steps[comp->nbStep].value4 = value4;
760 comp->steps[comp->nbStep].value5 = value5;
761 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000762 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000763 return(comp->nbStep++);
764}
765
Daniel Veillardf06307e2001-07-03 10:35:50 +0000766/**
767 * xmlXPathCompSwap:
768 * @comp: the compiled expression
769 * @op: operation index
770 *
771 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000772 */
773static void
774xmlXPathCompSwap(xmlXPathStepOpPtr op) {
775 int tmp;
776
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000777#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000778 /*
779 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000780 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000781 * application
782 */
783 if (xmlXPathDisableOptimizer)
784 return;
785#endif
786
Daniel Veillardf06307e2001-07-03 10:35:50 +0000787 tmp = op->ch1;
788 op->ch1 = op->ch2;
789 op->ch2 = tmp;
790}
791
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000792#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
794 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000795#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
797 (op), (val), (val2), (val3), (val4), (val5))
798
799#define PUSH_LEAVE_EXPR(op, val, val2) \
800xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801
802#define PUSH_UNARY_EXPR(op, ch, val, val2) \
803xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804
805#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000806xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
807 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000808
809/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000810 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000811 * XPath object cache structures *
812 * *
813 ************************************************************************/
814
815/* #define XP_DEFAULT_CACHE_ON */
816
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000817#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000818
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000819typedef struct _xmlXPathContextCache xmlXPathContextCache;
820typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000827 int maxNodeset;
828 int maxString;
829 int maxBoolean;
830 int maxNumber;
831 int maxMisc;
832#ifdef XP_DEBUG_OBJ_USAGE
833 int dbgCachedAll;
834 int dbgCachedNodeset;
835 int dbgCachedString;
836 int dbgCachedBool;
837 int dbgCachedNumber;
838 int dbgCachedPoint;
839 int dbgCachedRange;
840 int dbgCachedLocset;
841 int dbgCachedUsers;
842 int dbgCachedXSLTTree;
843 int dbgCachedUndefined;
844
845
846 int dbgReusedAll;
847 int dbgReusedNodeset;
848 int dbgReusedString;
849 int dbgReusedBool;
850 int dbgReusedNumber;
851 int dbgReusedPoint;
852 int dbgReusedRange;
853 int dbgReusedLocset;
854 int dbgReusedUsers;
855 int dbgReusedXSLTTree;
856 int dbgReusedUndefined;
857
858#endif
859};
860
861/************************************************************************
862 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000863 * Debugging related functions *
864 * *
865 ************************************************************************/
866
Owen Taylor3473f882001-02-23 17:55:21 +0000867#define STRANGE \
868 xmlGenericError(xmlGenericErrorContext, \
869 "Internal error at %s:%d\n", \
870 __FILE__, __LINE__);
871
872#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000873static void
874xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000875 int i;
876 char shift[100];
877
878 for (i = 0;((i < depth) && (i < 25));i++)
879 shift[2 * i] = shift[2 * i + 1] = ' ';
880 shift[2 * i] = shift[2 * i + 1] = 0;
881 if (cur == NULL) {
882 fprintf(output, shift);
883 fprintf(output, "Node is NULL !\n");
884 return;
885
886 }
887
888 if ((cur->type == XML_DOCUMENT_NODE) ||
889 (cur->type == XML_HTML_DOCUMENT_NODE)) {
890 fprintf(output, shift);
891 fprintf(output, " /\n");
892 } else if (cur->type == XML_ATTRIBUTE_NODE)
893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894 else
895 xmlDebugDumpOneNode(output, cur, depth);
896}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000897static void
898xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000899 xmlNodePtr tmp;
900 int i;
901 char shift[100];
902
903 for (i = 0;((i < depth) && (i < 25));i++)
904 shift[2 * i] = shift[2 * i + 1] = ' ';
905 shift[2 * i] = shift[2 * i + 1] = 0;
906 if (cur == NULL) {
907 fprintf(output, shift);
908 fprintf(output, "Node is NULL !\n");
909 return;
910
911 }
912
913 while (cur != NULL) {
914 tmp = cur;
915 cur = cur->next;
916 xmlDebugDumpOneNode(output, tmp, depth);
917 }
918}
Owen Taylor3473f882001-02-23 17:55:21 +0000919
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000920static void
921xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000922 int i;
923 char shift[100];
924
925 for (i = 0;((i < depth) && (i < 25));i++)
926 shift[2 * i] = shift[2 * i + 1] = ' ';
927 shift[2 * i] = shift[2 * i + 1] = 0;
928
929 if (cur == NULL) {
930 fprintf(output, shift);
931 fprintf(output, "NodeSet is NULL !\n");
932 return;
933
934 }
935
Daniel Veillard911f49a2001-04-07 15:39:35 +0000936 if (cur != NULL) {
937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938 for (i = 0;i < cur->nodeNr;i++) {
939 fprintf(output, shift);
940 fprintf(output, "%d", i + 1);
941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
942 }
Owen Taylor3473f882001-02-23 17:55:21 +0000943 }
944}
945
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000946static void
947xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000948 int i;
949 char shift[100];
950
951 for (i = 0;((i < depth) && (i < 25));i++)
952 shift[2 * i] = shift[2 * i + 1] = ' ';
953 shift[2 * i] = shift[2 * i + 1] = 0;
954
955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956 fprintf(output, shift);
957 fprintf(output, "Value Tree is NULL !\n");
958 return;
959
960 }
961
962 fprintf(output, shift);
963 fprintf(output, "%d", i + 1);
964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965}
Owen Taylor3473f882001-02-23 17:55:21 +0000966#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000967static void
968xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000969 int i;
970 char shift[100];
971
972 for (i = 0;((i < depth) && (i < 25));i++)
973 shift[2 * i] = shift[2 * i + 1] = ' ';
974 shift[2 * i] = shift[2 * i + 1] = 0;
975
976 if (cur == NULL) {
977 fprintf(output, shift);
978 fprintf(output, "LocationSet is NULL !\n");
979 return;
980
981 }
982
983 for (i = 0;i < cur->locNr;i++) {
984 fprintf(output, shift);
985 fprintf(output, "%d : ", i + 1);
986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
987 }
988}
Daniel Veillard017b1082001-06-21 11:20:21 +0000989#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000990
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000991/**
992 * xmlXPathDebugDumpObject:
993 * @output: the FILE * to dump the output
994 * @cur: the object to inspect
995 * @depth: indentation level
996 *
997 * Dump the content of the object for debugging purposes
998 */
999void
1000xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001001 int i;
1002 char shift[100];
1003
Daniel Veillarda82b1822004-11-08 16:24:57 +00001004 if (output == NULL) return;
1005
Owen Taylor3473f882001-02-23 17:55:21 +00001006 for (i = 0;((i < depth) && (i < 25));i++)
1007 shift[2 * i] = shift[2 * i + 1] = ' ';
1008 shift[2 * i] = shift[2 * i + 1] = 0;
1009
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001010
1011 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001012
1013 if (cur == NULL) {
1014 fprintf(output, "Object is empty (NULL)\n");
1015 return;
1016 }
1017 switch(cur->type) {
1018 case XPATH_UNDEFINED:
1019 fprintf(output, "Object is uninitialized\n");
1020 break;
1021 case XPATH_NODESET:
1022 fprintf(output, "Object is a Node Set :\n");
1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024 break;
1025 case XPATH_XSLT_TREE:
1026 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001028 break;
1029 case XPATH_BOOLEAN:
1030 fprintf(output, "Object is a Boolean : ");
1031 if (cur->boolval) fprintf(output, "true\n");
1032 else fprintf(output, "false\n");
1033 break;
1034 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001035 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001036 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001037 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001038 break;
1039 case -1:
1040 fprintf(output, "Object is a number : -Infinity\n");
1041 break;
1042 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001043 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001044 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001047 } else {
1048 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1049 }
1050 }
Owen Taylor3473f882001-02-23 17:55:21 +00001051 break;
1052 case XPATH_STRING:
1053 fprintf(output, "Object is a string : ");
1054 xmlDebugDumpString(output, cur->stringval);
1055 fprintf(output, "\n");
1056 break;
1057 case XPATH_POINT:
1058 fprintf(output, "Object is a point : index %d in node", cur->index);
1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060 fprintf(output, "\n");
1061 break;
1062 case XPATH_RANGE:
1063 if ((cur->user2 == NULL) ||
1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065 fprintf(output, "Object is a collapsed range :\n");
1066 fprintf(output, shift);
1067 if (cur->index >= 0)
1068 fprintf(output, "index %d in ", cur->index);
1069 fprintf(output, "node\n");
1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1071 depth + 1);
1072 } else {
1073 fprintf(output, "Object is a range :\n");
1074 fprintf(output, shift);
1075 fprintf(output, "From ");
1076 if (cur->index >= 0)
1077 fprintf(output, "index %d in ", cur->index);
1078 fprintf(output, "node\n");
1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080 depth + 1);
1081 fprintf(output, shift);
1082 fprintf(output, "To ");
1083 if (cur->index2 >= 0)
1084 fprintf(output, "index %d in ", cur->index2);
1085 fprintf(output, "node\n");
1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087 depth + 1);
1088 fprintf(output, "\n");
1089 }
1090 break;
1091 case XPATH_LOCATIONSET:
1092#if defined(LIBXML_XPTR_ENABLED)
1093 fprintf(output, "Object is a Location Set:\n");
1094 xmlXPathDebugDumpLocationSet(output,
1095 (xmlLocationSetPtr) cur->user, depth);
1096#endif
1097 break;
1098 case XPATH_USERS:
1099 fprintf(output, "Object is user defined\n");
1100 break;
1101 }
1102}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001103
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001104static void
1105xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001106 xmlXPathStepOpPtr op, int depth) {
1107 int i;
1108 char shift[100];
1109
1110 for (i = 0;((i < depth) && (i < 25));i++)
1111 shift[2 * i] = shift[2 * i + 1] = ' ';
1112 shift[2 * i] = shift[2 * i + 1] = 0;
1113
1114 fprintf(output, shift);
1115 if (op == NULL) {
1116 fprintf(output, "Step is NULL\n");
1117 return;
1118 }
1119 switch (op->op) {
1120 case XPATH_OP_END:
1121 fprintf(output, "END"); break;
1122 case XPATH_OP_AND:
1123 fprintf(output, "AND"); break;
1124 case XPATH_OP_OR:
1125 fprintf(output, "OR"); break;
1126 case XPATH_OP_EQUAL:
1127 if (op->value)
1128 fprintf(output, "EQUAL =");
1129 else
1130 fprintf(output, "EQUAL !=");
1131 break;
1132 case XPATH_OP_CMP:
1133 if (op->value)
1134 fprintf(output, "CMP <");
1135 else
1136 fprintf(output, "CMP >");
1137 if (!op->value2)
1138 fprintf(output, "=");
1139 break;
1140 case XPATH_OP_PLUS:
1141 if (op->value == 0)
1142 fprintf(output, "PLUS -");
1143 else if (op->value == 1)
1144 fprintf(output, "PLUS +");
1145 else if (op->value == 2)
1146 fprintf(output, "PLUS unary -");
1147 else if (op->value == 3)
1148 fprintf(output, "PLUS unary - -");
1149 break;
1150 case XPATH_OP_MULT:
1151 if (op->value == 0)
1152 fprintf(output, "MULT *");
1153 else if (op->value == 1)
1154 fprintf(output, "MULT div");
1155 else
1156 fprintf(output, "MULT mod");
1157 break;
1158 case XPATH_OP_UNION:
1159 fprintf(output, "UNION"); break;
1160 case XPATH_OP_ROOT:
1161 fprintf(output, "ROOT"); break;
1162 case XPATH_OP_NODE:
1163 fprintf(output, "NODE"); break;
1164 case XPATH_OP_RESET:
1165 fprintf(output, "RESET"); break;
1166 case XPATH_OP_SORT:
1167 fprintf(output, "SORT"); break;
1168 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001172 const xmlChar *prefix = op->value4;
1173 const xmlChar *name = op->value5;
1174
1175 fprintf(output, "COLLECT ");
1176 switch (axis) {
1177 case AXIS_ANCESTOR:
1178 fprintf(output, " 'ancestors' "); break;
1179 case AXIS_ANCESTOR_OR_SELF:
1180 fprintf(output, " 'ancestors-or-self' "); break;
1181 case AXIS_ATTRIBUTE:
1182 fprintf(output, " 'attributes' "); break;
1183 case AXIS_CHILD:
1184 fprintf(output, " 'child' "); break;
1185 case AXIS_DESCENDANT:
1186 fprintf(output, " 'descendant' "); break;
1187 case AXIS_DESCENDANT_OR_SELF:
1188 fprintf(output, " 'descendant-or-self' "); break;
1189 case AXIS_FOLLOWING:
1190 fprintf(output, " 'following' "); break;
1191 case AXIS_FOLLOWING_SIBLING:
1192 fprintf(output, " 'following-siblings' "); break;
1193 case AXIS_NAMESPACE:
1194 fprintf(output, " 'namespace' "); break;
1195 case AXIS_PARENT:
1196 fprintf(output, " 'parent' "); break;
1197 case AXIS_PRECEDING:
1198 fprintf(output, " 'preceding' "); break;
1199 case AXIS_PRECEDING_SIBLING:
1200 fprintf(output, " 'preceding-sibling' "); break;
1201 case AXIS_SELF:
1202 fprintf(output, " 'self' "); break;
1203 }
1204 switch (test) {
1205 case NODE_TEST_NONE:
1206 fprintf(output, "'none' "); break;
1207 case NODE_TEST_TYPE:
1208 fprintf(output, "'type' "); break;
1209 case NODE_TEST_PI:
1210 fprintf(output, "'PI' "); break;
1211 case NODE_TEST_ALL:
1212 fprintf(output, "'all' "); break;
1213 case NODE_TEST_NS:
1214 fprintf(output, "'namespace' "); break;
1215 case NODE_TEST_NAME:
1216 fprintf(output, "'name' "); break;
1217 }
1218 switch (type) {
1219 case NODE_TYPE_NODE:
1220 fprintf(output, "'node' "); break;
1221 case NODE_TYPE_COMMENT:
1222 fprintf(output, "'comment' "); break;
1223 case NODE_TYPE_TEXT:
1224 fprintf(output, "'text' "); break;
1225 case NODE_TYPE_PI:
1226 fprintf(output, "'PI' "); break;
1227 }
1228 if (prefix != NULL)
1229 fprintf(output, "%s:", prefix);
1230 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001231 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001232 break;
1233
1234 }
1235 case XPATH_OP_VALUE: {
1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237
1238 fprintf(output, "ELEM ");
1239 xmlXPathDebugDumpObject(output, object, 0);
1240 goto finish;
1241 }
1242 case XPATH_OP_VARIABLE: {
1243 const xmlChar *prefix = op->value5;
1244 const xmlChar *name = op->value4;
1245
1246 if (prefix != NULL)
1247 fprintf(output, "VARIABLE %s:%s", prefix, name);
1248 else
1249 fprintf(output, "VARIABLE %s", name);
1250 break;
1251 }
1252 case XPATH_OP_FUNCTION: {
1253 int nbargs = op->value;
1254 const xmlChar *prefix = op->value5;
1255 const xmlChar *name = op->value4;
1256
1257 if (prefix != NULL)
1258 fprintf(output, "FUNCTION %s:%s(%d args)",
1259 prefix, name, nbargs);
1260 else
1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1262 break;
1263 }
1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001267#ifdef LIBXML_XPTR_ENABLED
1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1269#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001270 default:
1271 fprintf(output, "UNKNOWN %d\n", op->op); return;
1272 }
1273 fprintf(output, "\n");
1274finish:
1275 if (op->ch1 >= 0)
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277 if (op->ch2 >= 0)
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1279}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001280
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001281/**
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output: the FILE * for the output
1284 * @comp: the precompiled XPath expression
1285 * @depth: the indentation level.
1286 *
1287 * Dumps the tree of the compiled XPath expression.
1288 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001289void
1290xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1291 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001292 int i;
1293 char shift[100];
1294
Daniel Veillarda82b1822004-11-08 16:24:57 +00001295 if ((output == NULL) || (comp == NULL)) return;
1296
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001297 for (i = 0;((i < depth) && (i < 25));i++)
1298 shift[2 * i] = shift[2 * i + 1] = ' ';
1299 shift[2 * i] = shift[2 * i + 1] = 0;
1300
1301 fprintf(output, shift);
1302
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001303 fprintf(output, "Compiled Expression : %d elements\n",
1304 comp->nbStep);
1305 i = comp->last;
1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1307}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001308
1309#ifdef XP_DEBUG_OBJ_USAGE
1310
1311/*
1312* XPath object usage related debugging variables.
1313*/
1314static int xmlXPathDebugObjCounterUndefined = 0;
1315static int xmlXPathDebugObjCounterNodeset = 0;
1316static int xmlXPathDebugObjCounterBool = 0;
1317static int xmlXPathDebugObjCounterNumber = 0;
1318static int xmlXPathDebugObjCounterString = 0;
1319static int xmlXPathDebugObjCounterPoint = 0;
1320static int xmlXPathDebugObjCounterRange = 0;
1321static int xmlXPathDebugObjCounterLocset = 0;
1322static int xmlXPathDebugObjCounterUsers = 0;
1323static int xmlXPathDebugObjCounterXSLTTree = 0;
1324static int xmlXPathDebugObjCounterAll = 0;
1325
1326static int xmlXPathDebugObjTotalUndefined = 0;
1327static int xmlXPathDebugObjTotalNodeset = 0;
1328static int xmlXPathDebugObjTotalBool = 0;
1329static int xmlXPathDebugObjTotalNumber = 0;
1330static int xmlXPathDebugObjTotalString = 0;
1331static int xmlXPathDebugObjTotalPoint = 0;
1332static int xmlXPathDebugObjTotalRange = 0;
1333static int xmlXPathDebugObjTotalLocset = 0;
1334static int xmlXPathDebugObjTotalUsers = 0;
1335static int xmlXPathDebugObjTotalXSLTTree = 0;
1336static int xmlXPathDebugObjTotalAll = 0;
1337
1338static int xmlXPathDebugObjMaxUndefined = 0;
1339static int xmlXPathDebugObjMaxNodeset = 0;
1340static int xmlXPathDebugObjMaxBool = 0;
1341static int xmlXPathDebugObjMaxNumber = 0;
1342static int xmlXPathDebugObjMaxString = 0;
1343static int xmlXPathDebugObjMaxPoint = 0;
1344static int xmlXPathDebugObjMaxRange = 0;
1345static int xmlXPathDebugObjMaxLocset = 0;
1346static int xmlXPathDebugObjMaxUsers = 0;
1347static int xmlXPathDebugObjMaxXSLTTree = 0;
1348static int xmlXPathDebugObjMaxAll = 0;
1349
1350/* REVISIT TODO: Make this static when committing */
1351static void
1352xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1353{
1354 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001355 if (ctxt->cache != NULL) {
1356 xmlXPathContextCachePtr cache =
1357 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001358
1359 cache->dbgCachedAll = 0;
1360 cache->dbgCachedNodeset = 0;
1361 cache->dbgCachedString = 0;
1362 cache->dbgCachedBool = 0;
1363 cache->dbgCachedNumber = 0;
1364 cache->dbgCachedPoint = 0;
1365 cache->dbgCachedRange = 0;
1366 cache->dbgCachedLocset = 0;
1367 cache->dbgCachedUsers = 0;
1368 cache->dbgCachedXSLTTree = 0;
1369 cache->dbgCachedUndefined = 0;
1370
1371 cache->dbgReusedAll = 0;
1372 cache->dbgReusedNodeset = 0;
1373 cache->dbgReusedString = 0;
1374 cache->dbgReusedBool = 0;
1375 cache->dbgReusedNumber = 0;
1376 cache->dbgReusedPoint = 0;
1377 cache->dbgReusedRange = 0;
1378 cache->dbgReusedLocset = 0;
1379 cache->dbgReusedUsers = 0;
1380 cache->dbgReusedXSLTTree = 0;
1381 cache->dbgReusedUndefined = 0;
1382 }
1383 }
1384
1385 xmlXPathDebugObjCounterUndefined = 0;
1386 xmlXPathDebugObjCounterNodeset = 0;
1387 xmlXPathDebugObjCounterBool = 0;
1388 xmlXPathDebugObjCounterNumber = 0;
1389 xmlXPathDebugObjCounterString = 0;
1390 xmlXPathDebugObjCounterPoint = 0;
1391 xmlXPathDebugObjCounterRange = 0;
1392 xmlXPathDebugObjCounterLocset = 0;
1393 xmlXPathDebugObjCounterUsers = 0;
1394 xmlXPathDebugObjCounterXSLTTree = 0;
1395 xmlXPathDebugObjCounterAll = 0;
1396
1397 xmlXPathDebugObjTotalUndefined = 0;
1398 xmlXPathDebugObjTotalNodeset = 0;
1399 xmlXPathDebugObjTotalBool = 0;
1400 xmlXPathDebugObjTotalNumber = 0;
1401 xmlXPathDebugObjTotalString = 0;
1402 xmlXPathDebugObjTotalPoint = 0;
1403 xmlXPathDebugObjTotalRange = 0;
1404 xmlXPathDebugObjTotalLocset = 0;
1405 xmlXPathDebugObjTotalUsers = 0;
1406 xmlXPathDebugObjTotalXSLTTree = 0;
1407 xmlXPathDebugObjTotalAll = 0;
1408
1409 xmlXPathDebugObjMaxUndefined = 0;
1410 xmlXPathDebugObjMaxNodeset = 0;
1411 xmlXPathDebugObjMaxBool = 0;
1412 xmlXPathDebugObjMaxNumber = 0;
1413 xmlXPathDebugObjMaxString = 0;
1414 xmlXPathDebugObjMaxPoint = 0;
1415 xmlXPathDebugObjMaxRange = 0;
1416 xmlXPathDebugObjMaxLocset = 0;
1417 xmlXPathDebugObjMaxUsers = 0;
1418 xmlXPathDebugObjMaxXSLTTree = 0;
1419 xmlXPathDebugObjMaxAll = 0;
1420
1421}
1422
1423static void
1424xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425 xmlXPathObjectType objType)
1426{
1427 int isCached = 0;
1428
1429 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001430 if (ctxt->cache != NULL) {
1431 xmlXPathContextCachePtr cache =
1432 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001433
1434 isCached = 1;
1435
1436 cache->dbgReusedAll++;
1437 switch (objType) {
1438 case XPATH_UNDEFINED:
1439 cache->dbgReusedUndefined++;
1440 break;
1441 case XPATH_NODESET:
1442 cache->dbgReusedNodeset++;
1443 break;
1444 case XPATH_BOOLEAN:
1445 cache->dbgReusedBool++;
1446 break;
1447 case XPATH_NUMBER:
1448 cache->dbgReusedNumber++;
1449 break;
1450 case XPATH_STRING:
1451 cache->dbgReusedString++;
1452 break;
1453 case XPATH_POINT:
1454 cache->dbgReusedPoint++;
1455 break;
1456 case XPATH_RANGE:
1457 cache->dbgReusedRange++;
1458 break;
1459 case XPATH_LOCATIONSET:
1460 cache->dbgReusedLocset++;
1461 break;
1462 case XPATH_USERS:
1463 cache->dbgReusedUsers++;
1464 break;
1465 case XPATH_XSLT_TREE:
1466 cache->dbgReusedXSLTTree++;
1467 break;
1468 default:
1469 break;
1470 }
1471 }
1472 }
1473
1474 switch (objType) {
1475 case XPATH_UNDEFINED:
1476 if (! isCached)
1477 xmlXPathDebugObjTotalUndefined++;
1478 xmlXPathDebugObjCounterUndefined++;
1479 if (xmlXPathDebugObjCounterUndefined >
1480 xmlXPathDebugObjMaxUndefined)
1481 xmlXPathDebugObjMaxUndefined =
1482 xmlXPathDebugObjCounterUndefined;
1483 break;
1484 case XPATH_NODESET:
1485 if (! isCached)
1486 xmlXPathDebugObjTotalNodeset++;
1487 xmlXPathDebugObjCounterNodeset++;
1488 if (xmlXPathDebugObjCounterNodeset >
1489 xmlXPathDebugObjMaxNodeset)
1490 xmlXPathDebugObjMaxNodeset =
1491 xmlXPathDebugObjCounterNodeset;
1492 break;
1493 case XPATH_BOOLEAN:
1494 if (! isCached)
1495 xmlXPathDebugObjTotalBool++;
1496 xmlXPathDebugObjCounterBool++;
1497 if (xmlXPathDebugObjCounterBool >
1498 xmlXPathDebugObjMaxBool)
1499 xmlXPathDebugObjMaxBool =
1500 xmlXPathDebugObjCounterBool;
1501 break;
1502 case XPATH_NUMBER:
1503 if (! isCached)
1504 xmlXPathDebugObjTotalNumber++;
1505 xmlXPathDebugObjCounterNumber++;
1506 if (xmlXPathDebugObjCounterNumber >
1507 xmlXPathDebugObjMaxNumber)
1508 xmlXPathDebugObjMaxNumber =
1509 xmlXPathDebugObjCounterNumber;
1510 break;
1511 case XPATH_STRING:
1512 if (! isCached)
1513 xmlXPathDebugObjTotalString++;
1514 xmlXPathDebugObjCounterString++;
1515 if (xmlXPathDebugObjCounterString >
1516 xmlXPathDebugObjMaxString)
1517 xmlXPathDebugObjMaxString =
1518 xmlXPathDebugObjCounterString;
1519 break;
1520 case XPATH_POINT:
1521 if (! isCached)
1522 xmlXPathDebugObjTotalPoint++;
1523 xmlXPathDebugObjCounterPoint++;
1524 if (xmlXPathDebugObjCounterPoint >
1525 xmlXPathDebugObjMaxPoint)
1526 xmlXPathDebugObjMaxPoint =
1527 xmlXPathDebugObjCounterPoint;
1528 break;
1529 case XPATH_RANGE:
1530 if (! isCached)
1531 xmlXPathDebugObjTotalRange++;
1532 xmlXPathDebugObjCounterRange++;
1533 if (xmlXPathDebugObjCounterRange >
1534 xmlXPathDebugObjMaxRange)
1535 xmlXPathDebugObjMaxRange =
1536 xmlXPathDebugObjCounterRange;
1537 break;
1538 case XPATH_LOCATIONSET:
1539 if (! isCached)
1540 xmlXPathDebugObjTotalLocset++;
1541 xmlXPathDebugObjCounterLocset++;
1542 if (xmlXPathDebugObjCounterLocset >
1543 xmlXPathDebugObjMaxLocset)
1544 xmlXPathDebugObjMaxLocset =
1545 xmlXPathDebugObjCounterLocset;
1546 break;
1547 case XPATH_USERS:
1548 if (! isCached)
1549 xmlXPathDebugObjTotalUsers++;
1550 xmlXPathDebugObjCounterUsers++;
1551 if (xmlXPathDebugObjCounterUsers >
1552 xmlXPathDebugObjMaxUsers)
1553 xmlXPathDebugObjMaxUsers =
1554 xmlXPathDebugObjCounterUsers;
1555 break;
1556 case XPATH_XSLT_TREE:
1557 if (! isCached)
1558 xmlXPathDebugObjTotalXSLTTree++;
1559 xmlXPathDebugObjCounterXSLTTree++;
1560 if (xmlXPathDebugObjCounterXSLTTree >
1561 xmlXPathDebugObjMaxXSLTTree)
1562 xmlXPathDebugObjMaxXSLTTree =
1563 xmlXPathDebugObjCounterXSLTTree;
1564 break;
1565 default:
1566 break;
1567 }
1568 if (! isCached)
1569 xmlXPathDebugObjTotalAll++;
1570 xmlXPathDebugObjCounterAll++;
1571 if (xmlXPathDebugObjCounterAll >
1572 xmlXPathDebugObjMaxAll)
1573 xmlXPathDebugObjMaxAll =
1574 xmlXPathDebugObjCounterAll;
1575}
1576
1577static void
1578xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579 xmlXPathObjectType objType)
1580{
1581 int isCached = 0;
1582
1583 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001584 if (ctxt->cache != NULL) {
1585 xmlXPathContextCachePtr cache =
1586 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001587
1588 isCached = 1;
1589
1590 cache->dbgCachedAll++;
1591 switch (objType) {
1592 case XPATH_UNDEFINED:
1593 cache->dbgCachedUndefined++;
1594 break;
1595 case XPATH_NODESET:
1596 cache->dbgCachedNodeset++;
1597 break;
1598 case XPATH_BOOLEAN:
1599 cache->dbgCachedBool++;
1600 break;
1601 case XPATH_NUMBER:
1602 cache->dbgCachedNumber++;
1603 break;
1604 case XPATH_STRING:
1605 cache->dbgCachedString++;
1606 break;
1607 case XPATH_POINT:
1608 cache->dbgCachedPoint++;
1609 break;
1610 case XPATH_RANGE:
1611 cache->dbgCachedRange++;
1612 break;
1613 case XPATH_LOCATIONSET:
1614 cache->dbgCachedLocset++;
1615 break;
1616 case XPATH_USERS:
1617 cache->dbgCachedUsers++;
1618 break;
1619 case XPATH_XSLT_TREE:
1620 cache->dbgCachedXSLTTree++;
1621 break;
1622 default:
1623 break;
1624 }
1625
1626 }
1627 }
1628 switch (objType) {
1629 case XPATH_UNDEFINED:
1630 xmlXPathDebugObjCounterUndefined--;
1631 break;
1632 case XPATH_NODESET:
1633 xmlXPathDebugObjCounterNodeset--;
1634 break;
1635 case XPATH_BOOLEAN:
1636 xmlXPathDebugObjCounterBool--;
1637 break;
1638 case XPATH_NUMBER:
1639 xmlXPathDebugObjCounterNumber--;
1640 break;
1641 case XPATH_STRING:
1642 xmlXPathDebugObjCounterString--;
1643 break;
1644 case XPATH_POINT:
1645 xmlXPathDebugObjCounterPoint--;
1646 break;
1647 case XPATH_RANGE:
1648 xmlXPathDebugObjCounterRange--;
1649 break;
1650 case XPATH_LOCATIONSET:
1651 xmlXPathDebugObjCounterLocset--;
1652 break;
1653 case XPATH_USERS:
1654 xmlXPathDebugObjCounterUsers--;
1655 break;
1656 case XPATH_XSLT_TREE:
1657 xmlXPathDebugObjCounterXSLTTree--;
1658 break;
1659 default:
1660 break;
1661 }
1662 xmlXPathDebugObjCounterAll--;
1663}
1664
1665/* REVISIT TODO: Make this static when committing */
1666static void
1667xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668{
1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670 reqXSLTTree, reqUndefined;
1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675 int leftObjs = xmlXPathDebugObjCounterAll;
1676
1677 reqAll = xmlXPathDebugObjTotalAll;
1678 reqNodeset = xmlXPathDebugObjTotalNodeset;
1679 reqString = xmlXPathDebugObjTotalString;
1680 reqBool = xmlXPathDebugObjTotalBool;
1681 reqNumber = xmlXPathDebugObjTotalNumber;
1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683 reqUndefined = xmlXPathDebugObjTotalUndefined;
1684
1685 printf("# XPath object usage:\n");
1686
1687 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001688 if (ctxt->cache != NULL) {
1689 xmlXPathContextCachePtr cache =
1690 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001691
1692 reAll = cache->dbgReusedAll;
1693 reqAll += reAll;
1694 reNodeset = cache->dbgReusedNodeset;
1695 reqNodeset += reNodeset;
1696 reString = cache->dbgReusedString;
1697 reqString += reString;
1698 reBool = cache->dbgReusedBool;
1699 reqBool += reBool;
1700 reNumber = cache->dbgReusedNumber;
1701 reqNumber += reNumber;
1702 reXSLTTree = cache->dbgReusedXSLTTree;
1703 reqXSLTTree += reXSLTTree;
1704 reUndefined = cache->dbgReusedUndefined;
1705 reqUndefined += reUndefined;
1706
1707 caAll = cache->dbgCachedAll;
1708 caBool = cache->dbgCachedBool;
1709 caNodeset = cache->dbgCachedNodeset;
1710 caString = cache->dbgCachedString;
1711 caNumber = cache->dbgCachedNumber;
1712 caXSLTTree = cache->dbgCachedXSLTTree;
1713 caUndefined = cache->dbgCachedUndefined;
1714
1715 if (cache->nodesetObjs)
1716 leftObjs -= cache->nodesetObjs->number;
1717 if (cache->stringObjs)
1718 leftObjs -= cache->stringObjs->number;
1719 if (cache->booleanObjs)
1720 leftObjs -= cache->booleanObjs->number;
1721 if (cache->numberObjs)
1722 leftObjs -= cache->numberObjs->number;
1723 if (cache->miscObjs)
1724 leftObjs -= cache->miscObjs->number;
1725 }
1726 }
1727
1728 printf("# all\n");
1729 printf("# total : %d\n", reqAll);
1730 printf("# left : %d\n", leftObjs);
1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1732 printf("# reused : %d\n", reAll);
1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1734
1735 printf("# node-sets\n");
1736 printf("# total : %d\n", reqNodeset);
1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1738 printf("# reused : %d\n", reNodeset);
1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1740
1741 printf("# strings\n");
1742 printf("# total : %d\n", reqString);
1743 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1744 printf("# reused : %d\n", reString);
1745 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1746
1747 printf("# booleans\n");
1748 printf("# total : %d\n", reqBool);
1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1750 printf("# reused : %d\n", reBool);
1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1752
1753 printf("# numbers\n");
1754 printf("# total : %d\n", reqNumber);
1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1756 printf("# reused : %d\n", reNumber);
1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1758
1759 printf("# XSLT result tree fragments\n");
1760 printf("# total : %d\n", reqXSLTTree);
1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762 printf("# reused : %d\n", reXSLTTree);
1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764
1765 printf("# undefined\n");
1766 printf("# total : %d\n", reqUndefined);
1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1768 printf("# reused : %d\n", reUndefined);
1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1770
1771}
1772
1773#endif /* XP_DEBUG_OBJ_USAGE */
1774
Daniel Veillard017b1082001-06-21 11:20:21 +00001775#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001776
1777/************************************************************************
1778 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001779 * XPath object caching *
1780 * *
1781 ************************************************************************/
1782
1783/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001784 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001785 *
1786 * Create a new object cache
1787 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001788 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001789 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001790static xmlXPathContextCachePtr
1791xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001796 if (ret == NULL) {
1797 xmlXPathErrMemory(NULL, "creating object cache\n");
1798 return(NULL);
1799 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001801 ret->maxNodeset = 100;
1802 ret->maxString = 100;
1803 ret->maxBoolean = 100;
1804 ret->maxNumber = 100;
1805 ret->maxMisc = 100;
1806 return(ret);
1807}
1808
1809static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001810xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001811{
1812 int i;
1813 xmlXPathObjectPtr obj;
1814
1815 if (list == NULL)
1816 return;
1817
1818 for (i = 0; i < list->number; i++) {
1819 obj = list->items[i];
1820 /*
1821 * Note that it is already assured that we don't need to
1822 * look out for namespace nodes in the node-set.
1823 */
1824 if (obj->nodesetval != NULL) {
1825 if (obj->nodesetval->nodeTab != NULL)
1826 xmlFree(obj->nodesetval->nodeTab);
1827 xmlFree(obj->nodesetval);
1828 }
1829 xmlFree(obj);
1830#ifdef XP_DEBUG_OBJ_USAGE
1831 xmlXPathDebugObjCounterAll--;
1832#endif
1833 }
1834 xmlPointerListFree(list);
1835}
1836
1837static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001838xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001839{
1840 if (cache == NULL)
1841 return;
1842 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001843 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001844 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001851 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001852 xmlFree(cache);
1853}
1854
1855/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001856 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001857 *
1858 * @ctxt: the XPath context
1859 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001860 * @value: a value with semantics dependant on @options
1861 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001862 *
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001865 * to be reused.
1866 * @options:
1867 * 0: This will set the XPath object caching:
1868 * @value:
1869 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001870 * to be cached per slot
1871 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001872 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001873 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001874 *
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1876 */
1877int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001878xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1879 int active,
1880 int value,
1881 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001882{
1883 if (ctxt == NULL)
1884 return(-1);
1885 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001886 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001887
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001888 if (ctxt->cache == NULL) {
1889 ctxt->cache = xmlXPathNewCache();
1890 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001891 return(-1);
1892 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001893 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001894 if (options == 0) {
1895 if (value < 0)
1896 value = 100;
1897 cache->maxNodeset = value;
1898 cache->maxString = value;
1899 cache->maxNumber = value;
1900 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001901 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001902 }
1903 } else if (ctxt->cache != NULL) {
1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1905 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001906 }
1907 return(0);
1908}
1909
1910/**
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val: the NodePtr value
1914 *
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 *
1918 * Returns the created or reused object.
1919 */
1920static xmlXPathObjectPtr
1921xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001923 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924 xmlXPathContextCachePtr cache =
1925 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001926
1927 if ((cache->miscObjs != NULL) &&
1928 (cache->miscObjs->number != 0))
1929 {
1930 xmlXPathObjectPtr ret;
1931
1932 ret = (xmlXPathObjectPtr)
1933 cache->miscObjs->items[--cache->miscObjs->number];
1934 ret->type = XPATH_NODESET;
1935 ret->nodesetval = val;
1936#ifdef XP_DEBUG_OBJ_USAGE
1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1938#endif
1939 return(ret);
1940 }
1941 }
1942
1943 return(xmlXPathWrapNodeSet(val));
1944
1945}
1946
1947/**
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val: the xmlChar * value
1951 *
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1954 *
1955 * Returns the created or reused object.
1956 */
1957static xmlXPathObjectPtr
1958xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001960 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001962
1963 if ((cache->stringObjs != NULL) &&
1964 (cache->stringObjs->number != 0))
1965 {
1966
1967 xmlXPathObjectPtr ret;
1968
1969 ret = (xmlXPathObjectPtr)
1970 cache->stringObjs->items[--cache->stringObjs->number];
1971 ret->type = XPATH_STRING;
1972 ret->stringval = val;
1973#ifdef XP_DEBUG_OBJ_USAGE
1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1975#endif
1976 return(ret);
1977 } else if ((cache->miscObjs != NULL) &&
1978 (cache->miscObjs->number != 0))
1979 {
1980 xmlXPathObjectPtr ret;
1981 /*
1982 * Fallback to misc-cache.
1983 */
1984 ret = (xmlXPathObjectPtr)
1985 cache->miscObjs->items[--cache->miscObjs->number];
1986
1987 ret->type = XPATH_STRING;
1988 ret->stringval = val;
1989#ifdef XP_DEBUG_OBJ_USAGE
1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1991#endif
1992 return(ret);
1993 }
1994 }
1995 return(xmlXPathWrapString(val));
1996}
1997
1998/**
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val: the NodePtr value
2002 *
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2006 *
2007 * Returns the created or reused object.
2008 */
2009static xmlXPathObjectPtr
2010xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002012 if ((ctxt != NULL) && (ctxt->cache)) {
2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002014
2015 if ((cache->nodesetObjs != NULL) &&
2016 (cache->nodesetObjs->number != 0))
2017 {
2018 xmlXPathObjectPtr ret;
2019 /*
2020 * Use the nodset-cache.
2021 */
2022 ret = (xmlXPathObjectPtr)
2023 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024 ret->type = XPATH_NODESET;
2025 ret->boolval = 0;
2026 if (val) {
2027 if ((ret->nodesetval->nodeMax == 0) ||
2028 (val->type == XML_NAMESPACE_DECL))
2029 {
2030 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031 } else {
2032 ret->nodesetval->nodeTab[0] = val;
2033 ret->nodesetval->nodeNr = 1;
2034 }
2035 }
2036#ifdef XP_DEBUG_OBJ_USAGE
2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2038#endif
2039 return(ret);
2040 } else if ((cache->miscObjs != NULL) &&
2041 (cache->miscObjs->number != 0))
2042 {
2043 xmlXPathObjectPtr ret;
2044 /*
2045 * Fallback to misc-cache.
2046 */
2047
2048 ret = (xmlXPathObjectPtr)
2049 cache->miscObjs->items[--cache->miscObjs->number];
2050
2051 ret->type = XPATH_NODESET;
2052 ret->boolval = 0;
2053 ret->nodesetval = xmlXPathNodeSetCreate(val);
2054#ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2056#endif
2057 return(ret);
2058 }
2059 }
2060 return(xmlXPathNewNodeSet(val));
2061}
2062
2063/**
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val: the char * value
2067 *
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 *
2071 * Returns the created or reused object.
2072 */
2073static xmlXPathObjectPtr
2074xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002076 if ((ctxt != NULL) && (ctxt->cache)) {
2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002078
2079 if ((cache->stringObjs != NULL) &&
2080 (cache->stringObjs->number != 0))
2081 {
2082 xmlXPathObjectPtr ret;
2083
2084 ret = (xmlXPathObjectPtr)
2085 cache->stringObjs->items[--cache->stringObjs->number];
2086
2087 ret->type = XPATH_STRING;
2088 ret->stringval = xmlStrdup(BAD_CAST val);
2089#ifdef XP_DEBUG_OBJ_USAGE
2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2091#endif
2092 return(ret);
2093 } else if ((cache->miscObjs != NULL) &&
2094 (cache->miscObjs->number != 0))
2095 {
2096 xmlXPathObjectPtr ret;
2097
2098 ret = (xmlXPathObjectPtr)
2099 cache->miscObjs->items[--cache->miscObjs->number];
2100
2101 ret->type = XPATH_STRING;
2102 ret->stringval = xmlStrdup(BAD_CAST val);
2103#ifdef XP_DEBUG_OBJ_USAGE
2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2105#endif
2106 return(ret);
2107 }
2108 }
2109 return(xmlXPathNewCString(val));
2110}
2111
2112/**
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val: the xmlChar * value
2116 *
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 *
2120 * Returns the created or reused object.
2121 */
2122static xmlXPathObjectPtr
2123xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002125 if ((ctxt != NULL) && (ctxt->cache)) {
2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002127
2128 if ((cache->stringObjs != NULL) &&
2129 (cache->stringObjs->number != 0))
2130 {
2131 xmlXPathObjectPtr ret;
2132
2133 ret = (xmlXPathObjectPtr)
2134 cache->stringObjs->items[--cache->stringObjs->number];
2135 ret->type = XPATH_STRING;
2136 if (val != NULL)
2137 ret->stringval = xmlStrdup(val);
2138 else
2139 ret->stringval = xmlStrdup((const xmlChar *)"");
2140#ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2142#endif
2143 return(ret);
2144 } else if ((cache->miscObjs != NULL) &&
2145 (cache->miscObjs->number != 0))
2146 {
2147 xmlXPathObjectPtr ret;
2148
2149 ret = (xmlXPathObjectPtr)
2150 cache->miscObjs->items[--cache->miscObjs->number];
2151
2152 ret->type = XPATH_STRING;
2153 if (val != NULL)
2154 ret->stringval = xmlStrdup(val);
2155 else
2156 ret->stringval = xmlStrdup((const xmlChar *)"");
2157#ifdef XP_DEBUG_OBJ_USAGE
2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2159#endif
2160 return(ret);
2161 }
2162 }
2163 return(xmlXPathNewString(val));
2164}
2165
2166/**
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val: the boolean value
2170 *
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 *
2174 * Returns the created or reused object.
2175 */
2176static xmlXPathObjectPtr
2177xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002179 if ((ctxt != NULL) && (ctxt->cache)) {
2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002181
2182 if ((cache->booleanObjs != NULL) &&
2183 (cache->booleanObjs->number != 0))
2184 {
2185 xmlXPathObjectPtr ret;
2186
2187 ret = (xmlXPathObjectPtr)
2188 cache->booleanObjs->items[--cache->booleanObjs->number];
2189 ret->type = XPATH_BOOLEAN;
2190 ret->boolval = (val != 0);
2191#ifdef XP_DEBUG_OBJ_USAGE
2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2193#endif
2194 return(ret);
2195 } else if ((cache->miscObjs != NULL) &&
2196 (cache->miscObjs->number != 0))
2197 {
2198 xmlXPathObjectPtr ret;
2199
2200 ret = (xmlXPathObjectPtr)
2201 cache->miscObjs->items[--cache->miscObjs->number];
2202
2203 ret->type = XPATH_BOOLEAN;
2204 ret->boolval = (val != 0);
2205#ifdef XP_DEBUG_OBJ_USAGE
2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2207#endif
2208 return(ret);
2209 }
2210 }
2211 return(xmlXPathNewBoolean(val));
2212}
2213
2214/**
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val: the double value
2218 *
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 *
2222 * Returns the created or reused object.
2223 */
2224static xmlXPathObjectPtr
2225xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002227 if ((ctxt != NULL) && (ctxt->cache)) {
2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002229
2230 if ((cache->numberObjs != NULL) &&
2231 (cache->numberObjs->number != 0))
2232 {
2233 xmlXPathObjectPtr ret;
2234
2235 ret = (xmlXPathObjectPtr)
2236 cache->numberObjs->items[--cache->numberObjs->number];
2237 ret->type = XPATH_NUMBER;
2238 ret->floatval = val;
2239#ifdef XP_DEBUG_OBJ_USAGE
2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2241#endif
2242 return(ret);
2243 } else if ((cache->miscObjs != NULL) &&
2244 (cache->miscObjs->number != 0))
2245 {
2246 xmlXPathObjectPtr ret;
2247
2248 ret = (xmlXPathObjectPtr)
2249 cache->miscObjs->items[--cache->miscObjs->number];
2250
2251 ret->type = XPATH_NUMBER;
2252 ret->floatval = val;
2253#ifdef XP_DEBUG_OBJ_USAGE
2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2255#endif
2256 return(ret);
2257 }
2258 }
2259 return(xmlXPathNewFloat(val));
2260}
2261
2262/**
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val: an XPath object
2266 *
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2269 *
2270 * Returns a created or reused object, the old one is freed (cached)
2271 * (or the operation is done directly on @val)
2272 */
2273
2274static xmlXPathObjectPtr
2275xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276 xmlChar *res = NULL;
2277
2278 if (val == NULL)
2279 return(xmlXPathCacheNewCString(ctxt, ""));
2280
2281 switch (val->type) {
2282 case XPATH_UNDEFINED:
2283#ifdef DEBUG_EXPR
2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2285#endif
2286 break;
2287 case XPATH_NODESET:
2288 case XPATH_XSLT_TREE:
2289 res = xmlXPathCastNodeSetToString(val->nodesetval);
2290 break;
2291 case XPATH_STRING:
2292 return(val);
2293 case XPATH_BOOLEAN:
2294 res = xmlXPathCastBooleanToString(val->boolval);
2295 break;
2296 case XPATH_NUMBER:
2297 res = xmlXPathCastNumberToString(val->floatval);
2298 break;
2299 case XPATH_USERS:
2300 case XPATH_POINT:
2301 case XPATH_RANGE:
2302 case XPATH_LOCATIONSET:
2303 TODO;
2304 break;
2305 }
2306 xmlXPathReleaseObject(ctxt, val);
2307 if (res == NULL)
2308 return(xmlXPathCacheNewCString(ctxt, ""));
2309 return(xmlXPathCacheWrapString(ctxt, res));
2310}
2311
2312/**
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val: the original object
2316 *
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2319 *
2320 * Returns a created or reused created object.
2321 */
2322static xmlXPathObjectPtr
2323xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2324{
2325 if (val == NULL)
2326 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002327
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002328 if (XP_HAS_CACHE(ctxt)) {
2329 switch (val->type) {
2330 case XPATH_NODESET:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002331 return(xmlXPathCacheWrapNodeSet(ctxt,
2332 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002333 case XPATH_STRING:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002334 return(xmlXPathCacheNewString(ctxt, val->stringval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002335 case XPATH_BOOLEAN:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00002337 case XPATH_NUMBER:
2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2339 default:
2340 break;
2341 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002342 }
2343 return(xmlXPathObjectCopy(val));
2344}
2345
2346/**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val: an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 * is done directly on @val)
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359 xmlXPathObjectPtr ret;
2360
2361 if (val == NULL)
2362 return(xmlXPathCacheNewBoolean(ctxt, 0));
2363 if (val->type == XPATH_BOOLEAN)
2364 return(val);
2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366 xmlXPathReleaseObject(ctxt, val);
2367 return(ret);
2368}
2369
2370/**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val: an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 * is done directly on @val)
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383 xmlXPathObjectPtr ret;
2384
2385 if (val == NULL)
2386 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387 if (val->type == XPATH_NUMBER)
2388 return(val);
2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390 xmlXPathReleaseObject(ctxt, val);
2391 return(ret);
2392}
2393
2394/************************************************************************
2395 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002396 * Parser stacks related functions and macros *
2397 * *
2398 ************************************************************************/
2399
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002400/**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002408xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002409valuePop(xmlXPathParserContextPtr ctxt)
2410{
2411 xmlXPathObjectPtr ret;
2412
Daniel Veillarda82b1822004-11-08 16:24:57 +00002413 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002414 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002415 ctxt->valueNr--;
2416 if (ctxt->valueNr > 0)
2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418 else
2419 ctxt->value = NULL;
2420 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002421 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002422 return (ret);
2423}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002424/**
2425 * valuePush:
2426 * @ctxt: an XPath evaluation context
2427 * @value: the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002430 *
2431 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002432 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002433int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002436 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002437 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002438 xmlXPathObjectPtr *tmp;
2439
2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002443 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445 return (0);
2446 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002447 ctxt->valueMax *= 2;
2448 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002449 }
2450 ctxt->valueTab[ctxt->valueNr] = value;
2451 ctxt->value = value;
2452 return (ctxt->valueNr++);
2453}
Owen Taylor3473f882001-02-23 17:55:21 +00002454
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002455/**
2456 * xmlXPathPopBoolean:
2457 * @ctxt: an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464int
2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466 xmlXPathObjectPtr obj;
2467 int ret;
2468
2469 obj = valuePop(ctxt);
2470 if (obj == NULL) {
2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472 return(0);
2473 }
William M. Brack08171912003-12-29 02:52:11 +00002474 if (obj->type != XPATH_BOOLEAN)
2475 ret = xmlXPathCastToBoolean(obj);
2476 else
2477 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002478 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002479 return(ret);
2480}
2481
2482/**
2483 * xmlXPathPopNumber:
2484 * @ctxt: an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491double
2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493 xmlXPathObjectPtr obj;
2494 double ret;
2495
2496 obj = valuePop(ctxt);
2497 if (obj == NULL) {
2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499 return(0);
2500 }
William M. Brack08171912003-12-29 02:52:11 +00002501 if (obj->type != XPATH_NUMBER)
2502 ret = xmlXPathCastToNumber(obj);
2503 else
2504 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002505 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002506 return(ret);
2507}
2508
2509/**
2510 * xmlXPathPopString:
2511 * @ctxt: an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518xmlChar *
2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520 xmlXPathObjectPtr obj;
2521 xmlChar * ret;
2522
2523 obj = valuePop(ctxt);
2524 if (obj == NULL) {
2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526 return(NULL);
2527 }
William M. Brack08171912003-12-29 02:52:11 +00002528 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002529 /* TODO: needs refactoring somewhere else */
2530 if (obj->stringval == ret)
2531 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002532 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002533 return(ret);
2534}
2535
2536/**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt: an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545xmlNodeSetPtr
2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547 xmlXPathObjectPtr obj;
2548 xmlNodeSetPtr ret;
2549
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002550 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002551 if (ctxt->value == NULL) {
2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553 return(NULL);
2554 }
2555 if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 xmlXPathSetTypeError(ctxt);
2557 return(NULL);
2558 }
2559 obj = valuePop(ctxt);
2560 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002561#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002562 /* to fix memory leak of not clearing obj->user */
2563 if (obj->boolval && obj->user != NULL)
2564 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002565#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002566 obj->nodesetval = NULL;
2567 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002568 return(ret);
2569}
2570
2571/**
2572 * xmlXPathPopExternal:
2573 * @ctxt: an XPath parser context
2574 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002575 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580void *
2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582 xmlXPathObjectPtr obj;
2583 void * ret;
2584
Daniel Veillarda82b1822004-11-08 16:24:57 +00002585 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587 return(NULL);
2588 }
2589 if (ctxt->value->type != XPATH_USERS) {
2590 xmlXPathSetTypeError(ctxt);
2591 return(NULL);
2592 }
2593 obj = valuePop(ctxt);
2594 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002595 obj->user = NULL;
2596 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002597 return(ret);
2598}
2599
Owen Taylor3473f882001-02-23 17:55:21 +00002600/*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 * CUR returns the current xmlChar value, i.e. a 8 bit value
2608 * in ISO-Latin or UTF-8.
2609 * This should be used internally by the parser
2610 * only to compare to ASCII values otherwise it would break when
2611 * running with UTF-8 encoding.
2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2613 * to compare on ASCII based substring.
2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 * strings within the parser.
2616 * CURRENT Returns the current char value, with the full decoding of
2617 * UTF-8 if we are using this mode. It returns an int.
2618 * NEXT Skip to the next character, this does the proper decoding
2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 * It returns the pointer to the current xmlChar.
2621 */
2622
2623#define CUR (*ctxt->cur)
2624#define SKIP(val) ctxt->cur += (val)
2625#define NXT(val) ctxt->cur[(val)]
2626#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629#define COPY_BUF(l,b,i,v) \
2630 if (l == 1) b[i++] = (xmlChar) v; \
2631 else i += xmlCopyChar(l,&b[i],v)
2632
2633#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002634
2635#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638#define CURRENT (*ctxt->cur)
2639#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2640
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002641
2642#ifndef DBL_DIG
2643#define DBL_DIG 16
2644#endif
2645#ifndef DBL_EPSILON
2646#define DBL_EPSILON 1E-9
2647#endif
2648
2649#define UPPER_DOUBLE 1E9
2650#define LOWER_DOUBLE 1E-5
William M. Brackca797882007-05-11 14:45:53 +00002651#define LOWER_DOUBLE_EXP 5
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002652
2653#define INTEGER_DIGITS DBL_DIG
William M. Brackca797882007-05-11 14:45:53 +00002654#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002655#define EXPONENT_DIGITS (3 + 2)
2656
2657/**
2658 * xmlXPathFormatNumber:
2659 * @number: number to format
2660 * @buffer: output buffer
2661 * @buffersize: size of output buffer
2662 *
2663 * Convert the number into a string representation.
2664 */
2665static void
2666xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2667{
Daniel Veillardcda96922001-08-21 10:56:31 +00002668 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002669 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002670 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002671 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002672 break;
2673 case -1:
2674 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002675 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002676 break;
2677 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002678 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002679 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002680 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002681 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002682 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002683 } else if (number == ((int) number)) {
2684 char work[30];
2685 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002686 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002687
2688 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002689 if (value == 0) {
2690 *ptr++ = '0';
2691 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002692 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002693 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002694 while ((*cur) && (ptr - buffer < buffersize)) {
2695 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002696 }
2697 }
2698 if (ptr - buffer < buffersize) {
2699 *ptr = 0;
2700 } else if (buffersize > 0) {
2701 ptr--;
2702 *ptr = 0;
2703 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002704 } else {
William M. Brackca797882007-05-11 14:45:53 +00002705 /*
2706 For the dimension of work,
2707 DBL_DIG is number of significant digits
2708 EXPONENT is only needed for "scientific notation"
2709 3 is sign, decimal point, and terminating zero
2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711 Note that this dimension is slightly (a few characters)
2712 larger than actually necessary.
2713 */
2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
Bjorn Reese70a9da52001-04-21 16:57:29 +00002715 int integer_place, fraction_place;
2716 char *ptr;
2717 char *after_fraction;
2718 double absolute_value;
2719 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002720
Bjorn Reese70a9da52001-04-21 16:57:29 +00002721 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002722
Bjorn Reese70a9da52001-04-21 16:57:29 +00002723 /*
2724 * First choose format - scientific or regular floating point.
2725 * In either case, result is in work, and after_fraction points
2726 * just past the fractional part.
2727 */
2728 if ( ((absolute_value > UPPER_DOUBLE) ||
2729 (absolute_value < LOWER_DOUBLE)) &&
2730 (absolute_value != 0.0) ) {
2731 /* Use scientific notation */
2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002734 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002735 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002736 while ((size > 0) && (work[size] != 'e')) size--;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002737
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002738 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002739 else {
2740 /* Use regular notation */
William M. Brackca797882007-05-11 14:45:53 +00002741 if (absolute_value > 0.0) {
2742 integer_place = (int)log10(absolute_value);
2743 if (integer_place > 0)
2744 fraction_place = DBL_DIG - integer_place - 1;
2745 else
2746 fraction_place = DBL_DIG - integer_place;
2747 } else {
2748 fraction_place = 1;
2749 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002750 size = snprintf(work, sizeof(work), "%0.*f",
2751 fraction_place, number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002752 }
2753
Bjorn Reese70a9da52001-04-21 16:57:29 +00002754 /* Remove fractional trailing zeroes */
William M. Brackca797882007-05-11 14:45:53 +00002755 after_fraction = work + size;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002756 ptr = after_fraction;
2757 while (*(--ptr) == '0')
2758 ;
2759 if (*ptr != '.')
2760 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002761 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002762
2763 /* Finally copy result back to caller */
2764 size = strlen(work) + 1;
2765 if (size > buffersize) {
2766 work[buffersize - 1] = 0;
2767 size = buffersize;
2768 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002769 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002770 }
2771 break;
2772 }
2773}
2774
Owen Taylor3473f882001-02-23 17:55:21 +00002775
2776/************************************************************************
2777 * *
2778 * Routines to handle NodeSets *
2779 * *
2780 ************************************************************************/
2781
2782/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002783 * xmlXPathOrderDocElems:
2784 * @doc: an input document
2785 *
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002791 *
William M. Brack08171912003-12-29 02:52:11 +00002792 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002793 * of error.
2794 */
2795long
2796xmlXPathOrderDocElems(xmlDocPtr doc) {
2797 long count = 0;
2798 xmlNodePtr cur;
2799
2800 if (doc == NULL)
2801 return(-1);
2802 cur = doc->children;
2803 while (cur != NULL) {
2804 if (cur->type == XML_ELEMENT_NODE) {
2805 cur->content = (void *) (-(++count));
2806 if (cur->children != NULL) {
2807 cur = cur->children;
2808 continue;
2809 }
2810 }
2811 if (cur->next != NULL) {
2812 cur = cur->next;
2813 continue;
2814 }
2815 do {
2816 cur = cur->parent;
2817 if (cur == NULL)
2818 break;
2819 if (cur == (xmlNodePtr) doc) {
2820 cur = NULL;
2821 break;
2822 }
2823 if (cur->next != NULL) {
2824 cur = cur->next;
2825 break;
2826 }
2827 } while (cur != NULL);
2828 }
2829 return(count);
2830}
2831
2832/**
Owen Taylor3473f882001-02-23 17:55:21 +00002833 * xmlXPathCmpNodes:
2834 * @node1: the first node
2835 * @node2: the second node
2836 *
2837 * Compare two nodes w.r.t document order
2838 *
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002840 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002841 */
2842int
2843xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2844 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002845 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002847 xmlNodePtr cur, root;
2848
2849 if ((node1 == NULL) || (node2 == NULL))
2850 return(-2);
2851 /*
2852 * a couple of optimizations which will avoid computations in most cases
2853 */
William M. Brackee0b9822007-03-07 08:15:01 +00002854 if (node1 == node2) /* trivial case */
2855 return(0);
Daniel Veillardedfd5882003-03-07 14:20:40 +00002856 if (node1->type == XML_ATTRIBUTE_NODE) {
2857 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002858 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002859 node1 = node1->parent;
2860 }
2861 if (node2->type == XML_ATTRIBUTE_NODE) {
2862 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002863 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002864 node2 = node2->parent;
2865 }
2866 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002867 if (attr1 == attr2) {
2868 /* not required, but we keep attributes in order */
2869 if (attr1 != 0) {
2870 cur = attrNode2->prev;
2871 while (cur != NULL) {
2872 if (cur == attrNode1)
2873 return (1);
2874 cur = cur->prev;
2875 }
2876 return (-1);
2877 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002878 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002879 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002880 if (attr2 == 1)
2881 return(1);
2882 return(-1);
2883 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002884 if ((node1->type == XML_NAMESPACE_DECL) ||
2885 (node2->type == XML_NAMESPACE_DECL))
2886 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002887 if (node1 == node2->prev)
2888 return(1);
2889 if (node1 == node2->next)
2890 return(-1);
2891
2892 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002893 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002894 */
2895 if ((node1->type == XML_ELEMENT_NODE) &&
2896 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002897 (0 > (long) node1->content) &&
2898 (0 > (long) node2->content) &&
2899 (node1->doc == node2->doc)) {
2900 long l1, l2;
2901
2902 l1 = -((long) node1->content);
2903 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002904 if (l1 < l2)
2905 return(1);
2906 if (l1 > l2)
2907 return(-1);
2908 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002909
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002910 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002911 * compute depth to root
2912 */
2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2914 if (cur == node1)
2915 return(1);
2916 depth2++;
2917 }
2918 root = cur;
2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2920 if (cur == node2)
2921 return(-1);
2922 depth1++;
2923 }
2924 /*
2925 * Distinct document (or distinct entities :-( ) case.
2926 */
2927 if (root != cur) {
2928 return(-2);
2929 }
2930 /*
2931 * get the nearest common ancestor.
2932 */
2933 while (depth1 > depth2) {
2934 depth1--;
2935 node1 = node1->parent;
2936 }
2937 while (depth2 > depth1) {
2938 depth2--;
2939 node2 = node2->parent;
2940 }
2941 while (node1->parent != node2->parent) {
2942 node1 = node1->parent;
2943 node2 = node2->parent;
2944 /* should not happen but just in case ... */
2945 if ((node1 == NULL) || (node2 == NULL))
2946 return(-2);
2947 }
2948 /*
2949 * Find who's first.
2950 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002951 if (node1 == node2->prev)
2952 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 if (node1 == node2->next)
2954 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002955 /*
2956 * Speedup using document order if availble.
2957 */
2958 if ((node1->type == XML_ELEMENT_NODE) &&
2959 (node2->type == XML_ELEMENT_NODE) &&
2960 (0 > (long) node1->content) &&
2961 (0 > (long) node2->content) &&
2962 (node1->doc == node2->doc)) {
2963 long l1, l2;
2964
2965 l1 = -((long) node1->content);
2966 l2 = -((long) node2->content);
2967 if (l1 < l2)
2968 return(1);
2969 if (l1 > l2)
2970 return(-1);
2971 }
2972
Owen Taylor3473f882001-02-23 17:55:21 +00002973 for (cur = node1->next;cur != NULL;cur = cur->next)
2974 if (cur == node2)
2975 return(1);
2976 return(-1); /* assume there is no sibling list corruption */
2977}
2978
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002979#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002980/**
2981 * xmlXPathCmpNodesExt:
2982 * @node1: the first node
2983 * @node2: the second node
2984 *
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2987 *
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 * it's the same node, -1 otherwise
2990 */
2991static int
2992xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2993 int depth1, depth2;
2994 int misc = 0, precedence1 = 0, precedence2 = 0;
2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002997 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002998
2999 if ((node1 == NULL) || (node2 == NULL))
3000 return(-2);
3001
3002 if (node1 == node2)
3003 return(0);
3004
3005 /*
3006 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003007 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003008 switch (node1->type) {
3009 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003010 if (node2->type == XML_ELEMENT_NODE) {
3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012 (0 > (long) node2->content) &&
3013 (node1->doc == node2->doc))
3014 {
3015 l1 = -((long) node1->content);
3016 l2 = -((long) node2->content);
3017 if (l1 < l2)
3018 return(1);
3019 if (l1 > l2)
3020 return(-1);
3021 } else
3022 goto turtle_comparison;
3023 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003024 break;
3025 case XML_ATTRIBUTE_NODE:
3026 precedence1 = 1; /* element is owner */
3027 miscNode1 = node1;
3028 node1 = node1->parent;
3029 misc = 1;
3030 break;
3031 case XML_TEXT_NODE:
3032 case XML_CDATA_SECTION_NODE:
3033 case XML_COMMENT_NODE:
3034 case XML_PI_NODE: {
3035 miscNode1 = node1;
3036 /*
3037 * Find nearest element node.
3038 */
3039 if (node1->prev != NULL) {
3040 do {
3041 node1 = node1->prev;
3042 if (node1->type == XML_ELEMENT_NODE) {
3043 precedence1 = 3; /* element in prev-sibl axis */
3044 break;
3045 }
3046 if (node1->prev == NULL) {
3047 precedence1 = 2; /* element is parent */
3048 /*
3049 * URGENT TODO: Are there any cases, where the
3050 * parent of such a node is not an element node?
3051 */
3052 node1 = node1->parent;
3053 break;
3054 }
3055 } while (1);
3056 } else {
3057 precedence1 = 2; /* element is parent */
3058 node1 = node1->parent;
3059 }
3060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3061 /*
3062 * Fallback for whatever case.
3063 */
3064 node1 = miscNode1;
3065 precedence1 = 0;
3066 } else
3067 misc = 1;
3068 }
3069 break;
3070 case XML_NAMESPACE_DECL:
3071 /*
3072 * TODO: why do we return 1 for namespace nodes?
3073 */
3074 return(1);
3075 default:
3076 break;
3077 }
3078 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003079 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003080 break;
3081 case XML_ATTRIBUTE_NODE:
3082 precedence2 = 1; /* element is owner */
3083 miscNode2 = node2;
3084 node2 = node2->parent;
3085 misc = 1;
3086 break;
3087 case XML_TEXT_NODE:
3088 case XML_CDATA_SECTION_NODE:
3089 case XML_COMMENT_NODE:
3090 case XML_PI_NODE: {
3091 miscNode2 = node2;
3092 if (node2->prev != NULL) {
3093 do {
3094 node2 = node2->prev;
3095 if (node2->type == XML_ELEMENT_NODE) {
3096 precedence2 = 3; /* element in prev-sibl axis */
3097 break;
3098 }
3099 if (node2->prev == NULL) {
3100 precedence2 = 2; /* element is parent */
3101 node2 = node2->parent;
3102 break;
3103 }
3104 } while (1);
3105 } else {
3106 precedence2 = 2; /* element is parent */
3107 node2 = node2->parent;
3108 }
3109 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3110 (0 <= (long) node1->content))
3111 {
3112 node2 = miscNode2;
3113 precedence2 = 0;
3114 } else
3115 misc = 1;
3116 }
3117 break;
3118 case XML_NAMESPACE_DECL:
3119 return(1);
3120 default:
3121 break;
3122 }
3123 if (misc) {
3124 if (node1 == node2) {
3125 if (precedence1 == precedence2) {
3126 /*
3127 * The ugly case; but normally there aren't many
3128 * adjacent non-element nodes around.
3129 */
3130 cur = miscNode2->prev;
3131 while (cur != NULL) {
3132 if (cur == miscNode1)
3133 return(1);
3134 if (cur->type == XML_ELEMENT_NODE)
3135 return(-1);
3136 cur = cur->prev;
3137 }
3138 return (-1);
3139 } else {
3140 /*
3141 * Evaluate based on higher precedence wrt to the element.
3142 * TODO: This assumes attributes are sorted before content.
3143 * Is this 100% correct?
3144 */
3145 if (precedence1 < precedence2)
3146 return(1);
3147 else
3148 return(-1);
3149 }
3150 }
3151 /*
3152 * Special case: One of the helper-elements is contained by the other.
3153 * <foo>
3154 * <node2>
3155 * <node1>Text-1(precedence1 == 2)</node1>
3156 * </node2>
3157 * Text-6(precedence2 == 3)
3158 * </foo>
3159 */
3160 if ((precedence2 == 3) && (precedence1 > 1)) {
3161 cur = node1->parent;
3162 while (cur) {
3163 if (cur == node2)
3164 return(1);
3165 cur = cur->parent;
3166 }
3167 }
3168 if ((precedence1 == 3) && (precedence2 > 1)) {
3169 cur = node2->parent;
3170 while (cur) {
3171 if (cur == node1)
3172 return(-1);
3173 cur = cur->parent;
3174 }
3175 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003176 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003177
3178 /*
3179 * Speedup using document order if availble.
3180 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003181 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003182 (node2->type == XML_ELEMENT_NODE) &&
3183 (0 > (long) node1->content) &&
3184 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003185 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003186
3187 l1 = -((long) node1->content);
3188 l2 = -((long) node2->content);
3189 if (l1 < l2)
3190 return(1);
3191 if (l1 > l2)
3192 return(-1);
3193 }
3194
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003195turtle_comparison:
3196
3197 if (node1 == node2->prev)
3198 return(1);
3199 if (node1 == node2->next)
3200 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003201 /*
3202 * compute depth to root
3203 */
3204 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3205 if (cur == node1)
3206 return(1);
3207 depth2++;
3208 }
3209 root = cur;
3210 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3211 if (cur == node2)
3212 return(-1);
3213 depth1++;
3214 }
3215 /*
3216 * Distinct document (or distinct entities :-( ) case.
3217 */
3218 if (root != cur) {
3219 return(-2);
3220 }
3221 /*
3222 * get the nearest common ancestor.
3223 */
3224 while (depth1 > depth2) {
3225 depth1--;
3226 node1 = node1->parent;
3227 }
3228 while (depth2 > depth1) {
3229 depth2--;
3230 node2 = node2->parent;
3231 }
3232 while (node1->parent != node2->parent) {
3233 node1 = node1->parent;
3234 node2 = node2->parent;
3235 /* should not happen but just in case ... */
3236 if ((node1 == NULL) || (node2 == NULL))
3237 return(-2);
3238 }
3239 /*
3240 * Find who's first.
3241 */
3242 if (node1 == node2->prev)
3243 return(1);
3244 if (node1 == node2->next)
3245 return(-1);
3246 /*
3247 * Speedup using document order if availble.
3248 */
3249 if ((node1->type == XML_ELEMENT_NODE) &&
3250 (node2->type == XML_ELEMENT_NODE) &&
3251 (0 > (long) node1->content) &&
3252 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003253 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003254
3255 l1 = -((long) node1->content);
3256 l2 = -((long) node2->content);
3257 if (l1 < l2)
3258 return(1);
3259 if (l1 > l2)
3260 return(-1);
3261 }
3262
3263 for (cur = node1->next;cur != NULL;cur = cur->next)
3264 if (cur == node2)
3265 return(1);
3266 return(-1); /* assume there is no sibling list corruption */
3267}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003268#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003269
Owen Taylor3473f882001-02-23 17:55:21 +00003270/**
3271 * xmlXPathNodeSetSort:
3272 * @set: the node set
3273 *
3274 * Sort the node set in document order
3275 */
3276void
3277xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003278 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003279 xmlNodePtr tmp;
3280
3281 if (set == NULL)
3282 return;
3283
3284 /* Use Shell's sort to sort the node-set */
3285 len = set->nodeNr;
3286 for (incr = len / 2; incr > 0; incr /= 2) {
3287 for (i = incr; i < len; i++) {
3288 j = i - incr;
3289 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003290#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003291 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3292 set->nodeTab[j + incr]) == -1)
3293#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003294 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003295 set->nodeTab[j + incr]) == -1)
3296#endif
3297 {
Owen Taylor3473f882001-02-23 17:55:21 +00003298 tmp = set->nodeTab[j];
3299 set->nodeTab[j] = set->nodeTab[j + incr];
3300 set->nodeTab[j + incr] = tmp;
3301 j -= incr;
3302 } else
3303 break;
3304 }
3305 }
3306 }
3307}
3308
3309#define XML_NODESET_DEFAULT 10
3310/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003311 * xmlXPathNodeSetDupNs:
3312 * @node: the parent node of the namespace XPath node
3313 * @ns: the libxml namespace declaration node.
3314 *
3315 * Namespace node in libxml don't match the XPath semantic. In a node set
3316 * the namespace nodes are duplicated and the next pointer is set to the
3317 * parent node in the XPath semantic.
3318 *
3319 * Returns the newly created object.
3320 */
3321static xmlNodePtr
3322xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3323 xmlNsPtr cur;
3324
3325 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3326 return(NULL);
3327 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3328 return((xmlNodePtr) ns);
3329
3330 /*
3331 * Allocate a new Namespace and fill the fields.
3332 */
3333 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3334 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003335 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003336 return(NULL);
3337 }
3338 memset(cur, 0, sizeof(xmlNs));
3339 cur->type = XML_NAMESPACE_DECL;
3340 if (ns->href != NULL)
3341 cur->href = xmlStrdup(ns->href);
3342 if (ns->prefix != NULL)
3343 cur->prefix = xmlStrdup(ns->prefix);
3344 cur->next = (xmlNsPtr) node;
3345 return((xmlNodePtr) cur);
3346}
3347
3348/**
3349 * xmlXPathNodeSetFreeNs:
3350 * @ns: the XPath namespace node found in a nodeset.
3351 *
William M. Brack08171912003-12-29 02:52:11 +00003352 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003353 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003354 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003355 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003356void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003357xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3358 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3359 return;
3360
3361 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3362 if (ns->href != NULL)
3363 xmlFree((xmlChar *)ns->href);
3364 if (ns->prefix != NULL)
3365 xmlFree((xmlChar *)ns->prefix);
3366 xmlFree(ns);
3367 }
3368}
3369
3370/**
Owen Taylor3473f882001-02-23 17:55:21 +00003371 * xmlXPathNodeSetCreate:
3372 * @val: an initial xmlNodePtr, or NULL
3373 *
3374 * Create a new xmlNodeSetPtr of type double and of value @val
3375 *
3376 * Returns the newly created object.
3377 */
3378xmlNodeSetPtr
3379xmlXPathNodeSetCreate(xmlNodePtr val) {
3380 xmlNodeSetPtr ret;
3381
3382 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3383 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003384 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003385 return(NULL);
3386 }
3387 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3388 if (val != NULL) {
3389 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3390 sizeof(xmlNodePtr));
3391 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003392 xmlXPathErrMemory(NULL, "creating nodeset\n");
3393 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003394 return(NULL);
3395 }
3396 memset(ret->nodeTab, 0 ,
3397 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3398 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003399 if (val->type == XML_NAMESPACE_DECL) {
3400 xmlNsPtr ns = (xmlNsPtr) val;
3401
3402 ret->nodeTab[ret->nodeNr++] =
3403 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3404 } else
3405 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003406 }
3407 return(ret);
3408}
3409
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003410/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003411 * xmlXPathNodeSetCreateSize:
3412 * @size: the initial size of the set
3413 *
3414 * Create a new xmlNodeSetPtr of type double and of value @val
3415 *
3416 * Returns the newly created object.
3417 */
3418static xmlNodeSetPtr
3419xmlXPathNodeSetCreateSize(int size) {
3420 xmlNodeSetPtr ret;
3421
3422 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3423 if (ret == NULL) {
3424 xmlXPathErrMemory(NULL, "creating nodeset\n");
3425 return(NULL);
3426 }
3427 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3428 if (size < XML_NODESET_DEFAULT)
3429 size = XML_NODESET_DEFAULT;
3430 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3431 if (ret->nodeTab == NULL) {
3432 xmlXPathErrMemory(NULL, "creating nodeset\n");
3433 xmlFree(ret);
3434 return(NULL);
3435 }
3436 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3437 ret->nodeMax = size;
3438 return(ret);
3439}
3440
3441/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003442 * xmlXPathNodeSetContains:
3443 * @cur: the node-set
3444 * @val: the node
3445 *
3446 * checks whether @cur contains @val
3447 *
3448 * Returns true (1) if @cur contains @val, false (0) otherwise
3449 */
3450int
3451xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3452 int i;
3453
Daniel Veillarda82b1822004-11-08 16:24:57 +00003454 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003455 if (val->type == XML_NAMESPACE_DECL) {
3456 for (i = 0; i < cur->nodeNr; i++) {
3457 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3458 xmlNsPtr ns1, ns2;
3459
3460 ns1 = (xmlNsPtr) val;
3461 ns2 = (xmlNsPtr) cur->nodeTab[i];
3462 if (ns1 == ns2)
3463 return(1);
3464 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3465 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3466 return(1);
3467 }
3468 }
3469 } else {
3470 for (i = 0; i < cur->nodeNr; i++) {
3471 if (cur->nodeTab[i] == val)
3472 return(1);
3473 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003474 }
3475 return(0);
3476}
3477
3478/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003479 * xmlXPathNodeSetAddNs:
3480 * @cur: the initial node set
3481 * @node: the hosting node
3482 * @ns: a the namespace node
3483 *
3484 * add a new namespace node to an existing NodeSet
3485 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003486void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003487xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3488 int i;
3489
Daniel Veillarda82b1822004-11-08 16:24:57 +00003490
3491 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3492 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003493 (node->type != XML_ELEMENT_NODE))
3494 return;
3495
William M. Brack08171912003-12-29 02:52:11 +00003496 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003497 /*
William M. Brack08171912003-12-29 02:52:11 +00003498 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003499 */
3500 for (i = 0;i < cur->nodeNr;i++) {
3501 if ((cur->nodeTab[i] != NULL) &&
3502 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003503 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003504 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3505 return;
3506 }
3507
3508 /*
3509 * grow the nodeTab if needed
3510 */
3511 if (cur->nodeMax == 0) {
3512 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3513 sizeof(xmlNodePtr));
3514 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003515 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003516 return;
3517 }
3518 memset(cur->nodeTab, 0 ,
3519 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3520 cur->nodeMax = XML_NODESET_DEFAULT;
3521 } else if (cur->nodeNr == cur->nodeMax) {
3522 xmlNodePtr *temp;
3523
3524 cur->nodeMax *= 2;
3525 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3526 sizeof(xmlNodePtr));
3527 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003528 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003529 return;
3530 }
3531 cur->nodeTab = temp;
3532 }
3533 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3534}
3535
3536/**
Owen Taylor3473f882001-02-23 17:55:21 +00003537 * xmlXPathNodeSetAdd:
3538 * @cur: the initial node set
3539 * @val: a new xmlNodePtr
3540 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003541 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003542 */
3543void
3544xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3545 int i;
3546
Daniel Veillarda82b1822004-11-08 16:24:57 +00003547 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003548
Daniel Veillardef0b4502003-03-24 13:57:34 +00003549#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003550 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3551 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003552#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003553
William M. Brack08171912003-12-29 02:52:11 +00003554 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003555 /*
William M. Brack08171912003-12-29 02:52:11 +00003556 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003557 */
3558 for (i = 0;i < cur->nodeNr;i++)
3559 if (cur->nodeTab[i] == val) return;
3560
3561 /*
3562 * grow the nodeTab if needed
3563 */
3564 if (cur->nodeMax == 0) {
3565 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3566 sizeof(xmlNodePtr));
3567 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003568 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003569 return;
3570 }
3571 memset(cur->nodeTab, 0 ,
3572 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3573 cur->nodeMax = XML_NODESET_DEFAULT;
3574 } else if (cur->nodeNr == cur->nodeMax) {
3575 xmlNodePtr *temp;
3576
3577 cur->nodeMax *= 2;
3578 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3579 sizeof(xmlNodePtr));
3580 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003581 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003582 return;
3583 }
3584 cur->nodeTab = temp;
3585 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003586 if (val->type == XML_NAMESPACE_DECL) {
3587 xmlNsPtr ns = (xmlNsPtr) val;
3588
3589 cur->nodeTab[cur->nodeNr++] =
3590 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3591 } else
3592 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003593}
3594
3595/**
3596 * xmlXPathNodeSetAddUnique:
3597 * @cur: the initial node set
3598 * @val: a new xmlNodePtr
3599 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003600 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003601 * when we are sure the node is not already in the set.
3602 */
3603void
3604xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003605 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003606
Daniel Veillardef0b4502003-03-24 13:57:34 +00003607#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003608 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3609 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003610#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003611
William M. Brack08171912003-12-29 02:52:11 +00003612 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003613 /*
3614 * grow the nodeTab if needed
3615 */
3616 if (cur->nodeMax == 0) {
3617 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3618 sizeof(xmlNodePtr));
3619 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003620 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003621 return;
3622 }
3623 memset(cur->nodeTab, 0 ,
3624 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3625 cur->nodeMax = XML_NODESET_DEFAULT;
3626 } else if (cur->nodeNr == cur->nodeMax) {
3627 xmlNodePtr *temp;
3628
3629 cur->nodeMax *= 2;
3630 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3631 sizeof(xmlNodePtr));
3632 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003633 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003634 return;
3635 }
3636 cur->nodeTab = temp;
3637 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003638 if (val->type == XML_NAMESPACE_DECL) {
3639 xmlNsPtr ns = (xmlNsPtr) val;
3640
3641 cur->nodeTab[cur->nodeNr++] =
3642 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3643 } else
3644 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003645}
3646
3647/**
3648 * xmlXPathNodeSetMerge:
3649 * @val1: the first NodeSet or NULL
3650 * @val2: the second NodeSet
3651 *
3652 * Merges two nodesets, all nodes from @val2 are added to @val1
3653 * if @val1 is NULL, a new set is created and copied from @val2
3654 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003655 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003656 */
3657xmlNodeSetPtr
3658xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003659 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003660 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003661
3662 if (val2 == NULL) return(val1);
3663 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003664 val1 = xmlXPathNodeSetCreate(NULL);
3665#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003666 /*
3667 * TODO: The optimization won't work in every case, since
3668 * those nasty namespace nodes need to be added with
3669 * xmlXPathNodeSetDupNs() to the set; thus a pure
3670 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003671 * If there was a flag on the nodesetval, indicating that
3672 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003673 */
3674 /*
3675 * Optimization: Create an equally sized node-set
3676 * and memcpy the content.
3677 */
3678 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3679 if (val1 == NULL)
3680 return(NULL);
3681 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003682 if (val2->nodeNr == 1)
3683 *(val1->nodeTab) = *(val2->nodeTab);
3684 else {
3685 memcpy(val1->nodeTab, val2->nodeTab,
3686 val2->nodeNr * sizeof(xmlNodePtr));
3687 }
3688 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003689 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003690 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003691#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003692 }
3693
William M. Brack08171912003-12-29 02:52:11 +00003694 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003695 initNr = val1->nodeNr;
3696
3697 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003698 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003699 /*
William M. Brack08171912003-12-29 02:52:11 +00003700 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003701 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003702 skip = 0;
3703 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003704 n1 = val1->nodeTab[j];
3705 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003706 skip = 1;
3707 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003708 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3709 (n2->type == XML_NAMESPACE_DECL)) {
3710 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3711 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3712 ((xmlNsPtr) n2)->prefix)))
3713 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003714 skip = 1;
3715 break;
3716 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003717 }
3718 }
3719 if (skip)
3720 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003721
3722 /*
3723 * grow the nodeTab if needed
3724 */
3725 if (val1->nodeMax == 0) {
3726 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3727 sizeof(xmlNodePtr));
3728 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003729 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003730 return(NULL);
3731 }
3732 memset(val1->nodeTab, 0 ,
3733 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3734 val1->nodeMax = XML_NODESET_DEFAULT;
3735 } else if (val1->nodeNr == val1->nodeMax) {
3736 xmlNodePtr *temp;
3737
3738 val1->nodeMax *= 2;
3739 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3740 sizeof(xmlNodePtr));
3741 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003742 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003743 return(NULL);
3744 }
3745 val1->nodeTab = temp;
3746 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003747 if (n2->type == XML_NAMESPACE_DECL) {
3748 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003749
3750 val1->nodeTab[val1->nodeNr++] =
3751 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3752 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003753 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003754 }
3755
3756 return(val1);
3757}
3758
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003759#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
Owen Taylor3473f882001-02-23 17:55:21 +00003760/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003761 * xmlXPathNodeSetMergeUnique:
3762 * @val1: the first NodeSet or NULL
3763 * @val2: the second NodeSet
3764 *
3765 * Merges two nodesets, all nodes from @val2 are added to @val1
3766 * if @val1 is NULL, a new set is created and copied from @val2
3767 *
3768 * Returns @val1 once extended or NULL in case of error.
3769 */
3770static xmlNodeSetPtr
3771xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003772 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003773
3774 if (val2 == NULL) return(val1);
3775 if (val1 == NULL) {
3776 val1 = xmlXPathNodeSetCreate(NULL);
3777 }
3778
William M. Brack08171912003-12-29 02:52:11 +00003779 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003780
3781 for (i = 0;i < val2->nodeNr;i++) {
3782 /*
3783 * grow the nodeTab if needed
3784 */
3785 if (val1->nodeMax == 0) {
3786 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3787 sizeof(xmlNodePtr));
3788 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003789 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003790 return(NULL);
3791 }
3792 memset(val1->nodeTab, 0 ,
3793 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3794 val1->nodeMax = XML_NODESET_DEFAULT;
3795 } else if (val1->nodeNr == val1->nodeMax) {
3796 xmlNodePtr *temp;
3797
3798 val1->nodeMax *= 2;
3799 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3800 sizeof(xmlNodePtr));
3801 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003802 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003803 return(NULL);
3804 }
3805 val1->nodeTab = temp;
3806 }
3807 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3808 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3809
3810 val1->nodeTab[val1->nodeNr++] =
3811 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3812 } else
3813 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3814 }
3815
3816 return(val1);
3817}
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00003818#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3819
3820/**
3821 * xmlXPathNodeSetMergeAndClear:
3822 * @set1: the first NodeSet or NULL
3823 * @set2: the second NodeSet
3824 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3825 *
3826 * Merges two nodesets, all nodes from @set2 are added to @set1
3827 * if @set1 is NULL, a new set is created and copied from @set2.
3828 * Checks for duplicate nodes. Clears set2.
3829 *
3830 * Returns @set1 once extended or NULL in case of error.
3831 */
3832static xmlNodeSetPtr
3833xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3834 int hasNullEntries)
3835{
3836 if ((set1 == NULL) && (hasNullEntries == 0)) {
3837 /*
3838 * Note that doing a memcpy of the list, namespace nodes are
3839 * just assigned to set1, since set2 is cleared anyway.
3840 */
3841 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3842 if (set1 == NULL)
3843 return(NULL);
3844 if (set2->nodeNr != 0) {
3845 memcpy(set1->nodeTab, set2->nodeTab,
3846 set2->nodeNr * sizeof(xmlNodePtr));
3847 set1->nodeNr = set2->nodeNr;
3848 }
3849 } else {
3850 int i, j, initNbSet1;
3851 xmlNodePtr n1, n2;
3852
3853 if (set1 == NULL)
3854 set1 = xmlXPathNodeSetCreate(NULL);
3855
3856 initNbSet1 = set1->nodeNr;
3857 for (i = 0;i < set2->nodeNr;i++) {
3858 n2 = set2->nodeTab[i];
3859 /*
3860 * Skip NULLed entries.
3861 */
3862 if (n2 == NULL)
3863 continue;
3864 /*
3865 * Skip duplicates.
3866 */
3867 for (j = 0; j < initNbSet1; j++) {
3868 n1 = set1->nodeTab[j];
3869 if (n1 == n2) {
3870 goto skip_node;
3871 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3872 (n2->type == XML_NAMESPACE_DECL))
3873 {
3874 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3875 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3876 ((xmlNsPtr) n2)->prefix)))
3877 {
3878 /*
3879 * Free the namespace node.
3880 */
3881 set2->nodeTab[i] = NULL;
3882 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3883 goto skip_node;
3884 }
3885 }
3886 }
3887 /*
3888 * grow the nodeTab if needed
3889 */
3890 if (set1->nodeMax == 0) {
3891 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3892 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3893 if (set1->nodeTab == NULL) {
3894 xmlXPathErrMemory(NULL, "merging nodeset\n");
3895 return(NULL);
3896 }
3897 memset(set1->nodeTab, 0,
3898 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3899 set1->nodeMax = XML_NODESET_DEFAULT;
3900 } else if (set1->nodeNr >= set1->nodeMax) {
3901 xmlNodePtr *temp;
3902
3903 set1->nodeMax *= 2;
3904 temp = (xmlNodePtr *) xmlRealloc(
3905 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3906 if (temp == NULL) {
3907 xmlXPathErrMemory(NULL, "merging nodeset\n");
3908 return(NULL);
3909 }
3910 set1->nodeTab = temp;
3911 }
3912 if (n2->type == XML_NAMESPACE_DECL) {
3913 xmlNsPtr ns = (xmlNsPtr) n2;
3914
3915 set1->nodeTab[set1->nodeNr++] =
3916 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3917 } else
3918 set1->nodeTab[set1->nodeNr++] = n2;
3919skip_node:
3920 {}
3921 }
3922 }
3923 set2->nodeNr = 0;
3924 return(set1);
3925}
3926
3927/**
3928 * xmlXPathNodeSetMergeAndClearNoDupls:
3929 * @set1: the first NodeSet or NULL
3930 * @set2: the second NodeSet
3931 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3932 *
3933 * Merges two nodesets, all nodes from @set2 are added to @set1
3934 * if @set1 is NULL, a new set is created and copied from @set2.
3935 * Doesn't chack for duplicate nodes. Clears set2.
3936 *
3937 * Returns @set1 once extended or NULL in case of error.
3938 */
3939static xmlNodeSetPtr
3940xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3941 int hasNullEntries)
3942{
3943 if (set2 == NULL)
3944 return(set1);
3945 if ((set1 == NULL) && (hasNullEntries == 0)) {
3946 /*
3947 * Note that doing a memcpy of the list, namespace nodes are
3948 * just assigned to set1, since set2 is cleared anyway.
3949 */
3950 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3951 if (set1 == NULL)
3952 return(NULL);
3953 if (set2->nodeNr != 0) {
3954 memcpy(set1->nodeTab, set2->nodeTab,
3955 set2->nodeNr * sizeof(xmlNodePtr));
3956 set1->nodeNr = set2->nodeNr;
3957 }
3958 } else {
3959 int i;
3960 xmlNodePtr n2;
3961
3962 if (set1 == NULL)
3963 set1 = xmlXPathNodeSetCreate(NULL);
3964
3965 for (i = 0;i < set2->nodeNr;i++) {
3966 n2 = set2->nodeTab[i];
3967 /*
3968 * Skip NULLed entries.
3969 */
3970 if (n2 == NULL)
3971 continue;
3972 if (set1->nodeMax == 0) {
3973 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3974 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3975 if (set1->nodeTab == NULL) {
3976 xmlXPathErrMemory(NULL, "merging nodeset\n");
3977 return(NULL);
3978 }
3979 memset(set1->nodeTab, 0,
3980 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3981 set1->nodeMax = XML_NODESET_DEFAULT;
3982 } else if (set1->nodeNr >= set1->nodeMax) {
3983 xmlNodePtr *temp;
3984
3985 set1->nodeMax *= 2;
3986 temp = (xmlNodePtr *) xmlRealloc(
3987 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3988 if (temp == NULL) {
3989 xmlXPathErrMemory(NULL, "merging nodeset\n");
3990 return(NULL);
3991 }
3992 set1->nodeTab = temp;
3993 }
3994 set1->nodeTab[set1->nodeNr++] = n2;
3995 }
3996 }
3997 set2->nodeNr = 0;
3998 return(set1);
3999}
Daniel Veillard75be0132002-03-13 10:03:35 +00004000
4001/**
Owen Taylor3473f882001-02-23 17:55:21 +00004002 * xmlXPathNodeSetDel:
4003 * @cur: the initial node set
4004 * @val: an xmlNodePtr
4005 *
4006 * Removes an xmlNodePtr from an existing NodeSet
4007 */
4008void
4009xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4010 int i;
4011
4012 if (cur == NULL) return;
4013 if (val == NULL) return;
4014
4015 /*
William M. Brack08171912003-12-29 02:52:11 +00004016 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00004017 */
4018 for (i = 0;i < cur->nodeNr;i++)
4019 if (cur->nodeTab[i] == val) break;
4020
William M. Brack08171912003-12-29 02:52:11 +00004021 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00004022#ifdef DEBUG
4023 xmlGenericError(xmlGenericErrorContext,
4024 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4025 val->name);
4026#endif
4027 return;
4028 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004029 if ((cur->nodeTab[i] != NULL) &&
4030 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4031 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004032 cur->nodeNr--;
4033 for (;i < cur->nodeNr;i++)
4034 cur->nodeTab[i] = cur->nodeTab[i + 1];
4035 cur->nodeTab[cur->nodeNr] = NULL;
4036}
4037
4038/**
4039 * xmlXPathNodeSetRemove:
4040 * @cur: the initial node set
4041 * @val: the index to remove
4042 *
4043 * Removes an entry from an existing NodeSet list.
4044 */
4045void
4046xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4047 if (cur == NULL) return;
4048 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004049 if ((cur->nodeTab[val] != NULL) &&
4050 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4051 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00004052 cur->nodeNr--;
4053 for (;val < cur->nodeNr;val++)
4054 cur->nodeTab[val] = cur->nodeTab[val + 1];
4055 cur->nodeTab[cur->nodeNr] = NULL;
4056}
4057
4058/**
4059 * xmlXPathFreeNodeSet:
4060 * @obj: the xmlNodeSetPtr to free
4061 *
4062 * Free the NodeSet compound (not the actual nodes !).
4063 */
4064void
4065xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4066 if (obj == NULL) return;
4067 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004068 int i;
4069
William M. Brack08171912003-12-29 02:52:11 +00004070 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004071 for (i = 0;i < obj->nodeNr;i++)
4072 if ((obj->nodeTab[i] != NULL) &&
4073 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004075 xmlFree(obj->nodeTab);
4076 }
Owen Taylor3473f882001-02-23 17:55:21 +00004077 xmlFree(obj);
4078}
4079
4080/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004081 * xmlXPathNodeSetClear:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004082 * @set: the node set to clear
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004083 *
4084 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4085 * are feed), but does *not* free the list itself. Sets the length of the
4086 * list to 0.
4087 */
4088static void
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004089xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4090{
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004091 if ((set == NULL) || (set->nodeNr <= 0))
4092 return;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004093 else if (hasNsNodes) {
4094 int i;
4095 xmlNodePtr node;
4096
4097 for (i = 0; i < set->nodeNr; i++) {
4098 node = set->nodeTab[i];
4099 if ((node != NULL) &&
4100 (node->type == XML_NAMESPACE_DECL))
4101 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4102 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004103 }
4104 set->nodeNr = 0;
4105}
4106
4107/**
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00004108 * xmlXPathNodeSetClearFromPos:
4109 * @set: the node set to be cleared
4110 * @pos: the start position to clear from
4111 *
4112 * Clears the list from temporary XPath objects (e.g. namespace nodes
4113 * are feed) starting with the entry at @pos, but does *not* free the list
4114 * itself. Sets the length of the list to @pos.
4115 */
4116static void
4117xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4118{
4119 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4120 return;
4121 else if ((hasNsNodes)) {
4122 int i;
4123 xmlNodePtr node;
4124
4125 for (i = pos; i < set->nodeNr; i++) {
4126 node = set->nodeTab[i];
4127 if ((node != NULL) &&
4128 (node->type == XML_NAMESPACE_DECL))
4129 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4130 }
4131 }
4132 set->nodeNr = pos;
4133}
4134
4135/**
Owen Taylor3473f882001-02-23 17:55:21 +00004136 * xmlXPathFreeValueTree:
4137 * @obj: the xmlNodeSetPtr to free
4138 *
4139 * Free the NodeSet compound and the actual tree, this is different
4140 * from xmlXPathFreeNodeSet()
4141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004142static void
Owen Taylor3473f882001-02-23 17:55:21 +00004143xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4144 int i;
4145
4146 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00004147
4148 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004149 for (i = 0;i < obj->nodeNr;i++) {
4150 if (obj->nodeTab[i] != NULL) {
4151 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4152 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4153 } else {
4154 xmlFreeNodeList(obj->nodeTab[i]);
4155 }
4156 }
4157 }
Owen Taylor3473f882001-02-23 17:55:21 +00004158 xmlFree(obj->nodeTab);
4159 }
Owen Taylor3473f882001-02-23 17:55:21 +00004160 xmlFree(obj);
4161}
4162
4163#if defined(DEBUG) || defined(DEBUG_STEP)
4164/**
4165 * xmlGenericErrorContextNodeSet:
4166 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00004167 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00004168 *
4169 * Quick display of a NodeSet
4170 */
4171void
4172xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4173 int i;
4174
4175 if (output == NULL) output = xmlGenericErrorContext;
4176 if (obj == NULL) {
4177 fprintf(output, "NodeSet == NULL !\n");
4178 return;
4179 }
4180 if (obj->nodeNr == 0) {
4181 fprintf(output, "NodeSet is empty\n");
4182 return;
4183 }
4184 if (obj->nodeTab == NULL) {
4185 fprintf(output, " nodeTab == NULL !\n");
4186 return;
4187 }
4188 for (i = 0; i < obj->nodeNr; i++) {
4189 if (obj->nodeTab[i] == NULL) {
4190 fprintf(output, " NULL !\n");
4191 return;
4192 }
4193 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4194 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4195 fprintf(output, " /");
4196 else if (obj->nodeTab[i]->name == NULL)
4197 fprintf(output, " noname!");
4198 else fprintf(output, " %s", obj->nodeTab[i]->name);
4199 }
4200 fprintf(output, "\n");
4201}
4202#endif
4203
4204/**
4205 * xmlXPathNewNodeSet:
4206 * @val: the NodePtr value
4207 *
4208 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4209 * it with the single Node @val
4210 *
4211 * Returns the newly created object.
4212 */
4213xmlXPathObjectPtr
4214xmlXPathNewNodeSet(xmlNodePtr val) {
4215 xmlXPathObjectPtr ret;
4216
4217 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4218 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004219 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004220 return(NULL);
4221 }
4222 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4223 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00004224 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004225 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004226 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004227#ifdef XP_DEBUG_OBJ_USAGE
4228 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4229#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004230 return(ret);
4231}
4232
4233/**
4234 * xmlXPathNewValueTree:
4235 * @val: the NodePtr value
4236 *
4237 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4238 * it with the tree root @val
4239 *
4240 * Returns the newly created object.
4241 */
4242xmlXPathObjectPtr
4243xmlXPathNewValueTree(xmlNodePtr val) {
4244 xmlXPathObjectPtr ret;
4245
4246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004248 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004249 return(NULL);
4250 }
4251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4252 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004253 ret->boolval = 1;
4254 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004255 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004256#ifdef XP_DEBUG_OBJ_USAGE
4257 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4258#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004259 return(ret);
4260}
4261
4262/**
4263 * xmlXPathNewNodeSetList:
4264 * @val: an existing NodeSet
4265 *
4266 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4267 * it with the Nodeset @val
4268 *
4269 * Returns the newly created object.
4270 */
4271xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004272xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4273{
Owen Taylor3473f882001-02-23 17:55:21 +00004274 xmlXPathObjectPtr ret;
4275 int i;
4276
4277 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004278 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004279 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004280 ret = xmlXPathNewNodeSet(NULL);
4281 else {
4282 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4283 for (i = 1; i < val->nodeNr; ++i)
4284 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4285 }
Owen Taylor3473f882001-02-23 17:55:21 +00004286
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004287 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004288}
4289
4290/**
4291 * xmlXPathWrapNodeSet:
4292 * @val: the NodePtr value
4293 *
4294 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4295 *
4296 * Returns the newly created object.
4297 */
4298xmlXPathObjectPtr
4299xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4300 xmlXPathObjectPtr ret;
4301
4302 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4303 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004304 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004305 return(NULL);
4306 }
4307 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4308 ret->type = XPATH_NODESET;
4309 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004310#ifdef XP_DEBUG_OBJ_USAGE
4311 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4312#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004313 return(ret);
4314}
4315
4316/**
4317 * xmlXPathFreeNodeSetList:
4318 * @obj: an existing NodeSetList object
4319 *
4320 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4321 * the list contrary to xmlXPathFreeObject().
4322 */
4323void
4324xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4325 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004326#ifdef XP_DEBUG_OBJ_USAGE
4327 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4328#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004329 xmlFree(obj);
4330}
4331
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004332/**
4333 * xmlXPathDifference:
4334 * @nodes1: a node-set
4335 * @nodes2: a node-set
4336 *
4337 * Implements the EXSLT - Sets difference() function:
4338 * node-set set:difference (node-set, node-set)
4339 *
4340 * Returns the difference between the two node sets, or nodes1 if
4341 * nodes2 is empty
4342 */
4343xmlNodeSetPtr
4344xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4345 xmlNodeSetPtr ret;
4346 int i, l1;
4347 xmlNodePtr cur;
4348
4349 if (xmlXPathNodeSetIsEmpty(nodes2))
4350 return(nodes1);
4351
4352 ret = xmlXPathNodeSetCreate(NULL);
4353 if (xmlXPathNodeSetIsEmpty(nodes1))
4354 return(ret);
4355
4356 l1 = xmlXPathNodeSetGetLength(nodes1);
4357
4358 for (i = 0; i < l1; i++) {
4359 cur = xmlXPathNodeSetItem(nodes1, i);
4360 if (!xmlXPathNodeSetContains(nodes2, cur))
4361 xmlXPathNodeSetAddUnique(ret, cur);
4362 }
4363 return(ret);
4364}
4365
4366/**
4367 * xmlXPathIntersection:
4368 * @nodes1: a node-set
4369 * @nodes2: a node-set
4370 *
4371 * Implements the EXSLT - Sets intersection() function:
4372 * node-set set:intersection (node-set, node-set)
4373 *
4374 * Returns a node set comprising the nodes that are within both the
4375 * node sets passed as arguments
4376 */
4377xmlNodeSetPtr
4378xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4379 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4380 int i, l1;
4381 xmlNodePtr cur;
4382
4383 if (xmlXPathNodeSetIsEmpty(nodes1))
4384 return(ret);
4385 if (xmlXPathNodeSetIsEmpty(nodes2))
4386 return(ret);
4387
4388 l1 = xmlXPathNodeSetGetLength(nodes1);
4389
4390 for (i = 0; i < l1; i++) {
4391 cur = xmlXPathNodeSetItem(nodes1, i);
4392 if (xmlXPathNodeSetContains(nodes2, cur))
4393 xmlXPathNodeSetAddUnique(ret, cur);
4394 }
4395 return(ret);
4396}
4397
4398/**
4399 * xmlXPathDistinctSorted:
4400 * @nodes: a node-set, sorted by document order
4401 *
4402 * Implements the EXSLT - Sets distinct() function:
4403 * node-set set:distinct (node-set)
4404 *
4405 * Returns a subset of the nodes contained in @nodes, or @nodes if
4406 * it is empty
4407 */
4408xmlNodeSetPtr
4409xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4410 xmlNodeSetPtr ret;
4411 xmlHashTablePtr hash;
4412 int i, l;
4413 xmlChar * strval;
4414 xmlNodePtr cur;
4415
4416 if (xmlXPathNodeSetIsEmpty(nodes))
4417 return(nodes);
4418
4419 ret = xmlXPathNodeSetCreate(NULL);
4420 l = xmlXPathNodeSetGetLength(nodes);
4421 hash = xmlHashCreate (l);
4422 for (i = 0; i < l; i++) {
4423 cur = xmlXPathNodeSetItem(nodes, i);
4424 strval = xmlXPathCastNodeToString(cur);
4425 if (xmlHashLookup(hash, strval) == NULL) {
4426 xmlHashAddEntry(hash, strval, strval);
4427 xmlXPathNodeSetAddUnique(ret, cur);
4428 } else {
4429 xmlFree(strval);
4430 }
4431 }
4432 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4433 return(ret);
4434}
4435
4436/**
4437 * xmlXPathDistinct:
4438 * @nodes: a node-set
4439 *
4440 * Implements the EXSLT - Sets distinct() function:
4441 * node-set set:distinct (node-set)
4442 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4443 * is called with the sorted node-set
4444 *
4445 * Returns a subset of the nodes contained in @nodes, or @nodes if
4446 * it is empty
4447 */
4448xmlNodeSetPtr
4449xmlXPathDistinct (xmlNodeSetPtr nodes) {
4450 if (xmlXPathNodeSetIsEmpty(nodes))
4451 return(nodes);
4452
4453 xmlXPathNodeSetSort(nodes);
4454 return(xmlXPathDistinctSorted(nodes));
4455}
4456
4457/**
4458 * xmlXPathHasSameNodes:
4459 * @nodes1: a node-set
4460 * @nodes2: a node-set
4461 *
4462 * Implements the EXSLT - Sets has-same-nodes function:
4463 * boolean set:has-same-node(node-set, node-set)
4464 *
4465 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4466 * otherwise
4467 */
4468int
4469xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4470 int i, l;
4471 xmlNodePtr cur;
4472
4473 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4474 xmlXPathNodeSetIsEmpty(nodes2))
4475 return(0);
4476
4477 l = xmlXPathNodeSetGetLength(nodes1);
4478 for (i = 0; i < l; i++) {
4479 cur = xmlXPathNodeSetItem(nodes1, i);
4480 if (xmlXPathNodeSetContains(nodes2, cur))
4481 return(1);
4482 }
4483 return(0);
4484}
4485
4486/**
4487 * xmlXPathNodeLeadingSorted:
4488 * @nodes: a node-set, sorted by document order
4489 * @node: a node
4490 *
4491 * Implements the EXSLT - Sets leading() function:
4492 * node-set set:leading (node-set, node-set)
4493 *
4494 * Returns the nodes in @nodes that precede @node in document order,
4495 * @nodes if @node is NULL or an empty node-set if @nodes
4496 * doesn't contain @node
4497 */
4498xmlNodeSetPtr
4499xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4500 int i, l;
4501 xmlNodePtr cur;
4502 xmlNodeSetPtr ret;
4503
4504 if (node == NULL)
4505 return(nodes);
4506
4507 ret = xmlXPathNodeSetCreate(NULL);
4508 if (xmlXPathNodeSetIsEmpty(nodes) ||
4509 (!xmlXPathNodeSetContains(nodes, node)))
4510 return(ret);
4511
4512 l = xmlXPathNodeSetGetLength(nodes);
4513 for (i = 0; i < l; i++) {
4514 cur = xmlXPathNodeSetItem(nodes, i);
4515 if (cur == node)
4516 break;
4517 xmlXPathNodeSetAddUnique(ret, cur);
4518 }
4519 return(ret);
4520}
4521
4522/**
4523 * xmlXPathNodeLeading:
4524 * @nodes: a node-set
4525 * @node: a node
4526 *
4527 * Implements the EXSLT - Sets leading() function:
4528 * node-set set:leading (node-set, node-set)
4529 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4530 * is called.
4531 *
4532 * Returns the nodes in @nodes that precede @node in document order,
4533 * @nodes if @node is NULL or an empty node-set if @nodes
4534 * doesn't contain @node
4535 */
4536xmlNodeSetPtr
4537xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4538 xmlXPathNodeSetSort(nodes);
4539 return(xmlXPathNodeLeadingSorted(nodes, node));
4540}
4541
4542/**
4543 * xmlXPathLeadingSorted:
4544 * @nodes1: a node-set, sorted by document order
4545 * @nodes2: a node-set, sorted by document order
4546 *
4547 * Implements the EXSLT - Sets leading() function:
4548 * node-set set:leading (node-set, node-set)
4549 *
4550 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4551 * in document order, @nodes1 if @nodes2 is NULL or empty or
4552 * an empty node-set if @nodes1 doesn't contain @nodes2
4553 */
4554xmlNodeSetPtr
4555xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4556 if (xmlXPathNodeSetIsEmpty(nodes2))
4557 return(nodes1);
4558 return(xmlXPathNodeLeadingSorted(nodes1,
4559 xmlXPathNodeSetItem(nodes2, 1)));
4560}
4561
4562/**
4563 * xmlXPathLeading:
4564 * @nodes1: a node-set
4565 * @nodes2: a node-set
4566 *
4567 * Implements the EXSLT - Sets leading() function:
4568 * node-set set:leading (node-set, node-set)
4569 * @nodes1 and @nodes2 are sorted by document order, then
4570 * #exslSetsLeadingSorted is called.
4571 *
4572 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4573 * in document order, @nodes1 if @nodes2 is NULL or empty or
4574 * an empty node-set if @nodes1 doesn't contain @nodes2
4575 */
4576xmlNodeSetPtr
4577xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4578 if (xmlXPathNodeSetIsEmpty(nodes2))
4579 return(nodes1);
4580 if (xmlXPathNodeSetIsEmpty(nodes1))
4581 return(xmlXPathNodeSetCreate(NULL));
4582 xmlXPathNodeSetSort(nodes1);
4583 xmlXPathNodeSetSort(nodes2);
4584 return(xmlXPathNodeLeadingSorted(nodes1,
4585 xmlXPathNodeSetItem(nodes2, 1)));
4586}
4587
4588/**
4589 * xmlXPathNodeTrailingSorted:
4590 * @nodes: a node-set, sorted by document order
4591 * @node: a node
4592 *
4593 * Implements the EXSLT - Sets trailing() function:
4594 * node-set set:trailing (node-set, node-set)
4595 *
4596 * Returns the nodes in @nodes that follow @node in document order,
4597 * @nodes if @node is NULL or an empty node-set if @nodes
4598 * doesn't contain @node
4599 */
4600xmlNodeSetPtr
4601xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4602 int i, l;
4603 xmlNodePtr cur;
4604 xmlNodeSetPtr ret;
4605
4606 if (node == NULL)
4607 return(nodes);
4608
4609 ret = xmlXPathNodeSetCreate(NULL);
4610 if (xmlXPathNodeSetIsEmpty(nodes) ||
4611 (!xmlXPathNodeSetContains(nodes, node)))
4612 return(ret);
4613
4614 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004615 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004616 cur = xmlXPathNodeSetItem(nodes, i);
4617 if (cur == node)
4618 break;
4619 xmlXPathNodeSetAddUnique(ret, cur);
4620 }
4621 return(ret);
4622}
4623
4624/**
4625 * xmlXPathNodeTrailing:
4626 * @nodes: a node-set
4627 * @node: a node
4628 *
4629 * Implements the EXSLT - Sets trailing() function:
4630 * node-set set:trailing (node-set, node-set)
4631 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4632 * is called.
4633 *
4634 * Returns the nodes in @nodes that follow @node in document order,
4635 * @nodes if @node is NULL or an empty node-set if @nodes
4636 * doesn't contain @node
4637 */
4638xmlNodeSetPtr
4639xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4640 xmlXPathNodeSetSort(nodes);
4641 return(xmlXPathNodeTrailingSorted(nodes, node));
4642}
4643
4644/**
4645 * xmlXPathTrailingSorted:
4646 * @nodes1: a node-set, sorted by document order
4647 * @nodes2: a node-set, sorted by document order
4648 *
4649 * Implements the EXSLT - Sets trailing() function:
4650 * node-set set:trailing (node-set, node-set)
4651 *
4652 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4653 * in document order, @nodes1 if @nodes2 is NULL or empty or
4654 * an empty node-set if @nodes1 doesn't contain @nodes2
4655 */
4656xmlNodeSetPtr
4657xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4658 if (xmlXPathNodeSetIsEmpty(nodes2))
4659 return(nodes1);
4660 return(xmlXPathNodeTrailingSorted(nodes1,
4661 xmlXPathNodeSetItem(nodes2, 0)));
4662}
4663
4664/**
4665 * xmlXPathTrailing:
4666 * @nodes1: a node-set
4667 * @nodes2: a node-set
4668 *
4669 * Implements the EXSLT - Sets trailing() function:
4670 * node-set set:trailing (node-set, node-set)
4671 * @nodes1 and @nodes2 are sorted by document order, then
4672 * #xmlXPathTrailingSorted is called.
4673 *
4674 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4675 * in document order, @nodes1 if @nodes2 is NULL or empty or
4676 * an empty node-set if @nodes1 doesn't contain @nodes2
4677 */
4678xmlNodeSetPtr
4679xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4680 if (xmlXPathNodeSetIsEmpty(nodes2))
4681 return(nodes1);
4682 if (xmlXPathNodeSetIsEmpty(nodes1))
4683 return(xmlXPathNodeSetCreate(NULL));
4684 xmlXPathNodeSetSort(nodes1);
4685 xmlXPathNodeSetSort(nodes2);
4686 return(xmlXPathNodeTrailingSorted(nodes1,
4687 xmlXPathNodeSetItem(nodes2, 0)));
4688}
4689
Owen Taylor3473f882001-02-23 17:55:21 +00004690/************************************************************************
4691 * *
4692 * Routines to handle extra functions *
4693 * *
4694 ************************************************************************/
4695
4696/**
4697 * xmlXPathRegisterFunc:
4698 * @ctxt: the XPath context
4699 * @name: the function name
4700 * @f: the function implementation or NULL
4701 *
4702 * Register a new function. If @f is NULL it unregisters the function
4703 *
4704 * Returns 0 in case of success, -1 in case of error
4705 */
4706int
4707xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4708 xmlXPathFunction f) {
4709 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4710}
4711
4712/**
4713 * xmlXPathRegisterFuncNS:
4714 * @ctxt: the XPath context
4715 * @name: the function name
4716 * @ns_uri: the function namespace URI
4717 * @f: the function implementation or NULL
4718 *
4719 * Register a new function. If @f is NULL it unregisters the function
4720 *
4721 * Returns 0 in case of success, -1 in case of error
4722 */
4723int
4724xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4725 const xmlChar *ns_uri, xmlXPathFunction f) {
4726 if (ctxt == NULL)
4727 return(-1);
4728 if (name == NULL)
4729 return(-1);
4730
4731 if (ctxt->funcHash == NULL)
4732 ctxt->funcHash = xmlHashCreate(0);
4733 if (ctxt->funcHash == NULL)
4734 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004735 if (f == NULL)
4736 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004737 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004738}
4739
4740/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004741 * xmlXPathRegisterFuncLookup:
4742 * @ctxt: the XPath context
4743 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004744 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004745 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004746 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004747 */
4748void
4749xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4750 xmlXPathFuncLookupFunc f,
4751 void *funcCtxt) {
4752 if (ctxt == NULL)
4753 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004754 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004755 ctxt->funcLookupData = funcCtxt;
4756}
4757
4758/**
Owen Taylor3473f882001-02-23 17:55:21 +00004759 * xmlXPathFunctionLookup:
4760 * @ctxt: the XPath context
4761 * @name: the function name
4762 *
4763 * Search in the Function array of the context for the given
4764 * function.
4765 *
4766 * Returns the xmlXPathFunction or NULL if not found
4767 */
4768xmlXPathFunction
4769xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004770 if (ctxt == NULL)
4771 return (NULL);
4772
4773 if (ctxt->funcLookupFunc != NULL) {
4774 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004775 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004776
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004777 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004778 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004779 if (ret != NULL)
4780 return(ret);
4781 }
Owen Taylor3473f882001-02-23 17:55:21 +00004782 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4783}
4784
4785/**
4786 * xmlXPathFunctionLookupNS:
4787 * @ctxt: the XPath context
4788 * @name: the function name
4789 * @ns_uri: the function namespace URI
4790 *
4791 * Search in the Function array of the context for the given
4792 * function.
4793 *
4794 * Returns the xmlXPathFunction or NULL if not found
4795 */
4796xmlXPathFunction
4797xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4798 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004799 xmlXPathFunction ret;
4800
Owen Taylor3473f882001-02-23 17:55:21 +00004801 if (ctxt == NULL)
4802 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004803 if (name == NULL)
4804 return(NULL);
4805
Thomas Broyerba4ad322001-07-26 16:55:21 +00004806 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004807 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004808
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004809 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004810 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004811 if (ret != NULL)
4812 return(ret);
4813 }
4814
4815 if (ctxt->funcHash == NULL)
4816 return(NULL);
4817
William M. Brackad0e67c2004-12-01 14:35:10 +00004818 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4819 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004820}
4821
4822/**
4823 * xmlXPathRegisteredFuncsCleanup:
4824 * @ctxt: the XPath context
4825 *
4826 * Cleanup the XPath context data associated to registered functions
4827 */
4828void
4829xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4830 if (ctxt == NULL)
4831 return;
4832
4833 xmlHashFree(ctxt->funcHash, NULL);
4834 ctxt->funcHash = NULL;
4835}
4836
4837/************************************************************************
4838 * *
William M. Brack08171912003-12-29 02:52:11 +00004839 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004840 * *
4841 ************************************************************************/
4842
4843/**
4844 * xmlXPathRegisterVariable:
4845 * @ctxt: the XPath context
4846 * @name: the variable name
4847 * @value: the variable value or NULL
4848 *
4849 * Register a new variable value. If @value is NULL it unregisters
4850 * the variable
4851 *
4852 * Returns 0 in case of success, -1 in case of error
4853 */
4854int
4855xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4856 xmlXPathObjectPtr value) {
4857 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4858}
4859
4860/**
4861 * xmlXPathRegisterVariableNS:
4862 * @ctxt: the XPath context
4863 * @name: the variable name
4864 * @ns_uri: the variable namespace URI
4865 * @value: the variable value or NULL
4866 *
4867 * Register a new variable value. If @value is NULL it unregisters
4868 * the variable
4869 *
4870 * Returns 0 in case of success, -1 in case of error
4871 */
4872int
4873xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4874 const xmlChar *ns_uri,
4875 xmlXPathObjectPtr value) {
4876 if (ctxt == NULL)
4877 return(-1);
4878 if (name == NULL)
4879 return(-1);
4880
4881 if (ctxt->varHash == NULL)
4882 ctxt->varHash = xmlHashCreate(0);
4883 if (ctxt->varHash == NULL)
4884 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004885 if (value == NULL)
4886 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4887 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004888 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4889 (void *) value,
4890 (xmlHashDeallocator)xmlXPathFreeObject));
4891}
4892
4893/**
4894 * xmlXPathRegisterVariableLookup:
4895 * @ctxt: the XPath context
4896 * @f: the lookup function
4897 * @data: the lookup data
4898 *
4899 * register an external mechanism to do variable lookup
4900 */
4901void
4902xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4903 xmlXPathVariableLookupFunc f, void *data) {
4904 if (ctxt == NULL)
4905 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004906 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004907 ctxt->varLookupData = data;
4908}
4909
4910/**
4911 * xmlXPathVariableLookup:
4912 * @ctxt: the XPath context
4913 * @name: the variable name
4914 *
4915 * Search in the Variable array of the context for the given
4916 * variable value.
4917 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004918 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004919 */
4920xmlXPathObjectPtr
4921xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4922 if (ctxt == NULL)
4923 return(NULL);
4924
4925 if (ctxt->varLookupFunc != NULL) {
4926 xmlXPathObjectPtr ret;
4927
4928 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4929 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004930 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004931 }
4932 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4933}
4934
4935/**
4936 * xmlXPathVariableLookupNS:
4937 * @ctxt: the XPath context
4938 * @name: the variable name
4939 * @ns_uri: the variable namespace URI
4940 *
4941 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004942 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004943 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004944 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004945 */
4946xmlXPathObjectPtr
4947xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4948 const xmlChar *ns_uri) {
4949 if (ctxt == NULL)
4950 return(NULL);
4951
4952 if (ctxt->varLookupFunc != NULL) {
4953 xmlXPathObjectPtr ret;
4954
4955 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4956 (ctxt->varLookupData, name, ns_uri);
4957 if (ret != NULL) return(ret);
4958 }
4959
4960 if (ctxt->varHash == NULL)
4961 return(NULL);
4962 if (name == NULL)
4963 return(NULL);
4964
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004965 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004966 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004967}
4968
4969/**
4970 * xmlXPathRegisteredVariablesCleanup:
4971 * @ctxt: the XPath context
4972 *
4973 * Cleanup the XPath context data associated to registered variables
4974 */
4975void
4976xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4977 if (ctxt == NULL)
4978 return;
4979
Daniel Veillard76d66f42001-05-16 21:05:17 +00004980 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004981 ctxt->varHash = NULL;
4982}
4983
4984/**
4985 * xmlXPathRegisterNs:
4986 * @ctxt: the XPath context
4987 * @prefix: the namespace prefix
4988 * @ns_uri: the namespace name
4989 *
4990 * Register a new namespace. If @ns_uri is NULL it unregisters
4991 * the namespace
4992 *
4993 * Returns 0 in case of success, -1 in case of error
4994 */
4995int
4996xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4997 const xmlChar *ns_uri) {
4998 if (ctxt == NULL)
4999 return(-1);
5000 if (prefix == NULL)
5001 return(-1);
5002
5003 if (ctxt->nsHash == NULL)
5004 ctxt->nsHash = xmlHashCreate(10);
5005 if (ctxt->nsHash == NULL)
5006 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00005007 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00005008 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00005009 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00005010 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00005011 (xmlHashDeallocator)xmlFree));
5012}
5013
5014/**
5015 * xmlXPathNsLookup:
5016 * @ctxt: the XPath context
5017 * @prefix: the namespace prefix value
5018 *
5019 * Search in the namespace declaration array of the context for the given
5020 * namespace name associated to the given prefix
5021 *
5022 * Returns the value or NULL if not found
5023 */
5024const xmlChar *
5025xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5026 if (ctxt == NULL)
5027 return(NULL);
5028 if (prefix == NULL)
5029 return(NULL);
5030
5031#ifdef XML_XML_NAMESPACE
5032 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5033 return(XML_XML_NAMESPACE);
5034#endif
5035
Daniel Veillardc8f620b2001-04-30 20:31:33 +00005036 if (ctxt->namespaces != NULL) {
5037 int i;
5038
5039 for (i = 0;i < ctxt->nsNr;i++) {
5040 if ((ctxt->namespaces[i] != NULL) &&
5041 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5042 return(ctxt->namespaces[i]->href);
5043 }
5044 }
Owen Taylor3473f882001-02-23 17:55:21 +00005045
5046 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5047}
5048
5049/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005050 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00005051 * @ctxt: the XPath context
5052 *
5053 * Cleanup the XPath context data associated to registered variables
5054 */
5055void
5056xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5057 if (ctxt == NULL)
5058 return;
5059
Daniel Veillard42766c02002-08-22 20:52:17 +00005060 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00005061 ctxt->nsHash = NULL;
5062}
5063
5064/************************************************************************
5065 * *
5066 * Routines to handle Values *
5067 * *
5068 ************************************************************************/
5069
William M. Brack08171912003-12-29 02:52:11 +00005070/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00005071
5072/**
5073 * xmlXPathNewFloat:
5074 * @val: the double value
5075 *
5076 * Create a new xmlXPathObjectPtr of type double and of value @val
5077 *
5078 * Returns the newly created object.
5079 */
5080xmlXPathObjectPtr
5081xmlXPathNewFloat(double val) {
5082 xmlXPathObjectPtr ret;
5083
5084 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5085 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005086 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005087 return(NULL);
5088 }
5089 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5090 ret->type = XPATH_NUMBER;
5091 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005092#ifdef XP_DEBUG_OBJ_USAGE
5093 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5094#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005095 return(ret);
5096}
5097
5098/**
5099 * xmlXPathNewBoolean:
5100 * @val: the boolean value
5101 *
5102 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5103 *
5104 * Returns the newly created object.
5105 */
5106xmlXPathObjectPtr
5107xmlXPathNewBoolean(int val) {
5108 xmlXPathObjectPtr ret;
5109
5110 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5111 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005112 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005113 return(NULL);
5114 }
5115 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5116 ret->type = XPATH_BOOLEAN;
5117 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005118#ifdef XP_DEBUG_OBJ_USAGE
5119 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5120#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005121 return(ret);
5122}
5123
5124/**
5125 * xmlXPathNewString:
5126 * @val: the xmlChar * value
5127 *
5128 * Create a new xmlXPathObjectPtr of type string and of value @val
5129 *
5130 * Returns the newly created object.
5131 */
5132xmlXPathObjectPtr
5133xmlXPathNewString(const xmlChar *val) {
5134 xmlXPathObjectPtr ret;
5135
5136 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5137 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005138 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005139 return(NULL);
5140 }
5141 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5142 ret->type = XPATH_STRING;
5143 if (val != NULL)
5144 ret->stringval = xmlStrdup(val);
5145 else
5146 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005147#ifdef XP_DEBUG_OBJ_USAGE
5148 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5149#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005150 return(ret);
5151}
5152
5153/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005154 * xmlXPathWrapString:
5155 * @val: the xmlChar * value
5156 *
5157 * Wraps the @val string into an XPath object.
5158 *
5159 * Returns the newly created object.
5160 */
5161xmlXPathObjectPtr
5162xmlXPathWrapString (xmlChar *val) {
5163 xmlXPathObjectPtr ret;
5164
5165 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5166 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005167 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005168 return(NULL);
5169 }
5170 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5171 ret->type = XPATH_STRING;
5172 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005173#ifdef XP_DEBUG_OBJ_USAGE
5174 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5175#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005176 return(ret);
5177}
5178
5179/**
Owen Taylor3473f882001-02-23 17:55:21 +00005180 * xmlXPathNewCString:
5181 * @val: the char * value
5182 *
5183 * Create a new xmlXPathObjectPtr of type string and of value @val
5184 *
5185 * Returns the newly created object.
5186 */
5187xmlXPathObjectPtr
5188xmlXPathNewCString(const char *val) {
5189 xmlXPathObjectPtr ret;
5190
5191 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5192 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005193 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005194 return(NULL);
5195 }
5196 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5197 ret->type = XPATH_STRING;
5198 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005199#ifdef XP_DEBUG_OBJ_USAGE
5200 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5201#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005202 return(ret);
5203}
5204
5205/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005206 * xmlXPathWrapCString:
5207 * @val: the char * value
5208 *
5209 * Wraps a string into an XPath object.
5210 *
5211 * Returns the newly created object.
5212 */
5213xmlXPathObjectPtr
5214xmlXPathWrapCString (char * val) {
5215 return(xmlXPathWrapString((xmlChar *)(val)));
5216}
5217
5218/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005219 * xmlXPathWrapExternal:
5220 * @val: the user data
5221 *
5222 * Wraps the @val data into an XPath object.
5223 *
5224 * Returns the newly created object.
5225 */
5226xmlXPathObjectPtr
5227xmlXPathWrapExternal (void *val) {
5228 xmlXPathObjectPtr ret;
5229
5230 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5231 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005232 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005233 return(NULL);
5234 }
5235 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236 ret->type = XPATH_USERS;
5237 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005238#ifdef XP_DEBUG_OBJ_USAGE
5239 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5240#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005241 return(ret);
5242}
5243
5244/**
Owen Taylor3473f882001-02-23 17:55:21 +00005245 * xmlXPathObjectCopy:
5246 * @val: the original object
5247 *
5248 * allocate a new copy of a given object
5249 *
5250 * Returns the newly created object.
5251 */
5252xmlXPathObjectPtr
5253xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5254 xmlXPathObjectPtr ret;
5255
5256 if (val == NULL)
5257 return(NULL);
5258
5259 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5260 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005261 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005262 return(NULL);
5263 }
5264 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005265#ifdef XP_DEBUG_OBJ_USAGE
5266 xmlXPathDebugObjUsageRequested(NULL, val->type);
5267#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005268 switch (val->type) {
5269 case XPATH_BOOLEAN:
5270 case XPATH_NUMBER:
5271 case XPATH_POINT:
5272 case XPATH_RANGE:
5273 break;
5274 case XPATH_STRING:
5275 ret->stringval = xmlStrdup(val->stringval);
5276 break;
5277 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005278#if 0
5279/*
5280 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5281 this previous handling is no longer correct, and can cause some serious
5282 problems (ref. bug 145547)
5283*/
Owen Taylor3473f882001-02-23 17:55:21 +00005284 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005285 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005286 xmlNodePtr cur, tmp;
5287 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005288
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005289 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005290 top = xmlNewDoc(NULL);
5291 top->name = (char *)
5292 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005293 ret->user = top;
5294 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005295 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005296 cur = val->nodesetval->nodeTab[0]->children;
5297 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005298 tmp = xmlDocCopyNode(cur, top, 1);
5299 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005300 cur = cur->next;
5301 }
5302 }
William M. Bracke9449c52004-07-11 14:41:20 +00005303
Daniel Veillard9adc0462003-03-24 18:39:54 +00005304 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005305 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005306 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005307 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005308 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005309#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005310 case XPATH_NODESET:
5311 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005312 /* Do not deallocate the copied tree value */
5313 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005314 break;
5315 case XPATH_LOCATIONSET:
5316#ifdef LIBXML_XPTR_ENABLED
5317 {
5318 xmlLocationSetPtr loc = val->user;
5319 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5320 break;
5321 }
5322#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005323 case XPATH_USERS:
5324 ret->user = val->user;
5325 break;
5326 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005327 xmlGenericError(xmlGenericErrorContext,
5328 "xmlXPathObjectCopy: unsupported type %d\n",
5329 val->type);
5330 break;
5331 }
5332 return(ret);
5333}
5334
5335/**
5336 * xmlXPathFreeObject:
5337 * @obj: the object to free
5338 *
5339 * Free up an xmlXPathObjectPtr object.
5340 */
5341void
5342xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5343 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005344 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005345 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005346#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005347 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005348 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005349 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005350 } else
5351#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005352 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005353 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005354 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005355 } else {
5356 if (obj->nodesetval != NULL)
5357 xmlXPathFreeNodeSet(obj->nodesetval);
5358 }
Owen Taylor3473f882001-02-23 17:55:21 +00005359#ifdef LIBXML_XPTR_ENABLED
5360 } else if (obj->type == XPATH_LOCATIONSET) {
5361 if (obj->user != NULL)
5362 xmlXPtrFreeLocationSet(obj->user);
5363#endif
5364 } else if (obj->type == XPATH_STRING) {
5365 if (obj->stringval != NULL)
5366 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005367 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005368#ifdef XP_DEBUG_OBJ_USAGE
5369 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5370#endif
5371 xmlFree(obj);
5372}
Owen Taylor3473f882001-02-23 17:55:21 +00005373
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005374/**
5375 * xmlXPathReleaseObject:
5376 * @obj: the xmlXPathObjectPtr to free or to cache
5377 *
5378 * Depending on the state of the cache this frees the given
5379 * XPath object or stores it in the cache.
5380 */
5381static void
5382xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5383{
5384#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5385 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5386 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5387
5388#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5389
5390 if (obj == NULL)
5391 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005392 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005393 xmlXPathFreeObject(obj);
5394 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005395 xmlXPathContextCachePtr cache =
5396 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005397
5398 switch (obj->type) {
5399 case XPATH_NODESET:
5400 case XPATH_XSLT_TREE:
5401 if (obj->nodesetval != NULL) {
5402 if (obj->boolval) {
5403 /*
5404 * It looks like the @boolval is used for
5405 * evaluation if this an XSLT Result Tree Fragment.
5406 * TODO: Check if this assumption is correct.
5407 */
5408 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5409 xmlXPathFreeValueTree(obj->nodesetval);
5410 obj->nodesetval = NULL;
5411 } else if ((obj->nodesetval->nodeMax <= 40) &&
5412 (XP_CACHE_WANTS(cache->nodesetObjs,
5413 cache->maxNodeset)))
5414 {
5415 XP_CACHE_ADD(cache->nodesetObjs, obj);
5416 goto obj_cached;
5417 } else {
5418 xmlXPathFreeNodeSet(obj->nodesetval);
5419 obj->nodesetval = NULL;
5420 }
5421 }
5422 break;
5423 case XPATH_STRING:
5424 if (obj->stringval != NULL)
5425 xmlFree(obj->stringval);
5426
5427 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5428 XP_CACHE_ADD(cache->stringObjs, obj);
5429 goto obj_cached;
5430 }
5431 break;
5432 case XPATH_BOOLEAN:
5433 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5434 XP_CACHE_ADD(cache->booleanObjs, obj);
5435 goto obj_cached;
5436 }
5437 break;
5438 case XPATH_NUMBER:
5439 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5440 XP_CACHE_ADD(cache->numberObjs, obj);
5441 goto obj_cached;
5442 }
5443 break;
5444#ifdef LIBXML_XPTR_ENABLED
5445 case XPATH_LOCATIONSET:
5446 if (obj->user != NULL) {
5447 xmlXPtrFreeLocationSet(obj->user);
5448 }
5449 goto free_obj;
5450#endif
5451 default:
5452 goto free_obj;
5453 }
5454
5455 /*
5456 * Fallback to adding to the misc-objects slot.
5457 */
5458 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5459 XP_CACHE_ADD(cache->miscObjs, obj);
5460 } else
5461 goto free_obj;
5462
5463obj_cached:
5464
5465#ifdef XP_DEBUG_OBJ_USAGE
5466 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5467#endif
5468
5469 if (obj->nodesetval != NULL) {
5470 xmlNodeSetPtr tmpset = obj->nodesetval;
5471
5472 /*
5473 * TODO: Due to those nasty ns-nodes, we need to traverse
5474 * the list and free the ns-nodes.
5475 * URGENT TODO: Check if it's actually slowing things down.
5476 * Maybe we shouldn't try to preserve the list.
5477 */
5478 if (tmpset->nodeNr > 1) {
5479 int i;
5480 xmlNodePtr node;
5481
5482 for (i = 0; i < tmpset->nodeNr; i++) {
5483 node = tmpset->nodeTab[i];
5484 if ((node != NULL) &&
5485 (node->type == XML_NAMESPACE_DECL))
5486 {
5487 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5488 }
5489 }
5490 } else if (tmpset->nodeNr == 1) {
5491 if ((tmpset->nodeTab[0] != NULL) &&
5492 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5493 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5494 }
5495 tmpset->nodeNr = 0;
5496 memset(obj, 0, sizeof(xmlXPathObject));
5497 obj->nodesetval = tmpset;
5498 } else
5499 memset(obj, 0, sizeof(xmlXPathObject));
5500
5501 return;
5502
5503free_obj:
5504 /*
5505 * Cache is full; free the object.
5506 */
5507 if (obj->nodesetval != NULL)
5508 xmlXPathFreeNodeSet(obj->nodesetval);
5509#ifdef XP_DEBUG_OBJ_USAGE
5510 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5511#endif
5512 xmlFree(obj);
5513 }
5514 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005515}
5516
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005517
5518/************************************************************************
5519 * *
5520 * Type Casting Routines *
5521 * *
5522 ************************************************************************/
5523
5524/**
5525 * xmlXPathCastBooleanToString:
5526 * @val: a boolean
5527 *
5528 * Converts a boolean to its string value.
5529 *
5530 * Returns a newly allocated string.
5531 */
5532xmlChar *
5533xmlXPathCastBooleanToString (int val) {
5534 xmlChar *ret;
5535 if (val)
5536 ret = xmlStrdup((const xmlChar *) "true");
5537 else
5538 ret = xmlStrdup((const xmlChar *) "false");
5539 return(ret);
5540}
5541
5542/**
5543 * xmlXPathCastNumberToString:
5544 * @val: a number
5545 *
5546 * Converts a number to its string value.
5547 *
5548 * Returns a newly allocated string.
5549 */
5550xmlChar *
5551xmlXPathCastNumberToString (double val) {
5552 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005553 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005554 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005555 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005556 break;
5557 case -1:
5558 ret = xmlStrdup((const xmlChar *) "-Infinity");
5559 break;
5560 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005561 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005562 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005563 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5564 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005565 } else {
5566 /* could be improved */
5567 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005568 xmlXPathFormatNumber(val, buf, 99);
5569 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005570 ret = xmlStrdup((const xmlChar *) buf);
5571 }
5572 }
5573 return(ret);
5574}
5575
5576/**
5577 * xmlXPathCastNodeToString:
5578 * @node: a node
5579 *
5580 * Converts a node to its string value.
5581 *
5582 * Returns a newly allocated string.
5583 */
5584xmlChar *
5585xmlXPathCastNodeToString (xmlNodePtr node) {
5586 return(xmlNodeGetContent(node));
5587}
5588
5589/**
5590 * xmlXPathCastNodeSetToString:
5591 * @ns: a node-set
5592 *
5593 * Converts a node-set to its string value.
5594 *
5595 * Returns a newly allocated string.
5596 */
5597xmlChar *
5598xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5599 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5600 return(xmlStrdup((const xmlChar *) ""));
5601
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005602 if (ns->nodeNr > 1)
5603 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005604 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5605}
5606
5607/**
5608 * xmlXPathCastToString:
5609 * @val: an XPath object
5610 *
5611 * Converts an existing object to its string() equivalent
5612 *
Kasimier T. Buchcik50128ad2006-08-15 13:04:07 +00005613 * Returns the allocated string value of the object, NULL in case of error.
5614 * It's up to the caller to free the string memory with xmlFree().
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005615 */
5616xmlChar *
5617xmlXPathCastToString(xmlXPathObjectPtr val) {
5618 xmlChar *ret = NULL;
5619
5620 if (val == NULL)
5621 return(xmlStrdup((const xmlChar *) ""));
5622 switch (val->type) {
5623 case XPATH_UNDEFINED:
5624#ifdef DEBUG_EXPR
5625 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5626#endif
5627 ret = xmlStrdup((const xmlChar *) "");
5628 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005629 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005630 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005631 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5632 break;
5633 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005634 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005635 case XPATH_BOOLEAN:
5636 ret = xmlXPathCastBooleanToString(val->boolval);
5637 break;
5638 case XPATH_NUMBER: {
5639 ret = xmlXPathCastNumberToString(val->floatval);
5640 break;
5641 }
5642 case XPATH_USERS:
5643 case XPATH_POINT:
5644 case XPATH_RANGE:
5645 case XPATH_LOCATIONSET:
5646 TODO
5647 ret = xmlStrdup((const xmlChar *) "");
5648 break;
5649 }
5650 return(ret);
5651}
5652
5653/**
5654 * xmlXPathConvertString:
5655 * @val: an XPath object
5656 *
5657 * Converts an existing object to its string() equivalent
5658 *
5659 * Returns the new object, the old one is freed (or the operation
5660 * is done directly on @val)
5661 */
5662xmlXPathObjectPtr
5663xmlXPathConvertString(xmlXPathObjectPtr val) {
5664 xmlChar *res = NULL;
5665
5666 if (val == NULL)
5667 return(xmlXPathNewCString(""));
5668
5669 switch (val->type) {
5670 case XPATH_UNDEFINED:
5671#ifdef DEBUG_EXPR
5672 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5673#endif
5674 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005675 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005676 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005677 res = xmlXPathCastNodeSetToString(val->nodesetval);
5678 break;
5679 case XPATH_STRING:
5680 return(val);
5681 case XPATH_BOOLEAN:
5682 res = xmlXPathCastBooleanToString(val->boolval);
5683 break;
5684 case XPATH_NUMBER:
5685 res = xmlXPathCastNumberToString(val->floatval);
5686 break;
5687 case XPATH_USERS:
5688 case XPATH_POINT:
5689 case XPATH_RANGE:
5690 case XPATH_LOCATIONSET:
5691 TODO;
5692 break;
5693 }
5694 xmlXPathFreeObject(val);
5695 if (res == NULL)
5696 return(xmlXPathNewCString(""));
5697 return(xmlXPathWrapString(res));
5698}
5699
5700/**
5701 * xmlXPathCastBooleanToNumber:
5702 * @val: a boolean
5703 *
5704 * Converts a boolean to its number value
5705 *
5706 * Returns the number value
5707 */
5708double
5709xmlXPathCastBooleanToNumber(int val) {
5710 if (val)
5711 return(1.0);
5712 return(0.0);
5713}
5714
5715/**
5716 * xmlXPathCastStringToNumber:
5717 * @val: a string
5718 *
5719 * Converts a string to its number value
5720 *
5721 * Returns the number value
5722 */
5723double
5724xmlXPathCastStringToNumber(const xmlChar * val) {
5725 return(xmlXPathStringEvalNumber(val));
5726}
5727
5728/**
5729 * xmlXPathCastNodeToNumber:
5730 * @node: a node
5731 *
5732 * Converts a node to its number value
5733 *
5734 * Returns the number value
5735 */
5736double
5737xmlXPathCastNodeToNumber (xmlNodePtr node) {
5738 xmlChar *strval;
5739 double ret;
5740
5741 if (node == NULL)
5742 return(xmlXPathNAN);
5743 strval = xmlXPathCastNodeToString(node);
5744 if (strval == NULL)
5745 return(xmlXPathNAN);
5746 ret = xmlXPathCastStringToNumber(strval);
5747 xmlFree(strval);
5748
5749 return(ret);
5750}
5751
5752/**
5753 * xmlXPathCastNodeSetToNumber:
5754 * @ns: a node-set
5755 *
5756 * Converts a node-set to its number value
5757 *
5758 * Returns the number value
5759 */
5760double
5761xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5762 xmlChar *str;
5763 double ret;
5764
5765 if (ns == NULL)
5766 return(xmlXPathNAN);
5767 str = xmlXPathCastNodeSetToString(ns);
5768 ret = xmlXPathCastStringToNumber(str);
5769 xmlFree(str);
5770 return(ret);
5771}
5772
5773/**
5774 * xmlXPathCastToNumber:
5775 * @val: an XPath object
5776 *
5777 * Converts an XPath object to its number value
5778 *
5779 * Returns the number value
5780 */
5781double
5782xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5783 double ret = 0.0;
5784
5785 if (val == NULL)
5786 return(xmlXPathNAN);
5787 switch (val->type) {
5788 case XPATH_UNDEFINED:
5789#ifdef DEGUB_EXPR
5790 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5791#endif
5792 ret = xmlXPathNAN;
5793 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005794 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005795 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005796 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5797 break;
5798 case XPATH_STRING:
5799 ret = xmlXPathCastStringToNumber(val->stringval);
5800 break;
5801 case XPATH_NUMBER:
5802 ret = val->floatval;
5803 break;
5804 case XPATH_BOOLEAN:
5805 ret = xmlXPathCastBooleanToNumber(val->boolval);
5806 break;
5807 case XPATH_USERS:
5808 case XPATH_POINT:
5809 case XPATH_RANGE:
5810 case XPATH_LOCATIONSET:
5811 TODO;
5812 ret = xmlXPathNAN;
5813 break;
5814 }
5815 return(ret);
5816}
5817
5818/**
5819 * xmlXPathConvertNumber:
5820 * @val: an XPath object
5821 *
5822 * Converts an existing object to its number() equivalent
5823 *
5824 * Returns the new object, the old one is freed (or the operation
5825 * is done directly on @val)
5826 */
5827xmlXPathObjectPtr
5828xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5829 xmlXPathObjectPtr ret;
5830
5831 if (val == NULL)
5832 return(xmlXPathNewFloat(0.0));
5833 if (val->type == XPATH_NUMBER)
5834 return(val);
5835 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5836 xmlXPathFreeObject(val);
5837 return(ret);
5838}
5839
5840/**
5841 * xmlXPathCastNumberToBoolean:
5842 * @val: a number
5843 *
5844 * Converts a number to its boolean value
5845 *
5846 * Returns the boolean value
5847 */
5848int
5849xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005850 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005851 return(0);
5852 return(1);
5853}
5854
5855/**
5856 * xmlXPathCastStringToBoolean:
5857 * @val: a string
5858 *
5859 * Converts a string to its boolean value
5860 *
5861 * Returns the boolean value
5862 */
5863int
5864xmlXPathCastStringToBoolean (const xmlChar *val) {
5865 if ((val == NULL) || (xmlStrlen(val) == 0))
5866 return(0);
5867 return(1);
5868}
5869
5870/**
5871 * xmlXPathCastNodeSetToBoolean:
5872 * @ns: a node-set
5873 *
5874 * Converts a node-set to its boolean value
5875 *
5876 * Returns the boolean value
5877 */
5878int
5879xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5880 if ((ns == NULL) || (ns->nodeNr == 0))
5881 return(0);
5882 return(1);
5883}
5884
5885/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005886 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005887 * @val: an XPath object
5888 *
5889 * Converts an XPath object to its boolean value
5890 *
5891 * Returns the boolean value
5892 */
5893int
5894xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5895 int ret = 0;
5896
5897 if (val == NULL)
5898 return(0);
5899 switch (val->type) {
5900 case XPATH_UNDEFINED:
5901#ifdef DEBUG_EXPR
5902 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5903#endif
5904 ret = 0;
5905 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005906 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005907 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005908 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5909 break;
5910 case XPATH_STRING:
5911 ret = xmlXPathCastStringToBoolean(val->stringval);
5912 break;
5913 case XPATH_NUMBER:
5914 ret = xmlXPathCastNumberToBoolean(val->floatval);
5915 break;
5916 case XPATH_BOOLEAN:
5917 ret = val->boolval;
5918 break;
5919 case XPATH_USERS:
5920 case XPATH_POINT:
5921 case XPATH_RANGE:
5922 case XPATH_LOCATIONSET:
5923 TODO;
5924 ret = 0;
5925 break;
5926 }
5927 return(ret);
5928}
5929
5930
5931/**
5932 * xmlXPathConvertBoolean:
5933 * @val: an XPath object
5934 *
5935 * Converts an existing object to its boolean() equivalent
5936 *
5937 * Returns the new object, the old one is freed (or the operation
5938 * is done directly on @val)
5939 */
5940xmlXPathObjectPtr
5941xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5942 xmlXPathObjectPtr ret;
5943
5944 if (val == NULL)
5945 return(xmlXPathNewBoolean(0));
5946 if (val->type == XPATH_BOOLEAN)
5947 return(val);
5948 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5949 xmlXPathFreeObject(val);
5950 return(ret);
5951}
5952
Owen Taylor3473f882001-02-23 17:55:21 +00005953/************************************************************************
5954 * *
5955 * Routines to handle XPath contexts *
5956 * *
5957 ************************************************************************/
5958
5959/**
5960 * xmlXPathNewContext:
5961 * @doc: the XML document
5962 *
5963 * Create a new xmlXPathContext
5964 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005965 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005966 */
5967xmlXPathContextPtr
5968xmlXPathNewContext(xmlDocPtr doc) {
5969 xmlXPathContextPtr ret;
5970
5971 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5972 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005973 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005974 return(NULL);
5975 }
5976 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5977 ret->doc = doc;
5978 ret->node = NULL;
5979
5980 ret->varHash = NULL;
5981
5982 ret->nb_types = 0;
5983 ret->max_types = 0;
5984 ret->types = NULL;
5985
5986 ret->funcHash = xmlHashCreate(0);
5987
5988 ret->nb_axis = 0;
5989 ret->max_axis = 0;
5990 ret->axis = NULL;
5991
5992 ret->nsHash = NULL;
5993 ret->user = NULL;
5994
5995 ret->contextSize = -1;
5996 ret->proximityPosition = -1;
5997
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005998#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005999 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006000 xmlXPathFreeContext(ret);
6001 return(NULL);
6002 }
6003#endif
6004
6005 xmlXPathRegisterAllFunctions(ret);
6006
Owen Taylor3473f882001-02-23 17:55:21 +00006007 return(ret);
6008}
6009
6010/**
6011 * xmlXPathFreeContext:
6012 * @ctxt: the context to free
6013 *
6014 * Free up an xmlXPathContext
6015 */
6016void
6017xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006018 if (ctxt == NULL) return;
6019
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00006020 if (ctxt->cache != NULL)
6021 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00006022 xmlXPathRegisteredNsCleanup(ctxt);
6023 xmlXPathRegisteredFuncsCleanup(ctxt);
6024 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00006025 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00006026 xmlFree(ctxt);
6027}
6028
6029/************************************************************************
6030 * *
6031 * Routines to handle XPath parser contexts *
6032 * *
6033 ************************************************************************/
6034
6035#define CHECK_CTXT(ctxt) \
6036 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00006037 __xmlRaiseError(NULL, NULL, NULL, \
6038 NULL, NULL, XML_FROM_XPATH, \
6039 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6040 __FILE__, __LINE__, \
6041 NULL, NULL, NULL, 0, 0, \
6042 "NULL context pointer\n"); \
6043 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00006044 } \
6045
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +00006046#define CHECK_CTXT_NEG(ctxt) \
6047 if (ctxt == NULL) { \
6048 __xmlRaiseError(NULL, NULL, NULL, \
6049 NULL, NULL, XML_FROM_XPATH, \
6050 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6051 __FILE__, __LINE__, \
6052 NULL, NULL, NULL, 0, 0, \
6053 "NULL context pointer\n"); \
6054 return(-1); \
6055 } \
6056
Owen Taylor3473f882001-02-23 17:55:21 +00006057
6058#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00006059 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6060 (ctxt->doc->children == NULL)) { \
6061 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00006062 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00006063 }
Owen Taylor3473f882001-02-23 17:55:21 +00006064
6065
6066/**
6067 * xmlXPathNewParserContext:
6068 * @str: the XPath expression
6069 * @ctxt: the XPath context
6070 *
6071 * Create a new xmlXPathParserContext
6072 *
6073 * Returns the xmlXPathParserContext just allocated.
6074 */
6075xmlXPathParserContextPtr
6076xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6077 xmlXPathParserContextPtr ret;
6078
6079 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6080 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006081 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006082 return(NULL);
6083 }
6084 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6085 ret->cur = ret->base = str;
6086 ret->context = ctxt;
6087
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006088 ret->comp = xmlXPathNewCompExpr();
6089 if (ret->comp == NULL) {
6090 xmlFree(ret->valueTab);
6091 xmlFree(ret);
6092 return(NULL);
6093 }
Daniel Veillard4773df22004-01-23 13:15:13 +00006094 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6095 ret->comp->dict = ctxt->dict;
6096 xmlDictReference(ret->comp->dict);
6097 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006098
6099 return(ret);
6100}
6101
6102/**
6103 * xmlXPathCompParserContext:
6104 * @comp: the XPath compiled expression
6105 * @ctxt: the XPath context
6106 *
6107 * Create a new xmlXPathParserContext when processing a compiled expression
6108 *
6109 * Returns the xmlXPathParserContext just allocated.
6110 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006111static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006112xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6113 xmlXPathParserContextPtr ret;
6114
6115 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6116 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006117 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006118 return(NULL);
6119 }
6120 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6121
Owen Taylor3473f882001-02-23 17:55:21 +00006122 /* Allocate the value stack */
6123 ret->valueTab = (xmlXPathObjectPtr *)
6124 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006125 if (ret->valueTab == NULL) {
6126 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006127 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006128 return(NULL);
6129 }
Owen Taylor3473f882001-02-23 17:55:21 +00006130 ret->valueNr = 0;
6131 ret->valueMax = 10;
6132 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006133
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006134 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006135 ret->comp = comp;
6136
Owen Taylor3473f882001-02-23 17:55:21 +00006137 return(ret);
6138}
6139
6140/**
6141 * xmlXPathFreeParserContext:
6142 * @ctxt: the context to free
6143 *
6144 * Free up an xmlXPathParserContext
6145 */
6146void
6147xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6148 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006149 xmlFree(ctxt->valueTab);
6150 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00006151 if (ctxt->comp != NULL) {
6152#ifdef XPATH_STREAMING
6153 if (ctxt->comp->stream != NULL) {
6154 xmlFreePatternList(ctxt->comp->stream);
6155 ctxt->comp->stream = NULL;
6156 }
6157#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006158 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00006159 }
Owen Taylor3473f882001-02-23 17:55:21 +00006160 xmlFree(ctxt);
6161}
6162
6163/************************************************************************
6164 * *
6165 * The implicit core function library *
6166 * *
6167 ************************************************************************/
6168
Owen Taylor3473f882001-02-23 17:55:21 +00006169/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006170 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00006171 * @node: a node pointer
6172 *
6173 * Function computing the beginning of the string value of the node,
6174 * used to speed up comparisons
6175 *
6176 * Returns an int usable as a hash
6177 */
6178static unsigned int
6179xmlXPathNodeValHash(xmlNodePtr node) {
6180 int len = 2;
6181 const xmlChar * string = NULL;
6182 xmlNodePtr tmp = NULL;
6183 unsigned int ret = 0;
6184
6185 if (node == NULL)
6186 return(0);
6187
Daniel Veillard9adc0462003-03-24 18:39:54 +00006188 if (node->type == XML_DOCUMENT_NODE) {
6189 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6190 if (tmp == NULL)
6191 node = node->children;
6192 else
6193 node = tmp;
6194
6195 if (node == NULL)
6196 return(0);
6197 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006198
6199 switch (node->type) {
6200 case XML_COMMENT_NODE:
6201 case XML_PI_NODE:
6202 case XML_CDATA_SECTION_NODE:
6203 case XML_TEXT_NODE:
6204 string = node->content;
6205 if (string == NULL)
6206 return(0);
6207 if (string[0] == 0)
6208 return(0);
6209 return(((unsigned int) string[0]) +
6210 (((unsigned int) string[1]) << 8));
6211 case XML_NAMESPACE_DECL:
6212 string = ((xmlNsPtr)node)->href;
6213 if (string == NULL)
6214 return(0);
6215 if (string[0] == 0)
6216 return(0);
6217 return(((unsigned int) string[0]) +
6218 (((unsigned int) string[1]) << 8));
6219 case XML_ATTRIBUTE_NODE:
6220 tmp = ((xmlAttrPtr) node)->children;
6221 break;
6222 case XML_ELEMENT_NODE:
6223 tmp = node->children;
6224 break;
6225 default:
6226 return(0);
6227 }
6228 while (tmp != NULL) {
6229 switch (tmp->type) {
6230 case XML_COMMENT_NODE:
6231 case XML_PI_NODE:
6232 case XML_CDATA_SECTION_NODE:
6233 case XML_TEXT_NODE:
6234 string = tmp->content;
6235 break;
6236 case XML_NAMESPACE_DECL:
6237 string = ((xmlNsPtr)tmp)->href;
6238 break;
6239 default:
6240 break;
6241 }
6242 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006243 if (len == 1) {
6244 return(ret + (((unsigned int) string[0]) << 8));
6245 }
6246 if (string[1] == 0) {
6247 len = 1;
6248 ret = (unsigned int) string[0];
6249 } else {
6250 return(((unsigned int) string[0]) +
6251 (((unsigned int) string[1]) << 8));
6252 }
6253 }
6254 /*
6255 * Skip to next node
6256 */
6257 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6258 if (tmp->children->type != XML_ENTITY_DECL) {
6259 tmp = tmp->children;
6260 continue;
6261 }
6262 }
6263 if (tmp == node)
6264 break;
6265
6266 if (tmp->next != NULL) {
6267 tmp = tmp->next;
6268 continue;
6269 }
6270
6271 do {
6272 tmp = tmp->parent;
6273 if (tmp == NULL)
6274 break;
6275 if (tmp == node) {
6276 tmp = NULL;
6277 break;
6278 }
6279 if (tmp->next != NULL) {
6280 tmp = tmp->next;
6281 break;
6282 }
6283 } while (tmp != NULL);
6284 }
6285 return(ret);
6286}
6287
6288/**
6289 * xmlXPathStringHash:
6290 * @string: a string
6291 *
6292 * Function computing the beginning of the string value of the node,
6293 * used to speed up comparisons
6294 *
6295 * Returns an int usable as a hash
6296 */
6297static unsigned int
6298xmlXPathStringHash(const xmlChar * string) {
6299 if (string == NULL)
6300 return((unsigned int) 0);
6301 if (string[0] == 0)
6302 return(0);
6303 return(((unsigned int) string[0]) +
6304 (((unsigned int) string[1]) << 8));
6305}
6306
6307/**
Owen Taylor3473f882001-02-23 17:55:21 +00006308 * xmlXPathCompareNodeSetFloat:
6309 * @ctxt: the XPath Parser context
6310 * @inf: less than (1) or greater than (0)
6311 * @strict: is the comparison strict
6312 * @arg: the node set
6313 * @f: the value
6314 *
6315 * Implement the compare operation between a nodeset and a number
6316 * @ns < @val (1, 1, ...
6317 * @ns <= @val (1, 0, ...
6318 * @ns > @val (0, 1, ...
6319 * @ns >= @val (0, 0, ...
6320 *
6321 * If one object to be compared is a node-set and the other is a number,
6322 * then the comparison will be true if and only if there is a node in the
6323 * node-set such that the result of performing the comparison on the number
6324 * to be compared and on the result of converting the string-value of that
6325 * node to a number using the number function is true.
6326 *
6327 * Returns 0 or 1 depending on the results of the test.
6328 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006329static int
Owen Taylor3473f882001-02-23 17:55:21 +00006330xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6331 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6332 int i, ret = 0;
6333 xmlNodeSetPtr ns;
6334 xmlChar *str2;
6335
6336 if ((f == NULL) || (arg == NULL) ||
6337 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006338 xmlXPathReleaseObject(ctxt->context, arg);
6339 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006340 return(0);
6341 }
6342 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006343 if (ns != NULL) {
6344 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006345 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006346 if (str2 != NULL) {
6347 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006348 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006349 xmlFree(str2);
6350 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006351 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006352 ret = xmlXPathCompareValues(ctxt, inf, strict);
6353 if (ret)
6354 break;
6355 }
6356 }
Owen Taylor3473f882001-02-23 17:55:21 +00006357 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006358 xmlXPathReleaseObject(ctxt->context, arg);
6359 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006360 return(ret);
6361}
6362
6363/**
6364 * xmlXPathCompareNodeSetString:
6365 * @ctxt: the XPath Parser context
6366 * @inf: less than (1) or greater than (0)
6367 * @strict: is the comparison strict
6368 * @arg: the node set
6369 * @s: the value
6370 *
6371 * Implement the compare operation between a nodeset and a string
6372 * @ns < @val (1, 1, ...
6373 * @ns <= @val (1, 0, ...
6374 * @ns > @val (0, 1, ...
6375 * @ns >= @val (0, 0, ...
6376 *
6377 * If one object to be compared is a node-set and the other is a string,
6378 * then the comparison will be true if and only if there is a node in
6379 * the node-set such that the result of performing the comparison on the
6380 * string-value of the node and the other string is true.
6381 *
6382 * Returns 0 or 1 depending on the results of the test.
6383 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006384static int
Owen Taylor3473f882001-02-23 17:55:21 +00006385xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6386 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6387 int i, ret = 0;
6388 xmlNodeSetPtr ns;
6389 xmlChar *str2;
6390
6391 if ((s == NULL) || (arg == NULL) ||
6392 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006393 xmlXPathReleaseObject(ctxt->context, arg);
6394 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006395 return(0);
6396 }
6397 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006398 if (ns != NULL) {
6399 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006400 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006401 if (str2 != NULL) {
6402 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006403 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006404 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006405 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006406 ret = xmlXPathCompareValues(ctxt, inf, strict);
6407 if (ret)
6408 break;
6409 }
6410 }
Owen Taylor3473f882001-02-23 17:55:21 +00006411 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006412 xmlXPathReleaseObject(ctxt->context, arg);
6413 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006414 return(ret);
6415}
6416
6417/**
6418 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006419 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006420 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006421 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006422 * @arg2: the second node set object
6423 *
6424 * Implement the compare operation on nodesets:
6425 *
6426 * If both objects to be compared are node-sets, then the comparison
6427 * will be true if and only if there is a node in the first node-set
6428 * and a node in the second node-set such that the result of performing
6429 * the comparison on the string-values of the two nodes is true.
6430 * ....
6431 * When neither object to be compared is a node-set and the operator
6432 * is <=, <, >= or >, then the objects are compared by converting both
6433 * objects to numbers and comparing the numbers according to IEEE 754.
6434 * ....
6435 * The number function converts its argument to a number as follows:
6436 * - a string that consists of optional whitespace followed by an
6437 * optional minus sign followed by a Number followed by whitespace
6438 * is converted to the IEEE 754 number that is nearest (according
6439 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6440 * represented by the string; any other string is converted to NaN
6441 *
6442 * Conclusion all nodes need to be converted first to their string value
6443 * and then the comparison must be done when possible
6444 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006445static int
6446xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006447 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6448 int i, j, init = 0;
6449 double val1;
6450 double *values2;
6451 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006452 xmlNodeSetPtr ns1;
6453 xmlNodeSetPtr ns2;
6454
6455 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006456 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6457 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006458 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006459 }
Owen Taylor3473f882001-02-23 17:55:21 +00006460 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006461 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6462 xmlXPathFreeObject(arg1);
6463 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006464 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006465 }
Owen Taylor3473f882001-02-23 17:55:21 +00006466
6467 ns1 = arg1->nodesetval;
6468 ns2 = arg2->nodesetval;
6469
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006470 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006471 xmlXPathFreeObject(arg1);
6472 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006473 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006474 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006475 if ((ns2 == NULL) || (ns2->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 }
Owen Taylor3473f882001-02-23 17:55:21 +00006480
6481 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6482 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006483 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006484 xmlXPathFreeObject(arg1);
6485 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006486 return(0);
6487 }
6488 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006489 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006490 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006491 continue;
6492 for (j = 0;j < ns2->nodeNr;j++) {
6493 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006494 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006495 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006496 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006497 continue;
6498 if (inf && strict)
6499 ret = (val1 < values2[j]);
6500 else if (inf && !strict)
6501 ret = (val1 <= values2[j]);
6502 else if (!inf && strict)
6503 ret = (val1 > values2[j]);
6504 else if (!inf && !strict)
6505 ret = (val1 >= values2[j]);
6506 if (ret)
6507 break;
6508 }
6509 if (ret)
6510 break;
6511 init = 1;
6512 }
6513 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006514 xmlXPathFreeObject(arg1);
6515 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006516 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006517}
6518
6519/**
6520 * xmlXPathCompareNodeSetValue:
6521 * @ctxt: the XPath Parser context
6522 * @inf: less than (1) or greater than (0)
6523 * @strict: is the comparison strict
6524 * @arg: the node set
6525 * @val: the value
6526 *
6527 * Implement the compare operation between a nodeset and a value
6528 * @ns < @val (1, 1, ...
6529 * @ns <= @val (1, 0, ...
6530 * @ns > @val (0, 1, ...
6531 * @ns >= @val (0, 0, ...
6532 *
6533 * If one object to be compared is a node-set and the other is a boolean,
6534 * then the comparison will be true if and only if the result of performing
6535 * the comparison on the boolean and on the result of converting
6536 * the node-set to a boolean using the boolean function is true.
6537 *
6538 * Returns 0 or 1 depending on the results of the test.
6539 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006540static int
Owen Taylor3473f882001-02-23 17:55:21 +00006541xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6542 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6543 if ((val == NULL) || (arg == NULL) ||
6544 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6545 return(0);
6546
6547 switch(val->type) {
6548 case XPATH_NUMBER:
6549 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6550 case XPATH_NODESET:
6551 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006552 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006553 case XPATH_STRING:
6554 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6555 case XPATH_BOOLEAN:
6556 valuePush(ctxt, arg);
6557 xmlXPathBooleanFunction(ctxt, 1);
6558 valuePush(ctxt, val);
6559 return(xmlXPathCompareValues(ctxt, inf, strict));
6560 default:
6561 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006562 }
6563 return(0);
6564}
6565
6566/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006567 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006568 * @arg: the nodeset object argument
6569 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006570 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006571 *
6572 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6573 * If one object to be compared is a node-set and the other is a string,
6574 * then the comparison will be true if and only if there is a node in
6575 * the node-set such that the result of performing the comparison on the
6576 * string-value of the node and the other string is true.
6577 *
6578 * Returns 0 or 1 depending on the results of the test.
6579 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006580static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006581xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006582{
Owen Taylor3473f882001-02-23 17:55:21 +00006583 int i;
6584 xmlNodeSetPtr ns;
6585 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006586 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006587
6588 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006589 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6590 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006591 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006592 /*
6593 * A NULL nodeset compared with a string is always false
6594 * (since there is no node equal, and no node not equal)
6595 */
6596 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006597 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006598 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006599 for (i = 0; i < ns->nodeNr; i++) {
6600 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6601 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6602 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6603 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006604 if (neq)
6605 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006606 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006607 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6608 if (neq)
6609 continue;
6610 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006611 } else if (neq) {
6612 if (str2 != NULL)
6613 xmlFree(str2);
6614 return (1);
6615 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006616 if (str2 != NULL)
6617 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006618 } else if (neq)
6619 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006620 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006621 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006622}
6623
6624/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006625 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006626 * @arg: the nodeset object argument
6627 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006628 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006629 *
6630 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6631 * If one object to be compared is a node-set and the other is a number,
6632 * then the comparison will be true if and only if there is a node in
6633 * the node-set such that the result of performing the comparison on the
6634 * number to be compared and on the result of converting the string-value
6635 * of that node to a number using the number function is true.
6636 *
6637 * Returns 0 or 1 depending on the results of the test.
6638 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006639static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006640xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6641 xmlXPathObjectPtr arg, double f, int neq) {
6642 int i, ret=0;
6643 xmlNodeSetPtr ns;
6644 xmlChar *str2;
6645 xmlXPathObjectPtr val;
6646 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006647
6648 if ((arg == NULL) ||
6649 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6650 return(0);
6651
William M. Brack0c022ad2002-07-12 00:56:01 +00006652 ns = arg->nodesetval;
6653 if (ns != NULL) {
6654 for (i=0;i<ns->nodeNr;i++) {
6655 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6656 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006657 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006658 xmlFree(str2);
6659 xmlXPathNumberFunction(ctxt, 1);
6660 val = valuePop(ctxt);
6661 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006662 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006663 if (!xmlXPathIsNaN(v)) {
6664 if ((!neq) && (v==f)) {
6665 ret = 1;
6666 break;
6667 } else if ((neq) && (v!=f)) {
6668 ret = 1;
6669 break;
6670 }
William M. Brack32f0f712005-07-14 07:00:33 +00006671 } else { /* NaN is unequal to any value */
6672 if (neq)
6673 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006674 }
6675 }
6676 }
6677 }
6678
6679 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006680}
6681
6682
6683/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006684 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006685 * @arg1: first nodeset object argument
6686 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006687 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006688 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006689 * Implement the equal / not equal operation on XPath nodesets:
6690 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006691 * If both objects to be compared are node-sets, then the comparison
6692 * will be true if and only if there is a node in the first node-set and
6693 * a node in the second node-set such that the result of performing the
6694 * comparison on the string-values of the two nodes is true.
6695 *
6696 * (needless to say, this is a costly operation)
6697 *
6698 * Returns 0 or 1 depending on the results of the test.
6699 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006700static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006701xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006702 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006703 unsigned int *hashs1;
6704 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006705 xmlChar **values1;
6706 xmlChar **values2;
6707 int ret = 0;
6708 xmlNodeSetPtr ns1;
6709 xmlNodeSetPtr ns2;
6710
6711 if ((arg1 == NULL) ||
6712 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6713 return(0);
6714 if ((arg2 == NULL) ||
6715 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6716 return(0);
6717
6718 ns1 = arg1->nodesetval;
6719 ns2 = arg2->nodesetval;
6720
Daniel Veillard911f49a2001-04-07 15:39:35 +00006721 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006722 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006723 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006724 return(0);
6725
6726 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006727 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006728 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006729 if (neq == 0)
6730 for (i = 0;i < ns1->nodeNr;i++)
6731 for (j = 0;j < ns2->nodeNr;j++)
6732 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6733 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006734
6735 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006736 if (values1 == NULL) {
6737 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006738 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006739 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006740 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6741 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006742 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006743 xmlFree(values1);
6744 return(0);
6745 }
Owen Taylor3473f882001-02-23 17:55:21 +00006746 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6747 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6748 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006749 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006750 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006751 xmlFree(values1);
6752 return(0);
6753 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006754 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6755 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006756 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006757 xmlFree(hashs1);
6758 xmlFree(values1);
6759 xmlFree(values2);
6760 return(0);
6761 }
Owen Taylor3473f882001-02-23 17:55:21 +00006762 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6763 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006764 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006765 for (j = 0;j < ns2->nodeNr;j++) {
6766 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006767 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006768 if (hashs1[i] != hashs2[j]) {
6769 if (neq) {
6770 ret = 1;
6771 break;
6772 }
6773 }
6774 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006775 if (values1[i] == NULL)
6776 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6777 if (values2[j] == NULL)
6778 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006779 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006780 if (ret)
6781 break;
6782 }
Owen Taylor3473f882001-02-23 17:55:21 +00006783 }
6784 if (ret)
6785 break;
6786 }
6787 for (i = 0;i < ns1->nodeNr;i++)
6788 if (values1[i] != NULL)
6789 xmlFree(values1[i]);
6790 for (j = 0;j < ns2->nodeNr;j++)
6791 if (values2[j] != NULL)
6792 xmlFree(values2[j]);
6793 xmlFree(values1);
6794 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006795 xmlFree(hashs1);
6796 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006797 return(ret);
6798}
6799
William M. Brack0c022ad2002-07-12 00:56:01 +00006800static int
6801xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6802 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006803 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006804 /*
6805 *At this point we are assured neither arg1 nor arg2
6806 *is a nodeset, so we can just pick the appropriate routine.
6807 */
Owen Taylor3473f882001-02-23 17:55:21 +00006808 switch (arg1->type) {
6809 case XPATH_UNDEFINED:
6810#ifdef DEBUG_EXPR
6811 xmlGenericError(xmlGenericErrorContext,
6812 "Equal: undefined\n");
6813#endif
6814 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006815 case XPATH_BOOLEAN:
6816 switch (arg2->type) {
6817 case XPATH_UNDEFINED:
6818#ifdef DEBUG_EXPR
6819 xmlGenericError(xmlGenericErrorContext,
6820 "Equal: undefined\n");
6821#endif
6822 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006823 case XPATH_BOOLEAN:
6824#ifdef DEBUG_EXPR
6825 xmlGenericError(xmlGenericErrorContext,
6826 "Equal: %d boolean %d \n",
6827 arg1->boolval, arg2->boolval);
6828#endif
6829 ret = (arg1->boolval == arg2->boolval);
6830 break;
6831 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006832 ret = (arg1->boolval ==
6833 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006834 break;
6835 case XPATH_STRING:
6836 if ((arg2->stringval == NULL) ||
6837 (arg2->stringval[0] == 0)) ret = 0;
6838 else
6839 ret = 1;
6840 ret = (arg1->boolval == ret);
6841 break;
6842 case XPATH_USERS:
6843 case XPATH_POINT:
6844 case XPATH_RANGE:
6845 case XPATH_LOCATIONSET:
6846 TODO
6847 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006848 case XPATH_NODESET:
6849 case XPATH_XSLT_TREE:
6850 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006851 }
6852 break;
6853 case XPATH_NUMBER:
6854 switch (arg2->type) {
6855 case XPATH_UNDEFINED:
6856#ifdef DEBUG_EXPR
6857 xmlGenericError(xmlGenericErrorContext,
6858 "Equal: undefined\n");
6859#endif
6860 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006861 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006862 ret = (arg2->boolval==
6863 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006864 break;
6865 case XPATH_STRING:
6866 valuePush(ctxt, arg2);
6867 xmlXPathNumberFunction(ctxt, 1);
6868 arg2 = valuePop(ctxt);
6869 /* no break on purpose */
6870 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006871 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006872 if (xmlXPathIsNaN(arg1->floatval) ||
6873 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006874 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006875 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6876 if (xmlXPathIsInf(arg2->floatval) == 1)
6877 ret = 1;
6878 else
6879 ret = 0;
6880 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6881 if (xmlXPathIsInf(arg2->floatval) == -1)
6882 ret = 1;
6883 else
6884 ret = 0;
6885 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6886 if (xmlXPathIsInf(arg1->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;
Daniel Veillard21458c82002-03-27 16:12:22 +00006895 } else {
6896 ret = (arg1->floatval == arg2->floatval);
6897 }
Owen Taylor3473f882001-02-23 17:55:21 +00006898 break;
6899 case XPATH_USERS:
6900 case XPATH_POINT:
6901 case XPATH_RANGE:
6902 case XPATH_LOCATIONSET:
6903 TODO
6904 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006905 case XPATH_NODESET:
6906 case XPATH_XSLT_TREE:
6907 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006908 }
6909 break;
6910 case XPATH_STRING:
6911 switch (arg2->type) {
6912 case XPATH_UNDEFINED:
6913#ifdef DEBUG_EXPR
6914 xmlGenericError(xmlGenericErrorContext,
6915 "Equal: undefined\n");
6916#endif
6917 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006918 case XPATH_BOOLEAN:
6919 if ((arg1->stringval == NULL) ||
6920 (arg1->stringval[0] == 0)) ret = 0;
6921 else
6922 ret = 1;
6923 ret = (arg2->boolval == ret);
6924 break;
6925 case XPATH_STRING:
6926 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6927 break;
6928 case XPATH_NUMBER:
6929 valuePush(ctxt, arg1);
6930 xmlXPathNumberFunction(ctxt, 1);
6931 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006932 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006933 if (xmlXPathIsNaN(arg1->floatval) ||
6934 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006935 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006936 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6937 if (xmlXPathIsInf(arg2->floatval) == 1)
6938 ret = 1;
6939 else
6940 ret = 0;
6941 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6942 if (xmlXPathIsInf(arg2->floatval) == -1)
6943 ret = 1;
6944 else
6945 ret = 0;
6946 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6947 if (xmlXPathIsInf(arg1->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;
Daniel Veillard21458c82002-03-27 16:12:22 +00006956 } else {
6957 ret = (arg1->floatval == arg2->floatval);
6958 }
Owen Taylor3473f882001-02-23 17:55:21 +00006959 break;
6960 case XPATH_USERS:
6961 case XPATH_POINT:
6962 case XPATH_RANGE:
6963 case XPATH_LOCATIONSET:
6964 TODO
6965 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006966 case XPATH_NODESET:
6967 case XPATH_XSLT_TREE:
6968 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006969 }
6970 break;
6971 case XPATH_USERS:
6972 case XPATH_POINT:
6973 case XPATH_RANGE:
6974 case XPATH_LOCATIONSET:
6975 TODO
6976 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006977 case XPATH_NODESET:
6978 case XPATH_XSLT_TREE:
6979 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006980 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006981 xmlXPathReleaseObject(ctxt->context, arg1);
6982 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006983 return(ret);
6984}
6985
William M. Brack0c022ad2002-07-12 00:56:01 +00006986/**
6987 * xmlXPathEqualValues:
6988 * @ctxt: the XPath Parser context
6989 *
6990 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6991 *
6992 * Returns 0 or 1 depending on the results of the test.
6993 */
6994int
6995xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6996 xmlXPathObjectPtr arg1, arg2, argtmp;
6997 int ret = 0;
6998
Daniel Veillard6128c012004-11-08 17:16:15 +00006999 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007000 arg2 = valuePop(ctxt);
7001 arg1 = valuePop(ctxt);
7002 if ((arg1 == NULL) || (arg2 == NULL)) {
7003 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007004 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007005 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007006 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007007 XP_ERROR0(XPATH_INVALID_OPERAND);
7008 }
7009
7010 if (arg1 == arg2) {
7011#ifdef DEBUG_EXPR
7012 xmlGenericError(xmlGenericErrorContext,
7013 "Equal: by pointer\n");
7014#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00007015 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007016 return(1);
7017 }
7018
7019 /*
7020 *If either argument is a nodeset, it's a 'special case'
7021 */
7022 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7023 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7024 /*
7025 *Hack it to assure arg1 is the nodeset
7026 */
7027 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7028 argtmp = arg2;
7029 arg2 = arg1;
7030 arg1 = argtmp;
7031 }
7032 switch (arg2->type) {
7033 case XPATH_UNDEFINED:
7034#ifdef DEBUG_EXPR
7035 xmlGenericError(xmlGenericErrorContext,
7036 "Equal: undefined\n");
7037#endif
7038 break;
7039 case XPATH_NODESET:
7040 case XPATH_XSLT_TREE:
7041 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7042 break;
7043 case XPATH_BOOLEAN:
7044 if ((arg1->nodesetval == NULL) ||
7045 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7046 else
7047 ret = 1;
7048 ret = (ret == arg2->boolval);
7049 break;
7050 case XPATH_NUMBER:
7051 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7052 break;
7053 case XPATH_STRING:
7054 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7055 break;
7056 case XPATH_USERS:
7057 case XPATH_POINT:
7058 case XPATH_RANGE:
7059 case XPATH_LOCATIONSET:
7060 TODO
7061 break;
7062 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007063 xmlXPathReleaseObject(ctxt->context, arg1);
7064 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007065 return(ret);
7066 }
7067
7068 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7069}
7070
7071/**
7072 * xmlXPathNotEqualValues:
7073 * @ctxt: the XPath Parser context
7074 *
7075 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7076 *
7077 * Returns 0 or 1 depending on the results of the test.
7078 */
7079int
7080xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7081 xmlXPathObjectPtr arg1, arg2, argtmp;
7082 int ret = 0;
7083
Daniel Veillard6128c012004-11-08 17:16:15 +00007084 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007085 arg2 = valuePop(ctxt);
7086 arg1 = valuePop(ctxt);
7087 if ((arg1 == NULL) || (arg2 == NULL)) {
7088 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007089 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007090 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007091 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007092 XP_ERROR0(XPATH_INVALID_OPERAND);
7093 }
7094
7095 if (arg1 == arg2) {
7096#ifdef DEBUG_EXPR
7097 xmlGenericError(xmlGenericErrorContext,
7098 "NotEqual: by pointer\n");
7099#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007100 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007101 return(0);
7102 }
7103
7104 /*
7105 *If either argument is a nodeset, it's a 'special case'
7106 */
7107 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7108 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7109 /*
7110 *Hack it to assure arg1 is the nodeset
7111 */
7112 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7113 argtmp = arg2;
7114 arg2 = arg1;
7115 arg1 = argtmp;
7116 }
7117 switch (arg2->type) {
7118 case XPATH_UNDEFINED:
7119#ifdef DEBUG_EXPR
7120 xmlGenericError(xmlGenericErrorContext,
7121 "NotEqual: undefined\n");
7122#endif
7123 break;
7124 case XPATH_NODESET:
7125 case XPATH_XSLT_TREE:
7126 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7127 break;
7128 case XPATH_BOOLEAN:
7129 if ((arg1->nodesetval == NULL) ||
7130 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7131 else
7132 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00007133 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00007134 break;
7135 case XPATH_NUMBER:
7136 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7137 break;
7138 case XPATH_STRING:
7139 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7140 break;
7141 case XPATH_USERS:
7142 case XPATH_POINT:
7143 case XPATH_RANGE:
7144 case XPATH_LOCATIONSET:
7145 TODO
7146 break;
7147 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007148 xmlXPathReleaseObject(ctxt->context, arg1);
7149 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00007150 return(ret);
7151 }
7152
7153 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7154}
Owen Taylor3473f882001-02-23 17:55:21 +00007155
7156/**
7157 * xmlXPathCompareValues:
7158 * @ctxt: the XPath Parser context
7159 * @inf: less than (1) or greater than (0)
7160 * @strict: is the comparison strict
7161 *
7162 * Implement the compare operation on XPath objects:
7163 * @arg1 < @arg2 (1, 1, ...
7164 * @arg1 <= @arg2 (1, 0, ...
7165 * @arg1 > @arg2 (0, 1, ...
7166 * @arg1 >= @arg2 (0, 0, ...
7167 *
7168 * When neither object to be compared is a node-set and the operator is
7169 * <=, <, >=, >, then the objects are compared by converted both objects
7170 * to numbers and comparing the numbers according to IEEE 754. The <
7171 * comparison will be true if and only if the first number is less than the
7172 * second number. The <= comparison will be true if and only if the first
7173 * number is less than or equal to the second number. The > comparison
7174 * will be true if and only if the first number is greater than the second
7175 * number. The >= comparison will be true if and only if the first number
7176 * is greater than or equal to the second number.
7177 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007178 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00007179 */
7180int
7181xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007182 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007183 xmlXPathObjectPtr arg1, arg2;
7184
Daniel Veillard6128c012004-11-08 17:16:15 +00007185 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00007186 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007187 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00007188 if ((arg1 == NULL) || (arg2 == NULL)) {
7189 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007190 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00007191 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007192 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007193 XP_ERROR0(XPATH_INVALID_OPERAND);
7194 }
7195
William M. Brack0c022ad2002-07-12 00:56:01 +00007196 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7197 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00007198 /*
7199 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7200 * are not freed from within this routine; they will be freed from the
7201 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7202 */
William M. Brack0c022ad2002-07-12 00:56:01 +00007203 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7204 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007205 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007206 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00007207 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007208 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7209 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007210 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00007211 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7212 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00007213 }
7214 }
7215 return(ret);
7216 }
7217
7218 if (arg1->type != XPATH_NUMBER) {
7219 valuePush(ctxt, arg1);
7220 xmlXPathNumberFunction(ctxt, 1);
7221 arg1 = valuePop(ctxt);
7222 }
7223 if (arg1->type != XPATH_NUMBER) {
7224 xmlXPathFreeObject(arg1);
7225 xmlXPathFreeObject(arg2);
7226 XP_ERROR0(XPATH_INVALID_OPERAND);
7227 }
7228 if (arg2->type != XPATH_NUMBER) {
7229 valuePush(ctxt, arg2);
7230 xmlXPathNumberFunction(ctxt, 1);
7231 arg2 = valuePop(ctxt);
7232 }
7233 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007234 xmlXPathReleaseObject(ctxt->context, arg1);
7235 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007236 XP_ERROR0(XPATH_INVALID_OPERAND);
7237 }
7238 /*
7239 * Add tests for infinity and nan
7240 * => feedback on 3.4 for Inf and NaN
7241 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007242 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007243 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007244 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007245 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007246 arg1i=xmlXPathIsInf(arg1->floatval);
7247 arg2i=xmlXPathIsInf(arg2->floatval);
7248 if (inf && strict) {
7249 if ((arg1i == -1 && arg2i != -1) ||
7250 (arg2i == 1 && arg1i != 1)) {
7251 ret = 1;
7252 } else if (arg1i == 0 && arg2i == 0) {
7253 ret = (arg1->floatval < arg2->floatval);
7254 } else {
7255 ret = 0;
7256 }
7257 }
7258 else if (inf && !strict) {
7259 if (arg1i == -1 || arg2i == 1) {
7260 ret = 1;
7261 } else if (arg1i == 0 && arg2i == 0) {
7262 ret = (arg1->floatval <= arg2->floatval);
7263 } else {
7264 ret = 0;
7265 }
7266 }
7267 else if (!inf && strict) {
7268 if ((arg1i == 1 && arg2i != 1) ||
7269 (arg2i == -1 && arg1i != -1)) {
7270 ret = 1;
7271 } else if (arg1i == 0 && arg2i == 0) {
7272 ret = (arg1->floatval > arg2->floatval);
7273 } else {
7274 ret = 0;
7275 }
7276 }
7277 else if (!inf && !strict) {
7278 if (arg1i == 1 || arg2i == -1) {
7279 ret = 1;
7280 } else if (arg1i == 0 && arg2i == 0) {
7281 ret = (arg1->floatval >= arg2->floatval);
7282 } else {
7283 ret = 0;
7284 }
7285 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007286 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007287 xmlXPathReleaseObject(ctxt->context, arg1);
7288 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007289 return(ret);
7290}
7291
7292/**
7293 * xmlXPathValueFlipSign:
7294 * @ctxt: the XPath Parser context
7295 *
7296 * Implement the unary - operation on an XPath object
7297 * The numeric operators convert their operands to numbers as if
7298 * by calling the number function.
7299 */
7300void
7301xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007302 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007303 CAST_TO_NUMBER;
7304 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007305 if (xmlXPathIsNaN(ctxt->value->floatval))
7306 ctxt->value->floatval=xmlXPathNAN;
7307 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7308 ctxt->value->floatval=xmlXPathNINF;
7309 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7310 ctxt->value->floatval=xmlXPathPINF;
7311 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007312 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7313 ctxt->value->floatval = xmlXPathNZERO;
7314 else
7315 ctxt->value->floatval = 0;
7316 }
7317 else
7318 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007319}
7320
7321/**
7322 * xmlXPathAddValues:
7323 * @ctxt: the XPath Parser context
7324 *
7325 * Implement the add operation on XPath objects:
7326 * The numeric operators convert their operands to numbers as if
7327 * by calling the number function.
7328 */
7329void
7330xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7331 xmlXPathObjectPtr arg;
7332 double val;
7333
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007334 arg = valuePop(ctxt);
7335 if (arg == NULL)
7336 XP_ERROR(XPATH_INVALID_OPERAND);
7337 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007338 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007339 CAST_TO_NUMBER;
7340 CHECK_TYPE(XPATH_NUMBER);
7341 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007342}
7343
7344/**
7345 * xmlXPathSubValues:
7346 * @ctxt: the XPath Parser context
7347 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007348 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007349 * The numeric operators convert their operands to numbers as if
7350 * by calling the number function.
7351 */
7352void
7353xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7354 xmlXPathObjectPtr arg;
7355 double val;
7356
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007357 arg = valuePop(ctxt);
7358 if (arg == NULL)
7359 XP_ERROR(XPATH_INVALID_OPERAND);
7360 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007361 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007362 CAST_TO_NUMBER;
7363 CHECK_TYPE(XPATH_NUMBER);
7364 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007365}
7366
7367/**
7368 * xmlXPathMultValues:
7369 * @ctxt: the XPath Parser context
7370 *
7371 * Implement the multiply operation on XPath objects:
7372 * The numeric operators convert their operands to numbers as if
7373 * by calling the number function.
7374 */
7375void
7376xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7377 xmlXPathObjectPtr arg;
7378 double val;
7379
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007380 arg = valuePop(ctxt);
7381 if (arg == NULL)
7382 XP_ERROR(XPATH_INVALID_OPERAND);
7383 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007384 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007385 CAST_TO_NUMBER;
7386 CHECK_TYPE(XPATH_NUMBER);
7387 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007388}
7389
7390/**
7391 * xmlXPathDivValues:
7392 * @ctxt: the XPath Parser context
7393 *
7394 * Implement the div operation on XPath objects @arg1 / @arg2:
7395 * The numeric operators convert their operands to numbers as if
7396 * by calling the number function.
7397 */
7398void
7399xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7400 xmlXPathObjectPtr arg;
7401 double val;
7402
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007403 arg = valuePop(ctxt);
7404 if (arg == NULL)
7405 XP_ERROR(XPATH_INVALID_OPERAND);
7406 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007407 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007408 CAST_TO_NUMBER;
7409 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007410 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7411 ctxt->value->floatval = xmlXPathNAN;
7412 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007413 if (ctxt->value->floatval == 0)
7414 ctxt->value->floatval = xmlXPathNAN;
7415 else if (ctxt->value->floatval > 0)
7416 ctxt->value->floatval = xmlXPathNINF;
7417 else if (ctxt->value->floatval < 0)
7418 ctxt->value->floatval = xmlXPathPINF;
7419 }
7420 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007421 if (ctxt->value->floatval == 0)
7422 ctxt->value->floatval = xmlXPathNAN;
7423 else if (ctxt->value->floatval > 0)
7424 ctxt->value->floatval = xmlXPathPINF;
7425 else if (ctxt->value->floatval < 0)
7426 ctxt->value->floatval = xmlXPathNINF;
7427 } else
7428 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007429}
7430
7431/**
7432 * xmlXPathModValues:
7433 * @ctxt: the XPath Parser context
7434 *
7435 * Implement the mod operation on XPath objects: @arg1 / @arg2
7436 * The numeric operators convert their operands to numbers as if
7437 * by calling the number function.
7438 */
7439void
7440xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7441 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007442 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007443
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007444 arg = valuePop(ctxt);
7445 if (arg == NULL)
7446 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007447 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007448 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007449 CAST_TO_NUMBER;
7450 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007451 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007452 if (arg2 == 0)
7453 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007454 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007455 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007456 }
Owen Taylor3473f882001-02-23 17:55:21 +00007457}
7458
7459/************************************************************************
7460 * *
7461 * The traversal functions *
7462 * *
7463 ************************************************************************/
7464
Owen Taylor3473f882001-02-23 17:55:21 +00007465/*
7466 * A traversal function enumerates nodes along an axis.
7467 * Initially it must be called with NULL, and it indicates
7468 * termination on the axis by returning NULL.
7469 */
7470typedef xmlNodePtr (*xmlXPathTraversalFunction)
7471 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7472
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007473/*
7474 * xmlXPathTraversalFunctionExt:
7475 * A traversal function enumerates nodes along an axis.
7476 * Initially it must be called with NULL, and it indicates
7477 * termination on the axis by returning NULL.
7478 * The context node of the traversal is specified via @contextNode.
7479 */
7480typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7481 (xmlNodePtr cur, xmlNodePtr contextNode);
7482
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +00007483/*
7484 * xmlXPathNodeSetMergeFunction:
7485 * Used for merging node sets in xmlXPathCollectAndTest().
7486 */
7487typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7488 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7489
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007490
Owen Taylor3473f882001-02-23 17:55:21 +00007491/**
7492 * xmlXPathNextSelf:
7493 * @ctxt: the XPath Parser context
7494 * @cur: the current node in the traversal
7495 *
7496 * Traversal function for the "self" direction
7497 * The self axis contains just the context node itself
7498 *
7499 * Returns the next element following that axis
7500 */
7501xmlNodePtr
7502xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007503 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007504 if (cur == NULL)
7505 return(ctxt->context->node);
7506 return(NULL);
7507}
7508
7509/**
7510 * xmlXPathNextChild:
7511 * @ctxt: the XPath Parser context
7512 * @cur: the current node in the traversal
7513 *
7514 * Traversal function for the "child" direction
7515 * The child axis contains the children of the context node in document order.
7516 *
7517 * Returns the next element following that axis
7518 */
7519xmlNodePtr
7520xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007521 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007522 if (cur == NULL) {
7523 if (ctxt->context->node == NULL) return(NULL);
7524 switch (ctxt->context->node->type) {
7525 case XML_ELEMENT_NODE:
7526 case XML_TEXT_NODE:
7527 case XML_CDATA_SECTION_NODE:
7528 case XML_ENTITY_REF_NODE:
7529 case XML_ENTITY_NODE:
7530 case XML_PI_NODE:
7531 case XML_COMMENT_NODE:
7532 case XML_NOTATION_NODE:
7533 case XML_DTD_NODE:
7534 return(ctxt->context->node->children);
7535 case XML_DOCUMENT_NODE:
7536 case XML_DOCUMENT_TYPE_NODE:
7537 case XML_DOCUMENT_FRAG_NODE:
7538 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007539#ifdef LIBXML_DOCB_ENABLED
7540 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007541#endif
7542 return(((xmlDocPtr) ctxt->context->node)->children);
7543 case XML_ELEMENT_DECL:
7544 case XML_ATTRIBUTE_DECL:
7545 case XML_ENTITY_DECL:
7546 case XML_ATTRIBUTE_NODE:
7547 case XML_NAMESPACE_DECL:
7548 case XML_XINCLUDE_START:
7549 case XML_XINCLUDE_END:
7550 return(NULL);
7551 }
7552 return(NULL);
7553 }
7554 if ((cur->type == XML_DOCUMENT_NODE) ||
7555 (cur->type == XML_HTML_DOCUMENT_NODE))
7556 return(NULL);
7557 return(cur->next);
7558}
7559
7560/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007561 * xmlXPathNextChildElement:
7562 * @ctxt: the XPath Parser context
7563 * @cur: the current node in the traversal
7564 *
7565 * Traversal function for the "child" direction and nodes of type element.
7566 * The child axis contains the children of the context node in document order.
7567 *
7568 * Returns the next element following that axis
7569 */
7570static xmlNodePtr
7571xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7572 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7573 if (cur == NULL) {
7574 cur = ctxt->context->node;
7575 if (cur == NULL) return(NULL);
7576 /*
7577 * Get the first element child.
7578 */
7579 switch (cur->type) {
7580 case XML_ELEMENT_NODE:
7581 case XML_DOCUMENT_FRAG_NODE:
7582 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7583 case XML_ENTITY_NODE:
7584 cur = cur->children;
7585 if (cur != NULL) {
7586 if (cur->type == XML_ELEMENT_NODE)
7587 return(cur);
7588 do {
7589 cur = cur->next;
7590 } while ((cur != NULL) &&
7591 (cur->type != XML_ELEMENT_NODE));
7592 return(cur);
7593 }
7594 return(NULL);
7595 case XML_DOCUMENT_NODE:
7596 case XML_HTML_DOCUMENT_NODE:
7597#ifdef LIBXML_DOCB_ENABLED
7598 case XML_DOCB_DOCUMENT_NODE:
7599#endif
7600 return(xmlDocGetRootElement((xmlDocPtr) cur));
7601 default:
7602 return(NULL);
7603 }
7604 return(NULL);
7605 }
7606 /*
7607 * Get the next sibling element node.
7608 */
7609 switch (cur->type) {
7610 case XML_ELEMENT_NODE:
7611 case XML_TEXT_NODE:
7612 case XML_ENTITY_REF_NODE:
7613 case XML_ENTITY_NODE:
7614 case XML_CDATA_SECTION_NODE:
7615 case XML_PI_NODE:
7616 case XML_COMMENT_NODE:
7617 case XML_XINCLUDE_END:
7618 break;
7619 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7620 default:
7621 return(NULL);
7622 }
7623 if (cur->next != NULL) {
7624 if (cur->next->type == XML_ELEMENT_NODE)
7625 return(cur->next);
7626 cur = cur->next;
7627 do {
7628 cur = cur->next;
7629 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7630 return(cur);
7631 }
7632 return(NULL);
7633}
7634
7635/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007636 * xmlXPathNextDescendantOrSelfElemParent:
7637 * @ctxt: the XPath Parser context
7638 * @cur: the current node in the traversal
7639 *
7640 * Traversal function for the "descendant-or-self" axis.
7641 * Additionally it returns only nodes which can be parents of
7642 * element nodes.
7643 *
7644 *
7645 * Returns the next element following that axis
7646 */
7647static xmlNodePtr
7648xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7649 xmlNodePtr contextNode)
7650{
7651 if (cur == NULL) {
7652 if (contextNode == NULL)
7653 return(NULL);
7654 switch (contextNode->type) {
7655 case XML_ELEMENT_NODE:
7656 case XML_XINCLUDE_START:
7657 case XML_DOCUMENT_FRAG_NODE:
7658 case XML_DOCUMENT_NODE:
7659#ifdef LIBXML_DOCB_ENABLED
7660 case XML_DOCB_DOCUMENT_NODE:
7661#endif
7662 case XML_HTML_DOCUMENT_NODE:
7663 return(contextNode);
7664 default:
7665 return(NULL);
7666 }
7667 return(NULL);
7668 } else {
7669 xmlNodePtr start = cur;
7670
7671 while (cur != NULL) {
7672 switch (cur->type) {
7673 case XML_ELEMENT_NODE:
7674 /* TODO: OK to have XInclude here? */
7675 case XML_XINCLUDE_START:
7676 case XML_DOCUMENT_FRAG_NODE:
7677 if (cur != start)
7678 return(cur);
7679 if (cur->children != NULL) {
7680 cur = cur->children;
7681 continue;
7682 }
7683 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007684 /* Not sure if we need those here. */
7685 case XML_DOCUMENT_NODE:
Daniel Veillard17970a72006-10-26 08:55:47 +00007686#ifdef LIBXML_DOCB_ENABLED
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007687 case XML_DOCB_DOCUMENT_NODE:
7688#endif
7689 case XML_HTML_DOCUMENT_NODE:
7690 if (cur != start)
7691 return(cur);
7692 return(xmlDocGetRootElement((xmlDocPtr) cur));
7693 default:
7694 break;
7695 }
7696
7697next_sibling:
7698 if ((cur == NULL) || (cur == contextNode))
7699 return(NULL);
7700 if (cur->next != NULL) {
7701 cur = cur->next;
7702 } else {
7703 cur = cur->parent;
7704 goto next_sibling;
7705 }
7706 }
7707 }
7708 return(NULL);
7709}
7710
7711/**
Owen Taylor3473f882001-02-23 17:55:21 +00007712 * xmlXPathNextDescendant:
7713 * @ctxt: the XPath Parser context
7714 * @cur: the current node in the traversal
7715 *
7716 * Traversal function for the "descendant" direction
7717 * the descendant axis contains the descendants of the context node in document
7718 * order; a descendant is a child or a child of a child and so on.
7719 *
7720 * Returns the next element following that axis
7721 */
7722xmlNodePtr
7723xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007724 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007725 if (cur == NULL) {
7726 if (ctxt->context->node == NULL)
7727 return(NULL);
7728 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7729 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7730 return(NULL);
7731
7732 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7733 return(ctxt->context->doc->children);
7734 return(ctxt->context->node->children);
7735 }
7736
Daniel Veillard567e1b42001-08-01 15:53:47 +00007737 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007738 /*
7739 * Do not descend on entities declarations
7740 */
7741 if (cur->children->type != XML_ENTITY_DECL) {
7742 cur = cur->children;
7743 /*
7744 * Skip DTDs
7745 */
7746 if (cur->type != XML_DTD_NODE)
7747 return(cur);
7748 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007749 }
7750
7751 if (cur == ctxt->context->node) return(NULL);
7752
Daniel Veillard68e9e742002-11-16 15:35:11 +00007753 while (cur->next != NULL) {
7754 cur = cur->next;
7755 if ((cur->type != XML_ENTITY_DECL) &&
7756 (cur->type != XML_DTD_NODE))
7757 return(cur);
7758 }
Owen Taylor3473f882001-02-23 17:55:21 +00007759
7760 do {
7761 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007762 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007763 if (cur == ctxt->context->node) return(NULL);
7764 if (cur->next != NULL) {
7765 cur = cur->next;
7766 return(cur);
7767 }
7768 } while (cur != NULL);
7769 return(cur);
7770}
7771
7772/**
7773 * xmlXPathNextDescendantOrSelf:
7774 * @ctxt: the XPath Parser context
7775 * @cur: the current node in the traversal
7776 *
7777 * Traversal function for the "descendant-or-self" direction
7778 * the descendant-or-self axis contains the context node and the descendants
7779 * of the context node in document order; thus the context node is the first
7780 * node on the axis, and the first child of the context node is the second node
7781 * on the axis
7782 *
7783 * Returns the next element following that axis
7784 */
7785xmlNodePtr
7786xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007787 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007788 if (cur == NULL) {
7789 if (ctxt->context->node == NULL)
7790 return(NULL);
7791 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7792 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7793 return(NULL);
7794 return(ctxt->context->node);
7795 }
7796
7797 return(xmlXPathNextDescendant(ctxt, cur));
7798}
7799
7800/**
7801 * xmlXPathNextParent:
7802 * @ctxt: the XPath Parser context
7803 * @cur: the current node in the traversal
7804 *
7805 * Traversal function for the "parent" direction
7806 * The parent axis contains the parent of the context node, if there is one.
7807 *
7808 * Returns the next element following that axis
7809 */
7810xmlNodePtr
7811xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007812 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007813 /*
7814 * the parent of an attribute or namespace node is the element
7815 * to which the attribute or namespace node is attached
7816 * Namespace handling !!!
7817 */
7818 if (cur == NULL) {
7819 if (ctxt->context->node == NULL) return(NULL);
7820 switch (ctxt->context->node->type) {
7821 case XML_ELEMENT_NODE:
7822 case XML_TEXT_NODE:
7823 case XML_CDATA_SECTION_NODE:
7824 case XML_ENTITY_REF_NODE:
7825 case XML_ENTITY_NODE:
7826 case XML_PI_NODE:
7827 case XML_COMMENT_NODE:
7828 case XML_NOTATION_NODE:
7829 case XML_DTD_NODE:
7830 case XML_ELEMENT_DECL:
7831 case XML_ATTRIBUTE_DECL:
7832 case XML_XINCLUDE_START:
7833 case XML_XINCLUDE_END:
7834 case XML_ENTITY_DECL:
7835 if (ctxt->context->node->parent == NULL)
7836 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007837 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007838 ((ctxt->context->node->parent->name[0] == ' ') ||
7839 (xmlStrEqual(ctxt->context->node->parent->name,
7840 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007841 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007842 return(ctxt->context->node->parent);
7843 case XML_ATTRIBUTE_NODE: {
7844 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7845
7846 return(att->parent);
7847 }
7848 case XML_DOCUMENT_NODE:
7849 case XML_DOCUMENT_TYPE_NODE:
7850 case XML_DOCUMENT_FRAG_NODE:
7851 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007852#ifdef LIBXML_DOCB_ENABLED
7853 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007854#endif
7855 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007856 case XML_NAMESPACE_DECL: {
7857 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7858
7859 if ((ns->next != NULL) &&
7860 (ns->next->type != XML_NAMESPACE_DECL))
7861 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007862 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007863 }
Owen Taylor3473f882001-02-23 17:55:21 +00007864 }
7865 }
7866 return(NULL);
7867}
7868
7869/**
7870 * xmlXPathNextAncestor:
7871 * @ctxt: the XPath Parser context
7872 * @cur: the current node in the traversal
7873 *
7874 * Traversal function for the "ancestor" direction
7875 * the ancestor axis contains the ancestors of the context node; the ancestors
7876 * of the context node consist of the parent of context node and the parent's
7877 * parent and so on; the nodes are ordered in reverse document order; thus the
7878 * parent is the first node on the axis, and the parent's parent is the second
7879 * node on the axis
7880 *
7881 * Returns the next element following that axis
7882 */
7883xmlNodePtr
7884xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007885 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007886 /*
7887 * the parent of an attribute or namespace node is the element
7888 * to which the attribute or namespace node is attached
7889 * !!!!!!!!!!!!!
7890 */
7891 if (cur == NULL) {
7892 if (ctxt->context->node == NULL) return(NULL);
7893 switch (ctxt->context->node->type) {
7894 case XML_ELEMENT_NODE:
7895 case XML_TEXT_NODE:
7896 case XML_CDATA_SECTION_NODE:
7897 case XML_ENTITY_REF_NODE:
7898 case XML_ENTITY_NODE:
7899 case XML_PI_NODE:
7900 case XML_COMMENT_NODE:
7901 case XML_DTD_NODE:
7902 case XML_ELEMENT_DECL:
7903 case XML_ATTRIBUTE_DECL:
7904 case XML_ENTITY_DECL:
7905 case XML_NOTATION_NODE:
7906 case XML_XINCLUDE_START:
7907 case XML_XINCLUDE_END:
7908 if (ctxt->context->node->parent == NULL)
7909 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007910 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007911 ((ctxt->context->node->parent->name[0] == ' ') ||
7912 (xmlStrEqual(ctxt->context->node->parent->name,
7913 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007914 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007915 return(ctxt->context->node->parent);
7916 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007917 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007918
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007919 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007920 }
7921 case XML_DOCUMENT_NODE:
7922 case XML_DOCUMENT_TYPE_NODE:
7923 case XML_DOCUMENT_FRAG_NODE:
7924 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007925#ifdef LIBXML_DOCB_ENABLED
7926 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007927#endif
7928 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007929 case XML_NAMESPACE_DECL: {
7930 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7931
7932 if ((ns->next != NULL) &&
7933 (ns->next->type != XML_NAMESPACE_DECL))
7934 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007935 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007936 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007937 }
Owen Taylor3473f882001-02-23 17:55:21 +00007938 }
7939 return(NULL);
7940 }
7941 if (cur == ctxt->context->doc->children)
7942 return((xmlNodePtr) ctxt->context->doc);
7943 if (cur == (xmlNodePtr) ctxt->context->doc)
7944 return(NULL);
7945 switch (cur->type) {
7946 case XML_ELEMENT_NODE:
7947 case XML_TEXT_NODE:
7948 case XML_CDATA_SECTION_NODE:
7949 case XML_ENTITY_REF_NODE:
7950 case XML_ENTITY_NODE:
7951 case XML_PI_NODE:
7952 case XML_COMMENT_NODE:
7953 case XML_NOTATION_NODE:
7954 case XML_DTD_NODE:
7955 case XML_ELEMENT_DECL:
7956 case XML_ATTRIBUTE_DECL:
7957 case XML_ENTITY_DECL:
7958 case XML_XINCLUDE_START:
7959 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007960 if (cur->parent == NULL)
7961 return(NULL);
7962 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007963 ((cur->parent->name[0] == ' ') ||
7964 (xmlStrEqual(cur->parent->name,
7965 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007966 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007967 return(cur->parent);
7968 case XML_ATTRIBUTE_NODE: {
7969 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7970
7971 return(att->parent);
7972 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007973 case XML_NAMESPACE_DECL: {
7974 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7975
7976 if ((ns->next != NULL) &&
7977 (ns->next->type != XML_NAMESPACE_DECL))
7978 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007979 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007980 return(NULL);
7981 }
Owen Taylor3473f882001-02-23 17:55:21 +00007982 case XML_DOCUMENT_NODE:
7983 case XML_DOCUMENT_TYPE_NODE:
7984 case XML_DOCUMENT_FRAG_NODE:
7985 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007986#ifdef LIBXML_DOCB_ENABLED
7987 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007988#endif
7989 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007990 }
7991 return(NULL);
7992}
7993
7994/**
7995 * xmlXPathNextAncestorOrSelf:
7996 * @ctxt: the XPath Parser context
7997 * @cur: the current node in the traversal
7998 *
7999 * Traversal function for the "ancestor-or-self" direction
8000 * he ancestor-or-self axis contains the context node and ancestors of
8001 * the context node in reverse document order; thus the context node is
8002 * the first node on the axis, and the context node's parent the second;
8003 * parent here is defined the same as with the parent axis.
8004 *
8005 * Returns the next element following that axis
8006 */
8007xmlNodePtr
8008xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008009 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008010 if (cur == NULL)
8011 return(ctxt->context->node);
8012 return(xmlXPathNextAncestor(ctxt, cur));
8013}
8014
8015/**
8016 * xmlXPathNextFollowingSibling:
8017 * @ctxt: the XPath Parser context
8018 * @cur: the current node in the traversal
8019 *
8020 * Traversal function for the "following-sibling" direction
8021 * The following-sibling axis contains the following siblings of the context
8022 * node in document order.
8023 *
8024 * Returns the next element following that axis
8025 */
8026xmlNodePtr
8027xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008028 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008029 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8030 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8031 return(NULL);
8032 if (cur == (xmlNodePtr) ctxt->context->doc)
8033 return(NULL);
8034 if (cur == NULL)
8035 return(ctxt->context->node->next);
8036 return(cur->next);
8037}
8038
8039/**
8040 * xmlXPathNextPrecedingSibling:
8041 * @ctxt: the XPath Parser context
8042 * @cur: the current node in the traversal
8043 *
8044 * Traversal function for the "preceding-sibling" direction
8045 * The preceding-sibling axis contains the preceding siblings of the context
8046 * node in reverse document order; the first preceding sibling is first on the
8047 * axis; the sibling preceding that node is the second on the axis and so on.
8048 *
8049 * Returns the next element following that axis
8050 */
8051xmlNodePtr
8052xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008053 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008054 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8055 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8056 return(NULL);
8057 if (cur == (xmlNodePtr) ctxt->context->doc)
8058 return(NULL);
8059 if (cur == NULL)
8060 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008061 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8062 cur = cur->prev;
8063 if (cur == NULL)
8064 return(ctxt->context->node->prev);
8065 }
Owen Taylor3473f882001-02-23 17:55:21 +00008066 return(cur->prev);
8067}
8068
8069/**
8070 * xmlXPathNextFollowing:
8071 * @ctxt: the XPath Parser context
8072 * @cur: the current node in the traversal
8073 *
8074 * Traversal function for the "following" direction
8075 * The following axis contains all nodes in the same document as the context
8076 * node that are after the context node in document order, excluding any
8077 * descendants and excluding attribute nodes and namespace nodes; the nodes
8078 * are ordered in document order
8079 *
8080 * Returns the next element following that axis
8081 */
8082xmlNodePtr
8083xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008084 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008085 if (cur != NULL && cur->children != NULL)
8086 return cur->children ;
8087 if (cur == NULL) cur = ctxt->context->node;
8088 if (cur == NULL) return(NULL) ; /* ERROR */
8089 if (cur->next != NULL) return(cur->next) ;
8090 do {
8091 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00008092 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00008093 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8094 if (cur->next != NULL) return(cur->next);
8095 } while (cur != NULL);
8096 return(cur);
8097}
8098
8099/*
8100 * xmlXPathIsAncestor:
8101 * @ancestor: the ancestor node
8102 * @node: the current node
8103 *
8104 * Check that @ancestor is a @node's ancestor
8105 *
8106 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8107 */
8108static int
8109xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8110 if ((ancestor == NULL) || (node == NULL)) return(0);
8111 /* nodes need to be in the same document */
8112 if (ancestor->doc != node->doc) return(0);
8113 /* avoid searching if ancestor or node is the root node */
8114 if (ancestor == (xmlNodePtr) node->doc) return(1);
8115 if (node == (xmlNodePtr) ancestor->doc) return(0);
8116 while (node->parent != NULL) {
8117 if (node->parent == ancestor)
8118 return(1);
8119 node = node->parent;
8120 }
8121 return(0);
8122}
8123
8124/**
8125 * xmlXPathNextPreceding:
8126 * @ctxt: the XPath Parser context
8127 * @cur: the current node in the traversal
8128 *
8129 * Traversal function for the "preceding" direction
8130 * the preceding axis contains all nodes in the same document as the context
8131 * node that are before the context node in document order, excluding any
8132 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8133 * ordered in reverse document order
8134 *
8135 * Returns the next element following that axis
8136 */
8137xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00008138xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8139{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008140 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008141 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00008142 cur = ctxt->context->node;
8143 if (cur == NULL)
8144 return (NULL);
8145 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8146 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00008147 do {
8148 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00008149 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8150 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008151 }
8152
8153 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008154 if (cur == NULL)
8155 return (NULL);
8156 if (cur == ctxt->context->doc->children)
8157 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008158 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00008159 return (cur);
8160}
8161
8162/**
8163 * xmlXPathNextPrecedingInternal:
8164 * @ctxt: the XPath Parser context
8165 * @cur: the current node in the traversal
8166 *
8167 * Traversal function for the "preceding" direction
8168 * the preceding axis contains all nodes in the same document as the context
8169 * node that are before the context node in document order, excluding any
8170 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8171 * ordered in reverse document order
8172 * This is a faster implementation but internal only since it requires a
8173 * state kept in the parser context: ctxt->ancestor.
8174 *
8175 * Returns the next element following that axis
8176 */
8177static xmlNodePtr
8178xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8179 xmlNodePtr cur)
8180{
Daniel Veillarda82b1822004-11-08 16:24:57 +00008181 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00008182 if (cur == NULL) {
8183 cur = ctxt->context->node;
8184 if (cur == NULL)
8185 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00008186 if (cur->type == XML_NAMESPACE_DECL)
8187 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00008188 ctxt->ancestor = cur->parent;
8189 }
8190 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8191 cur = cur->prev;
8192 while (cur->prev == NULL) {
8193 cur = cur->parent;
8194 if (cur == NULL)
8195 return (NULL);
8196 if (cur == ctxt->context->doc->children)
8197 return (NULL);
8198 if (cur != ctxt->ancestor)
8199 return (cur);
8200 ctxt->ancestor = cur->parent;
8201 }
8202 cur = cur->prev;
8203 while (cur->last != NULL)
8204 cur = cur->last;
8205 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008206}
8207
8208/**
8209 * xmlXPathNextNamespace:
8210 * @ctxt: the XPath Parser context
8211 * @cur: the current attribute in the traversal
8212 *
8213 * Traversal function for the "namespace" direction
8214 * the namespace axis contains the namespace nodes of the context node;
8215 * the order of nodes on this axis is implementation-defined; the axis will
8216 * be empty unless the context node is an element
8217 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008218 * We keep the XML namespace node at the end of the list.
8219 *
Owen Taylor3473f882001-02-23 17:55:21 +00008220 * Returns the next element following that axis
8221 */
8222xmlNodePtr
8223xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008224 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008225 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00008226 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008227 if (ctxt->context->tmpNsList != NULL)
8228 xmlFree(ctxt->context->tmpNsList);
8229 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00008230 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008231 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00008232 if (ctxt->context->tmpNsList != NULL) {
8233 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8234 ctxt->context->tmpNsNr++;
8235 }
8236 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00008237 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00008238 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00008239 if (ctxt->context->tmpNsNr > 0) {
8240 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8241 } else {
8242 if (ctxt->context->tmpNsList != NULL)
8243 xmlFree(ctxt->context->tmpNsList);
8244 ctxt->context->tmpNsList = NULL;
8245 return(NULL);
8246 }
Owen Taylor3473f882001-02-23 17:55:21 +00008247}
8248
8249/**
8250 * xmlXPathNextAttribute:
8251 * @ctxt: the XPath Parser context
8252 * @cur: the current attribute in the traversal
8253 *
8254 * Traversal function for the "attribute" direction
8255 * TODO: support DTD inherited default attributes
8256 *
8257 * Returns the next element following that axis
8258 */
8259xmlNodePtr
8260xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008261 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00008262 if (ctxt->context->node == NULL)
8263 return(NULL);
8264 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8265 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008266 if (cur == NULL) {
8267 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8268 return(NULL);
8269 return((xmlNodePtr)ctxt->context->node->properties);
8270 }
8271 return((xmlNodePtr)cur->next);
8272}
8273
8274/************************************************************************
8275 * *
8276 * NodeTest Functions *
8277 * *
8278 ************************************************************************/
8279
Owen Taylor3473f882001-02-23 17:55:21 +00008280#define IS_FUNCTION 200
8281
Owen Taylor3473f882001-02-23 17:55:21 +00008282
8283/************************************************************************
8284 * *
8285 * Implicit tree core function library *
8286 * *
8287 ************************************************************************/
8288
8289/**
8290 * xmlXPathRoot:
8291 * @ctxt: the XPath Parser context
8292 *
8293 * Initialize the context to the root of the document
8294 */
8295void
8296xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008297 if ((ctxt == NULL) || (ctxt->context == NULL))
8298 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008299 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008300 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8301 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008302}
8303
8304/************************************************************************
8305 * *
8306 * The explicit core function library *
8307 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8308 * *
8309 ************************************************************************/
8310
8311
8312/**
8313 * xmlXPathLastFunction:
8314 * @ctxt: the XPath Parser context
8315 * @nargs: the number of arguments
8316 *
8317 * Implement the last() XPath function
8318 * number last()
8319 * The last function returns the number of nodes in the context node list.
8320 */
8321void
8322xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8323 CHECK_ARITY(0);
8324 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008325 valuePush(ctxt,
8326 xmlXPathCacheNewFloat(ctxt->context,
8327 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008328#ifdef DEBUG_EXPR
8329 xmlGenericError(xmlGenericErrorContext,
8330 "last() : %d\n", ctxt->context->contextSize);
8331#endif
8332 } else {
8333 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8334 }
8335}
8336
8337/**
8338 * xmlXPathPositionFunction:
8339 * @ctxt: the XPath Parser context
8340 * @nargs: the number of arguments
8341 *
8342 * Implement the position() XPath function
8343 * number position()
8344 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008345 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008346 * will be equal to last().
8347 */
8348void
8349xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8350 CHECK_ARITY(0);
8351 if (ctxt->context->proximityPosition >= 0) {
8352 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008353 xmlXPathCacheNewFloat(ctxt->context,
8354 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008355#ifdef DEBUG_EXPR
8356 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8357 ctxt->context->proximityPosition);
8358#endif
8359 } else {
8360 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8361 }
8362}
8363
8364/**
8365 * xmlXPathCountFunction:
8366 * @ctxt: the XPath Parser context
8367 * @nargs: the number of arguments
8368 *
8369 * Implement the count() XPath function
8370 * number count(node-set)
8371 */
8372void
8373xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8374 xmlXPathObjectPtr cur;
8375
8376 CHECK_ARITY(1);
8377 if ((ctxt->value == NULL) ||
8378 ((ctxt->value->type != XPATH_NODESET) &&
8379 (ctxt->value->type != XPATH_XSLT_TREE)))
8380 XP_ERROR(XPATH_INVALID_TYPE);
8381 cur = valuePop(ctxt);
8382
Daniel Veillard911f49a2001-04-07 15:39:35 +00008383 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008384 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008385 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008386 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8387 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008388 } else {
8389 if ((cur->nodesetval->nodeNr != 1) ||
8390 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008391 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008392 } else {
8393 xmlNodePtr tmp;
8394 int i = 0;
8395
8396 tmp = cur->nodesetval->nodeTab[0];
8397 if (tmp != NULL) {
8398 tmp = tmp->children;
8399 while (tmp != NULL) {
8400 tmp = tmp->next;
8401 i++;
8402 }
8403 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008404 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008405 }
8406 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008407 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008408}
8409
8410/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008411 * xmlXPathGetElementsByIds:
8412 * @doc: the document
8413 * @ids: a whitespace separated list of IDs
8414 *
8415 * Selects elements by their unique ID.
8416 *
8417 * Returns a node-set of selected elements.
8418 */
8419static xmlNodeSetPtr
8420xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8421 xmlNodeSetPtr ret;
8422 const xmlChar *cur = ids;
8423 xmlChar *ID;
8424 xmlAttrPtr attr;
8425 xmlNodePtr elem = NULL;
8426
Daniel Veillard7a985a12003-07-06 17:57:42 +00008427 if (ids == NULL) return(NULL);
8428
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008429 ret = xmlXPathNodeSetCreate(NULL);
8430
William M. Brack76e95df2003-10-18 16:20:14 +00008431 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008432 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008433 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008434 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008435
8436 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008437 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008438 /*
8439 * We used to check the fact that the value passed
8440 * was an NCName, but this generated much troubles for
8441 * me and Aleksey Sanin, people blatantly violated that
8442 * constaint, like Visa3D spec.
8443 * if (xmlValidateNCName(ID, 1) == 0)
8444 */
8445 attr = xmlGetID(doc, ID);
8446 if (attr != NULL) {
8447 if (attr->type == XML_ATTRIBUTE_NODE)
8448 elem = attr->parent;
8449 else if (attr->type == XML_ELEMENT_NODE)
8450 elem = (xmlNodePtr) attr;
8451 else
8452 elem = NULL;
8453 if (elem != NULL)
8454 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008455 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008456 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008457 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008458
William M. Brack76e95df2003-10-18 16:20:14 +00008459 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008460 ids = cur;
8461 }
8462 return(ret);
8463}
8464
8465/**
Owen Taylor3473f882001-02-23 17:55:21 +00008466 * xmlXPathIdFunction:
8467 * @ctxt: the XPath Parser context
8468 * @nargs: the number of arguments
8469 *
8470 * Implement the id() XPath function
8471 * node-set id(object)
8472 * The id function selects elements by their unique ID
8473 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8474 * then the result is the union of the result of applying id to the
8475 * string value of each of the nodes in the argument node-set. When the
8476 * argument to id is of any other type, the argument is converted to a
8477 * string as if by a call to the string function; the string is split
8478 * into a whitespace-separated list of tokens (whitespace is any sequence
8479 * of characters matching the production S); the result is a node-set
8480 * containing the elements in the same document as the context node that
8481 * have a unique ID equal to any of the tokens in the list.
8482 */
8483void
8484xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008485 xmlChar *tokens;
8486 xmlNodeSetPtr ret;
8487 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008488
8489 CHECK_ARITY(1);
8490 obj = valuePop(ctxt);
8491 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008492 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008493 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008494 int i;
8495
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008496 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008497
Daniel Veillard911f49a2001-04-07 15:39:35 +00008498 if (obj->nodesetval != NULL) {
8499 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008500 tokens =
8501 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8502 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8503 ret = xmlXPathNodeSetMerge(ret, ns);
8504 xmlXPathFreeNodeSet(ns);
8505 if (tokens != NULL)
8506 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008507 }
Owen Taylor3473f882001-02-23 17:55:21 +00008508 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008509 xmlXPathReleaseObject(ctxt->context, obj);
8510 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008511 return;
8512 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008513 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008514 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008515 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8516 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008517 return;
8518}
8519
8520/**
8521 * xmlXPathLocalNameFunction:
8522 * @ctxt: the XPath Parser context
8523 * @nargs: the number of arguments
8524 *
8525 * Implement the local-name() XPath function
8526 * string local-name(node-set?)
8527 * The local-name function returns a string containing the local part
8528 * of the name of the node in the argument node-set that is first in
8529 * document order. If the node-set is empty or the first node has no
8530 * name, an empty string is returned. If the argument is omitted it
8531 * defaults to the context node.
8532 */
8533void
8534xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8535 xmlXPathObjectPtr cur;
8536
Daniel Veillarda82b1822004-11-08 16:24:57 +00008537 if (ctxt == NULL) return;
8538
Owen Taylor3473f882001-02-23 17:55:21 +00008539 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008540 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8541 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008542 nargs = 1;
8543 }
8544
8545 CHECK_ARITY(1);
8546 if ((ctxt->value == NULL) ||
8547 ((ctxt->value->type != XPATH_NODESET) &&
8548 (ctxt->value->type != XPATH_XSLT_TREE)))
8549 XP_ERROR(XPATH_INVALID_TYPE);
8550 cur = valuePop(ctxt);
8551
Daniel Veillard911f49a2001-04-07 15:39:35 +00008552 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008553 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008554 } else {
8555 int i = 0; /* Should be first in document order !!!!! */
8556 switch (cur->nodesetval->nodeTab[i]->type) {
8557 case XML_ELEMENT_NODE:
8558 case XML_ATTRIBUTE_NODE:
8559 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008560 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008561 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008562 else
8563 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008564 xmlXPathCacheNewString(ctxt->context,
8565 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008566 break;
8567 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008568 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008569 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8570 break;
8571 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008572 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008573 }
8574 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008575 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008576}
8577
8578/**
8579 * xmlXPathNamespaceURIFunction:
8580 * @ctxt: the XPath Parser context
8581 * @nargs: the number of arguments
8582 *
8583 * Implement the namespace-uri() XPath function
8584 * string namespace-uri(node-set?)
8585 * The namespace-uri function returns a string containing the
8586 * namespace URI of the expanded name of the node in the argument
8587 * node-set that is first in document order. If the node-set is empty,
8588 * the first node has no name, or the expanded name has no namespace
8589 * URI, an empty string is returned. If the argument is omitted it
8590 * defaults to the context node.
8591 */
8592void
8593xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8594 xmlXPathObjectPtr cur;
8595
Daniel Veillarda82b1822004-11-08 16:24:57 +00008596 if (ctxt == NULL) return;
8597
Owen Taylor3473f882001-02-23 17:55:21 +00008598 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008599 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8600 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008601 nargs = 1;
8602 }
8603 CHECK_ARITY(1);
8604 if ((ctxt->value == NULL) ||
8605 ((ctxt->value->type != XPATH_NODESET) &&
8606 (ctxt->value->type != XPATH_XSLT_TREE)))
8607 XP_ERROR(XPATH_INVALID_TYPE);
8608 cur = valuePop(ctxt);
8609
Daniel Veillard911f49a2001-04-07 15:39:35 +00008610 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008611 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008612 } else {
8613 int i = 0; /* Should be first in document order !!!!! */
8614 switch (cur->nodesetval->nodeTab[i]->type) {
8615 case XML_ELEMENT_NODE:
8616 case XML_ATTRIBUTE_NODE:
8617 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008618 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008619 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008620 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008621 cur->nodesetval->nodeTab[i]->ns->href));
8622 break;
8623 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008624 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008625 }
8626 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008627 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008628}
8629
8630/**
8631 * xmlXPathNameFunction:
8632 * @ctxt: the XPath Parser context
8633 * @nargs: the number of arguments
8634 *
8635 * Implement the name() XPath function
8636 * string name(node-set?)
8637 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008638 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008639 * order. The QName must represent the name with respect to the namespace
8640 * declarations in effect on the node whose name is being represented.
8641 * Typically, this will be the form in which the name occurred in the XML
8642 * source. This need not be the case if there are namespace declarations
8643 * in effect on the node that associate multiple prefixes with the same
8644 * namespace. However, an implementation may include information about
8645 * the original prefix in its representation of nodes; in this case, an
8646 * implementation can ensure that the returned string is always the same
8647 * as the QName used in the XML source. If the argument it omitted it
8648 * defaults to the context node.
8649 * Libxml keep the original prefix so the "real qualified name" used is
8650 * returned.
8651 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008652static void
Daniel Veillard04383752001-07-08 14:27:15 +00008653xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8654{
Owen Taylor3473f882001-02-23 17:55:21 +00008655 xmlXPathObjectPtr cur;
8656
8657 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008658 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8659 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008660 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008661 }
8662
8663 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008664 if ((ctxt->value == NULL) ||
8665 ((ctxt->value->type != XPATH_NODESET) &&
8666 (ctxt->value->type != XPATH_XSLT_TREE)))
8667 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008668 cur = valuePop(ctxt);
8669
Daniel Veillard911f49a2001-04-07 15:39:35 +00008670 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008671 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008672 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008673 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008674
Daniel Veillard04383752001-07-08 14:27:15 +00008675 switch (cur->nodesetval->nodeTab[i]->type) {
8676 case XML_ELEMENT_NODE:
8677 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008678 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008679 valuePush(ctxt,
8680 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008681 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8682 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008683 valuePush(ctxt,
8684 xmlXPathCacheNewString(ctxt->context,
8685 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008686 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008687 xmlChar *fullname;
8688
8689 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8690 cur->nodesetval->nodeTab[i]->ns->prefix,
8691 NULL, 0);
8692 if (fullname == cur->nodesetval->nodeTab[i]->name)
8693 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8694 if (fullname == NULL) {
8695 XP_ERROR(XPATH_MEMORY_ERROR);
8696 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008697 valuePush(ctxt, xmlXPathCacheWrapString(
8698 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008699 }
8700 break;
8701 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8703 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008704 xmlXPathLocalNameFunction(ctxt, 1);
8705 }
Owen Taylor3473f882001-02-23 17:55:21 +00008706 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008707 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008708}
8709
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008710
8711/**
Owen Taylor3473f882001-02-23 17:55:21 +00008712 * xmlXPathStringFunction:
8713 * @ctxt: the XPath Parser context
8714 * @nargs: the number of arguments
8715 *
8716 * Implement the string() XPath function
8717 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008718 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008719 * - A node-set is converted to a string by returning the value of
8720 * the node in the node-set that is first in document order.
8721 * If the node-set is empty, an empty string is returned.
8722 * - A number is converted to a string as follows
8723 * + NaN is converted to the string NaN
8724 * + positive zero is converted to the string 0
8725 * + negative zero is converted to the string 0
8726 * + positive infinity is converted to the string Infinity
8727 * + negative infinity is converted to the string -Infinity
8728 * + if the number is an integer, the number is represented in
8729 * decimal form as a Number with no decimal point and no leading
8730 * zeros, preceded by a minus sign (-) if the number is negative
8731 * + otherwise, the number is represented in decimal form as a
8732 * Number including a decimal point with at least one digit
8733 * before the decimal point and at least one digit after the
8734 * decimal point, preceded by a minus sign (-) if the number
8735 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008736 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008737 * before the decimal point; beyond the one required digit
8738 * after the decimal point there must be as many, but only as
8739 * many, more digits as are needed to uniquely distinguish the
8740 * number from all other IEEE 754 numeric values.
8741 * - The boolean false value is converted to the string false.
8742 * The boolean true value is converted to the string true.
8743 *
8744 * If the argument is omitted, it defaults to a node-set with the
8745 * context node as its only member.
8746 */
8747void
8748xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8749 xmlXPathObjectPtr cur;
8750
Daniel Veillarda82b1822004-11-08 16:24:57 +00008751 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008752 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008753 valuePush(ctxt,
8754 xmlXPathCacheWrapString(ctxt->context,
8755 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008756 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008757 }
8758
8759 CHECK_ARITY(1);
8760 cur = valuePop(ctxt);
8761 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008762 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008763}
8764
8765/**
8766 * xmlXPathStringLengthFunction:
8767 * @ctxt: the XPath Parser context
8768 * @nargs: the number of arguments
8769 *
8770 * Implement the string-length() XPath function
8771 * number string-length(string?)
8772 * The string-length returns the number of characters in the string
8773 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8774 * the context node converted to a string, in other words the value
8775 * of the context node.
8776 */
8777void
8778xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8779 xmlXPathObjectPtr cur;
8780
8781 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008782 if ((ctxt == NULL) || (ctxt->context == NULL))
8783 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008784 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008785 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008786 } else {
8787 xmlChar *content;
8788
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008789 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8791 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008792 xmlFree(content);
8793 }
8794 return;
8795 }
8796 CHECK_ARITY(1);
8797 CAST_TO_STRING;
8798 CHECK_TYPE(XPATH_STRING);
8799 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008800 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8801 xmlUTF8Strlen(cur->stringval)));
8802 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008803}
8804
8805/**
8806 * xmlXPathConcatFunction:
8807 * @ctxt: the XPath Parser context
8808 * @nargs: the number of arguments
8809 *
8810 * Implement the concat() XPath function
8811 * string concat(string, string, string*)
8812 * The concat function returns the concatenation of its arguments.
8813 */
8814void
8815xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8816 xmlXPathObjectPtr cur, newobj;
8817 xmlChar *tmp;
8818
Daniel Veillarda82b1822004-11-08 16:24:57 +00008819 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008820 if (nargs < 2) {
8821 CHECK_ARITY(2);
8822 }
8823
8824 CAST_TO_STRING;
8825 cur = valuePop(ctxt);
8826 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008827 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008828 return;
8829 }
8830 nargs--;
8831
8832 while (nargs > 0) {
8833 CAST_TO_STRING;
8834 newobj = valuePop(ctxt);
8835 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008836 xmlXPathReleaseObject(ctxt->context, newobj);
8837 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008838 XP_ERROR(XPATH_INVALID_TYPE);
8839 }
8840 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8841 newobj->stringval = cur->stringval;
8842 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008843 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008844 nargs--;
8845 }
8846 valuePush(ctxt, cur);
8847}
8848
8849/**
8850 * xmlXPathContainsFunction:
8851 * @ctxt: the XPath Parser context
8852 * @nargs: the number of arguments
8853 *
8854 * Implement the contains() XPath function
8855 * boolean contains(string, string)
8856 * The contains function returns true if the first argument string
8857 * contains the second argument string, and otherwise returns false.
8858 */
8859void
8860xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8861 xmlXPathObjectPtr hay, needle;
8862
8863 CHECK_ARITY(2);
8864 CAST_TO_STRING;
8865 CHECK_TYPE(XPATH_STRING);
8866 needle = valuePop(ctxt);
8867 CAST_TO_STRING;
8868 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008869
Owen Taylor3473f882001-02-23 17:55:21 +00008870 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008871 xmlXPathReleaseObject(ctxt->context, hay);
8872 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008873 XP_ERROR(XPATH_INVALID_TYPE);
8874 }
8875 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008876 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008877 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008878 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8879 xmlXPathReleaseObject(ctxt->context, hay);
8880 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008881}
8882
8883/**
8884 * xmlXPathStartsWithFunction:
8885 * @ctxt: the XPath Parser context
8886 * @nargs: the number of arguments
8887 *
8888 * Implement the starts-with() XPath function
8889 * boolean starts-with(string, string)
8890 * The starts-with function returns true if the first argument string
8891 * starts with the second argument string, and otherwise returns false.
8892 */
8893void
8894xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8895 xmlXPathObjectPtr hay, needle;
8896 int n;
8897
8898 CHECK_ARITY(2);
8899 CAST_TO_STRING;
8900 CHECK_TYPE(XPATH_STRING);
8901 needle = valuePop(ctxt);
8902 CAST_TO_STRING;
8903 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008904
Owen Taylor3473f882001-02-23 17:55:21 +00008905 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008906 xmlXPathReleaseObject(ctxt->context, hay);
8907 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008908 XP_ERROR(XPATH_INVALID_TYPE);
8909 }
8910 n = xmlStrlen(needle->stringval);
8911 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008912 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008913 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008914 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8915 xmlXPathReleaseObject(ctxt->context, hay);
8916 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008917}
8918
8919/**
8920 * xmlXPathSubstringFunction:
8921 * @ctxt: the XPath Parser context
8922 * @nargs: the number of arguments
8923 *
8924 * Implement the substring() XPath function
8925 * string substring(string, number, number?)
8926 * The substring function returns the substring of the first argument
8927 * starting at the position specified in the second argument with
8928 * length specified in the third argument. For example,
8929 * substring("12345",2,3) returns "234". If the third argument is not
8930 * specified, it returns the substring starting at the position specified
8931 * in the second argument and continuing to the end of the string. For
8932 * example, substring("12345",2) returns "2345". More precisely, each
8933 * character in the string (see [3.6 Strings]) is considered to have a
8934 * numeric position: the position of the first character is 1, the position
8935 * of the second character is 2 and so on. The returned substring contains
8936 * those characters for which the position of the character is greater than
8937 * or equal to the second argument and, if the third argument is specified,
8938 * less than the sum of the second and third arguments; the comparisons
8939 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8940 * - substring("12345", 1.5, 2.6) returns "234"
8941 * - substring("12345", 0, 3) returns "12"
8942 * - substring("12345", 0 div 0, 3) returns ""
8943 * - substring("12345", 1, 0 div 0) returns ""
8944 * - substring("12345", -42, 1 div 0) returns "12345"
8945 * - substring("12345", -1 div 0, 1 div 0) returns ""
8946 */
8947void
8948xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8949 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008950 double le=0, in;
8951 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008952 xmlChar *ret;
8953
Owen Taylor3473f882001-02-23 17:55:21 +00008954 if (nargs < 2) {
8955 CHECK_ARITY(2);
8956 }
8957 if (nargs > 3) {
8958 CHECK_ARITY(3);
8959 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008960 /*
8961 * take care of possible last (position) argument
8962 */
Owen Taylor3473f882001-02-23 17:55:21 +00008963 if (nargs == 3) {
8964 CAST_TO_NUMBER;
8965 CHECK_TYPE(XPATH_NUMBER);
8966 len = valuePop(ctxt);
8967 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008968 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008969 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008970
Owen Taylor3473f882001-02-23 17:55:21 +00008971 CAST_TO_NUMBER;
8972 CHECK_TYPE(XPATH_NUMBER);
8973 start = valuePop(ctxt);
8974 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008975 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008976 CAST_TO_STRING;
8977 CHECK_TYPE(XPATH_STRING);
8978 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008979 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008980
Daniel Veillard97ac1312001-05-30 19:14:17 +00008981 /*
8982 * If last pos not present, calculate last position
8983 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008984 if (nargs != 3) {
8985 le = (double)m;
8986 if (in < 1.0)
8987 in = 1.0;
8988 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008989
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008990 /* Need to check for the special cases where either
8991 * the index is NaN, the length is NaN, or both
8992 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008993 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008994 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008995 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008996 * To meet the requirements of the spec, the arguments
8997 * must be converted to integer format before
8998 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008999 *
Daniel Veillard9e412302002-06-10 15:59:44 +00009000 * First we go to integer form, rounding up
9001 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009002 */
9003 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00009004 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00009005
Daniel Veillard9e412302002-06-10 15:59:44 +00009006 if (xmlXPathIsInf(le) == 1) {
9007 l = m;
9008 if (i < 1)
9009 i = 1;
9010 }
9011 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9012 l = 0;
9013 else {
9014 l = (int) le;
9015 if (((double)l)+0.5 <= le) l++;
9016 }
9017
9018 /* Now we normalize inidices */
9019 i -= 1;
9020 l += i;
9021 if (i < 0)
9022 i = 0;
9023 if (l > m)
9024 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00009025
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009026 /* number of chars to copy */
9027 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00009028
Daniel Veillard0eafdef2002-04-10 16:14:34 +00009029 ret = xmlUTF8Strsub(str->stringval, i, l);
9030 }
9031 else {
9032 ret = NULL;
9033 }
Owen Taylor3473f882001-02-23 17:55:21 +00009034 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009035 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00009036 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009037 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009038 xmlFree(ret);
9039 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009040 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00009041}
9042
9043/**
9044 * xmlXPathSubstringBeforeFunction:
9045 * @ctxt: the XPath Parser context
9046 * @nargs: the number of arguments
9047 *
9048 * Implement the substring-before() XPath function
9049 * string substring-before(string, string)
9050 * The substring-before function returns the substring of the first
9051 * argument string that precedes the first occurrence of the second
9052 * argument string in the first argument string, or the empty string
9053 * if the first argument string does not contain the second argument
9054 * string. For example, substring-before("1999/04/01","/") returns 1999.
9055 */
9056void
9057xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9058 xmlXPathObjectPtr str;
9059 xmlXPathObjectPtr find;
9060 xmlBufferPtr target;
9061 const xmlChar *point;
9062 int offset;
9063
9064 CHECK_ARITY(2);
9065 CAST_TO_STRING;
9066 find = valuePop(ctxt);
9067 CAST_TO_STRING;
9068 str = valuePop(ctxt);
9069
9070 target = xmlBufferCreate();
9071 if (target) {
9072 point = xmlStrstr(str->stringval, find->stringval);
9073 if (point) {
9074 offset = (int)(point - str->stringval);
9075 xmlBufferAdd(target, str->stringval, offset);
9076 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009077 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9078 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009079 xmlBufferFree(target);
9080 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009081 xmlXPathReleaseObject(ctxt->context, str);
9082 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009083}
9084
9085/**
9086 * xmlXPathSubstringAfterFunction:
9087 * @ctxt: the XPath Parser context
9088 * @nargs: the number of arguments
9089 *
9090 * Implement the substring-after() XPath function
9091 * string substring-after(string, string)
9092 * The substring-after function returns the substring of the first
9093 * argument string that follows the first occurrence of the second
9094 * argument string in the first argument string, or the empty stringi
9095 * if the first argument string does not contain the second argument
9096 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9097 * and substring-after("1999/04/01","19") returns 99/04/01.
9098 */
9099void
9100xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9101 xmlXPathObjectPtr str;
9102 xmlXPathObjectPtr find;
9103 xmlBufferPtr target;
9104 const xmlChar *point;
9105 int offset;
9106
9107 CHECK_ARITY(2);
9108 CAST_TO_STRING;
9109 find = valuePop(ctxt);
9110 CAST_TO_STRING;
9111 str = valuePop(ctxt);
9112
9113 target = xmlBufferCreate();
9114 if (target) {
9115 point = xmlStrstr(str->stringval, find->stringval);
9116 if (point) {
9117 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9118 xmlBufferAdd(target, &str->stringval[offset],
9119 xmlStrlen(str->stringval) - offset);
9120 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009121 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9122 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009123 xmlBufferFree(target);
9124 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009125 xmlXPathReleaseObject(ctxt->context, str);
9126 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00009127}
9128
9129/**
9130 * xmlXPathNormalizeFunction:
9131 * @ctxt: the XPath Parser context
9132 * @nargs: the number of arguments
9133 *
9134 * Implement the normalize-space() XPath function
9135 * string normalize-space(string?)
9136 * The normalize-space function returns the argument string with white
9137 * space normalized by stripping leading and trailing whitespace
9138 * and replacing sequences of whitespace characters by a single
9139 * space. Whitespace characters are the same allowed by the S production
9140 * in XML. If the argument is omitted, it defaults to the context
9141 * node converted to a string, in other words the value of the context node.
9142 */
9143void
9144xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9145 xmlXPathObjectPtr obj = NULL;
9146 xmlChar *source = NULL;
9147 xmlBufferPtr target;
9148 xmlChar blank;
9149
Daniel Veillarda82b1822004-11-08 16:24:57 +00009150 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009151 if (nargs == 0) {
9152 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009153 valuePush(ctxt,
9154 xmlXPathCacheWrapString(ctxt->context,
9155 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00009156 nargs = 1;
9157 }
9158
9159 CHECK_ARITY(1);
9160 CAST_TO_STRING;
9161 CHECK_TYPE(XPATH_STRING);
9162 obj = valuePop(ctxt);
9163 source = obj->stringval;
9164
9165 target = xmlBufferCreate();
9166 if (target && source) {
9167
9168 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00009169 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00009170 source++;
9171
9172 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9173 blank = 0;
9174 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00009175 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009176 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00009177 } else {
9178 if (blank) {
9179 xmlBufferAdd(target, &blank, 1);
9180 blank = 0;
9181 }
9182 xmlBufferAdd(target, source, 1);
9183 }
9184 source++;
9185 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009186 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9187 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00009188 xmlBufferFree(target);
9189 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009190 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00009191}
9192
9193/**
9194 * xmlXPathTranslateFunction:
9195 * @ctxt: the XPath Parser context
9196 * @nargs: the number of arguments
9197 *
9198 * Implement the translate() XPath function
9199 * string translate(string, string, string)
9200 * The translate function returns the first argument string with
9201 * occurrences of characters in the second argument string replaced
9202 * by the character at the corresponding position in the third argument
9203 * string. For example, translate("bar","abc","ABC") returns the string
9204 * BAr. If there is a character in the second argument string with no
9205 * character at a corresponding position in the third argument string
9206 * (because the second argument string is longer than the third argument
9207 * string), then occurrences of that character in the first argument
9208 * string are removed. For example, translate("--aaa--","abc-","ABC")
9209 * returns "AAA". If a character occurs more than once in second
9210 * argument string, then the first occurrence determines the replacement
9211 * character. If the third argument string is longer than the second
9212 * argument string, then excess characters are ignored.
9213 */
9214void
9215xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00009216 xmlXPathObjectPtr str;
9217 xmlXPathObjectPtr from;
9218 xmlXPathObjectPtr to;
9219 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009220 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009221 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00009222 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00009223 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00009224
Daniel Veillarde043ee12001-04-16 14:08:07 +00009225 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00009226
Daniel Veillarde043ee12001-04-16 14:08:07 +00009227 CAST_TO_STRING;
9228 to = valuePop(ctxt);
9229 CAST_TO_STRING;
9230 from = valuePop(ctxt);
9231 CAST_TO_STRING;
9232 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009233
Daniel Veillarde043ee12001-04-16 14:08:07 +00009234 target = xmlBufferCreate();
9235 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00009236 max = xmlUTF8Strlen(to->stringval);
9237 for (cptr = str->stringval; (ch=*cptr); ) {
9238 offset = xmlUTF8Strloc(from->stringval, cptr);
9239 if (offset >= 0) {
9240 if (offset < max) {
9241 point = xmlUTF8Strpos(to->stringval, offset);
9242 if (point)
9243 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9244 }
9245 } else
9246 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9247
9248 /* Step to next character in input */
9249 cptr++;
9250 if ( ch & 0x80 ) {
9251 /* if not simple ascii, verify proper format */
9252 if ( (ch & 0xc0) != 0xc0 ) {
9253 xmlGenericError(xmlGenericErrorContext,
9254 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9255 break;
9256 }
9257 /* then skip over remaining bytes for this char */
9258 while ( (ch <<= 1) & 0x80 )
9259 if ( (*cptr++ & 0xc0) != 0x80 ) {
9260 xmlGenericError(xmlGenericErrorContext,
9261 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9262 break;
9263 }
9264 if (ch & 0x80) /* must have had error encountered */
9265 break;
9266 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009267 }
Owen Taylor3473f882001-02-23 17:55:21 +00009268 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009269 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9270 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009271 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009272 xmlXPathReleaseObject(ctxt->context, str);
9273 xmlXPathReleaseObject(ctxt->context, from);
9274 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009275}
9276
9277/**
9278 * xmlXPathBooleanFunction:
9279 * @ctxt: the XPath Parser context
9280 * @nargs: the number of arguments
9281 *
9282 * Implement the boolean() XPath function
9283 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009284 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009285 * - a number is true if and only if it is neither positive or
9286 * negative zero nor NaN
9287 * - a node-set is true if and only if it is non-empty
9288 * - a string is true if and only if its length is non-zero
9289 */
9290void
9291xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9292 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009293
9294 CHECK_ARITY(1);
9295 cur = valuePop(ctxt);
9296 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009297 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009298 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009299}
9300
9301/**
9302 * xmlXPathNotFunction:
9303 * @ctxt: the XPath Parser context
9304 * @nargs: the number of arguments
9305 *
9306 * Implement the not() XPath function
9307 * boolean not(boolean)
9308 * The not function returns true if its argument is false,
9309 * and false otherwise.
9310 */
9311void
9312xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9313 CHECK_ARITY(1);
9314 CAST_TO_BOOLEAN;
9315 CHECK_TYPE(XPATH_BOOLEAN);
9316 ctxt->value->boolval = ! ctxt->value->boolval;
9317}
9318
9319/**
9320 * xmlXPathTrueFunction:
9321 * @ctxt: the XPath Parser context
9322 * @nargs: the number of arguments
9323 *
9324 * Implement the true() XPath function
9325 * boolean true()
9326 */
9327void
9328xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9329 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009330 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009331}
9332
9333/**
9334 * xmlXPathFalseFunction:
9335 * @ctxt: the XPath Parser context
9336 * @nargs: the number of arguments
9337 *
9338 * Implement the false() XPath function
9339 * boolean false()
9340 */
9341void
9342xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9343 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009344 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009345}
9346
9347/**
9348 * xmlXPathLangFunction:
9349 * @ctxt: the XPath Parser context
9350 * @nargs: the number of arguments
9351 *
9352 * Implement the lang() XPath function
9353 * boolean lang(string)
9354 * The lang function returns true or false depending on whether the
9355 * language of the context node as specified by xml:lang attributes
9356 * is the same as or is a sublanguage of the language specified by
9357 * the argument string. The language of the context node is determined
9358 * by the value of the xml:lang attribute on the context node, or, if
9359 * the context node has no xml:lang attribute, by the value of the
9360 * xml:lang attribute on the nearest ancestor of the context node that
9361 * has an xml:lang attribute. If there is no such attribute, then lang
9362 * returns false. If there is such an attribute, then lang returns
9363 * true if the attribute value is equal to the argument ignoring case,
9364 * or if there is some suffix starting with - such that the attribute
9365 * value is equal to the argument ignoring that suffix of the attribute
9366 * value and ignoring case.
9367 */
9368void
9369xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009370 xmlXPathObjectPtr val = NULL;
9371 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009372 const xmlChar *lang;
9373 int ret = 0;
9374 int i;
9375
9376 CHECK_ARITY(1);
9377 CAST_TO_STRING;
9378 CHECK_TYPE(XPATH_STRING);
9379 val = valuePop(ctxt);
9380 lang = val->stringval;
9381 theLang = xmlNodeGetLang(ctxt->context->node);
9382 if ((theLang != NULL) && (lang != NULL)) {
9383 for (i = 0;lang[i] != 0;i++)
9384 if (toupper(lang[i]) != toupper(theLang[i]))
9385 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009386 if ((theLang[i] == 0) || (theLang[i] == '-'))
9387 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009388 }
9389not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009390 if (theLang != NULL)
9391 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009392
9393 xmlXPathReleaseObject(ctxt->context, val);
9394 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009395}
9396
9397/**
9398 * xmlXPathNumberFunction:
9399 * @ctxt: the XPath Parser context
9400 * @nargs: the number of arguments
9401 *
9402 * Implement the number() XPath function
9403 * number number(object?)
9404 */
9405void
9406xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9407 xmlXPathObjectPtr cur;
9408 double res;
9409
Daniel Veillarda82b1822004-11-08 16:24:57 +00009410 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009411 if (nargs == 0) {
9412 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009413 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009414 } else {
9415 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9416
9417 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009418 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009419 xmlFree(content);
9420 }
9421 return;
9422 }
9423
9424 CHECK_ARITY(1);
9425 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009426 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009427}
9428
9429/**
9430 * xmlXPathSumFunction:
9431 * @ctxt: the XPath Parser context
9432 * @nargs: the number of arguments
9433 *
9434 * Implement the sum() XPath function
9435 * number sum(node-set)
9436 * The sum function returns the sum of the values of the nodes in
9437 * the argument node-set.
9438 */
9439void
9440xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9441 xmlXPathObjectPtr cur;
9442 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009443 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009444
9445 CHECK_ARITY(1);
9446 if ((ctxt->value == NULL) ||
9447 ((ctxt->value->type != XPATH_NODESET) &&
9448 (ctxt->value->type != XPATH_XSLT_TREE)))
9449 XP_ERROR(XPATH_INVALID_TYPE);
9450 cur = valuePop(ctxt);
9451
William M. Brack08171912003-12-29 02:52:11 +00009452 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009453 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9454 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009455 }
9456 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009457 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9458 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009459}
9460
William M. Brack3d426662005-04-19 14:40:28 +00009461/*
9462 * To assure working code on multiple platforms, we want to only depend
9463 * upon the characteristic truncation of converting a floating point value
9464 * to an integer. Unfortunately, because of the different storage sizes
9465 * of our internal floating point value (double) and integer (int), we
9466 * can't directly convert (see bug 301162). This macro is a messy
9467 * 'workaround'
9468 */
9469#define XTRUNC(f, v) \
9470 f = fmod((v), INT_MAX); \
9471 f = (v) - (f) + (double)((int)(f));
9472
Owen Taylor3473f882001-02-23 17:55:21 +00009473/**
9474 * xmlXPathFloorFunction:
9475 * @ctxt: the XPath Parser context
9476 * @nargs: the number of arguments
9477 *
9478 * Implement the floor() XPath function
9479 * number floor(number)
9480 * The floor function returns the largest (closest to positive infinity)
9481 * number that is not greater than the argument and that is an integer.
9482 */
9483void
9484xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009485 double f;
9486
Owen Taylor3473f882001-02-23 17:55:21 +00009487 CHECK_ARITY(1);
9488 CAST_TO_NUMBER;
9489 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009490
William M. Brack3d426662005-04-19 14:40:28 +00009491 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009492 if (f != ctxt->value->floatval) {
9493 if (ctxt->value->floatval > 0)
9494 ctxt->value->floatval = f;
9495 else
9496 ctxt->value->floatval = f - 1;
9497 }
Owen Taylor3473f882001-02-23 17:55:21 +00009498}
9499
9500/**
9501 * xmlXPathCeilingFunction:
9502 * @ctxt: the XPath Parser context
9503 * @nargs: the number of arguments
9504 *
9505 * Implement the ceiling() XPath function
9506 * number ceiling(number)
9507 * The ceiling function returns the smallest (closest to negative infinity)
9508 * number that is not less than the argument and that is an integer.
9509 */
9510void
9511xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9512 double f;
9513
9514 CHECK_ARITY(1);
9515 CAST_TO_NUMBER;
9516 CHECK_TYPE(XPATH_NUMBER);
9517
9518#if 0
9519 ctxt->value->floatval = ceil(ctxt->value->floatval);
9520#else
William M. Brack3d426662005-04-19 14:40:28 +00009521 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009522 if (f != ctxt->value->floatval) {
9523 if (ctxt->value->floatval > 0)
9524 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009525 else {
9526 if (ctxt->value->floatval < 0 && f == 0)
9527 ctxt->value->floatval = xmlXPathNZERO;
9528 else
9529 ctxt->value->floatval = f;
9530 }
9531
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009532 }
Owen Taylor3473f882001-02-23 17:55:21 +00009533#endif
9534}
9535
9536/**
9537 * xmlXPathRoundFunction:
9538 * @ctxt: the XPath Parser context
9539 * @nargs: the number of arguments
9540 *
9541 * Implement the round() XPath function
9542 * number round(number)
9543 * The round function returns the number that is closest to the
9544 * argument and that is an integer. If there are two such numbers,
9545 * then the one that is even is returned.
9546 */
9547void
9548xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9549 double f;
9550
9551 CHECK_ARITY(1);
9552 CAST_TO_NUMBER;
9553 CHECK_TYPE(XPATH_NUMBER);
9554
Daniel Veillardcda96922001-08-21 10:56:31 +00009555 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9556 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9557 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009558 (ctxt->value->floatval == 0.0))
9559 return;
9560
William M. Brack3d426662005-04-19 14:40:28 +00009561 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009562 if (ctxt->value->floatval < 0) {
9563 if (ctxt->value->floatval < f - 0.5)
9564 ctxt->value->floatval = f - 1;
9565 else
9566 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009567 if (ctxt->value->floatval == 0)
9568 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009569 } else {
9570 if (ctxt->value->floatval < f + 0.5)
9571 ctxt->value->floatval = f;
9572 else
9573 ctxt->value->floatval = f + 1;
9574 }
Owen Taylor3473f882001-02-23 17:55:21 +00009575}
9576
9577/************************************************************************
9578 * *
9579 * The Parser *
9580 * *
9581 ************************************************************************/
9582
9583/*
William M. Brack08171912003-12-29 02:52:11 +00009584 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009585 * implementation.
9586 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009587static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009588static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009589static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009590static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009591static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9592 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009593
9594/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009595 * xmlXPathCurrentChar:
9596 * @ctxt: the XPath parser context
9597 * @cur: pointer to the beginning of the char
9598 * @len: pointer to the length of the char read
9599 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009600 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009601 * bytes in the input buffer.
9602 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009603 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009604 */
9605
9606static int
9607xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9608 unsigned char c;
9609 unsigned int val;
9610 const xmlChar *cur;
9611
9612 if (ctxt == NULL)
9613 return(0);
9614 cur = ctxt->cur;
9615
9616 /*
9617 * We are supposed to handle UTF8, check it's valid
9618 * From rfc2044: encoding of the Unicode values on UTF-8:
9619 *
9620 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9621 * 0000 0000-0000 007F 0xxxxxxx
9622 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9623 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9624 *
9625 * Check for the 0x110000 limit too
9626 */
9627 c = *cur;
9628 if (c & 0x80) {
9629 if ((cur[1] & 0xc0) != 0x80)
9630 goto encoding_error;
9631 if ((c & 0xe0) == 0xe0) {
9632
9633 if ((cur[2] & 0xc0) != 0x80)
9634 goto encoding_error;
9635 if ((c & 0xf0) == 0xf0) {
9636 if (((c & 0xf8) != 0xf0) ||
9637 ((cur[3] & 0xc0) != 0x80))
9638 goto encoding_error;
9639 /* 4-byte code */
9640 *len = 4;
9641 val = (cur[0] & 0x7) << 18;
9642 val |= (cur[1] & 0x3f) << 12;
9643 val |= (cur[2] & 0x3f) << 6;
9644 val |= cur[3] & 0x3f;
9645 } else {
9646 /* 3-byte code */
9647 *len = 3;
9648 val = (cur[0] & 0xf) << 12;
9649 val |= (cur[1] & 0x3f) << 6;
9650 val |= cur[2] & 0x3f;
9651 }
9652 } else {
9653 /* 2-byte code */
9654 *len = 2;
9655 val = (cur[0] & 0x1f) << 6;
9656 val |= cur[1] & 0x3f;
9657 }
9658 if (!IS_CHAR(val)) {
9659 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9660 }
9661 return(val);
9662 } else {
9663 /* 1-byte code */
9664 *len = 1;
9665 return((int) *cur);
9666 }
9667encoding_error:
9668 /*
William M. Brack08171912003-12-29 02:52:11 +00009669 * If we detect an UTF8 error that probably means that the
9670 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009671 * declaration header. Report the error and switch the encoding
9672 * to ISO-Latin-1 (if you don't like this policy, just declare the
9673 * encoding !)
9674 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009675 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009676 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009677}
9678
9679/**
Owen Taylor3473f882001-02-23 17:55:21 +00009680 * xmlXPathParseNCName:
9681 * @ctxt: the XPath Parser context
9682 *
9683 * parse an XML namespace non qualified name.
9684 *
9685 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9686 *
9687 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9688 * CombiningChar | Extender
9689 *
9690 * Returns the namespace name or NULL
9691 */
9692
9693xmlChar *
9694xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009695 const xmlChar *in;
9696 xmlChar *ret;
9697 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009698
Daniel Veillarda82b1822004-11-08 16:24:57 +00009699 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009700 /*
9701 * Accelerator for simple ASCII names
9702 */
9703 in = ctxt->cur;
9704 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9705 ((*in >= 0x41) && (*in <= 0x5A)) ||
9706 (*in == '_')) {
9707 in++;
9708 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9709 ((*in >= 0x41) && (*in <= 0x5A)) ||
9710 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009711 (*in == '_') || (*in == '.') ||
9712 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009713 in++;
9714 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9715 (*in == '[') || (*in == ']') || (*in == ':') ||
9716 (*in == '@') || (*in == '*')) {
9717 count = in - ctxt->cur;
9718 if (count == 0)
9719 return(NULL);
9720 ret = xmlStrndup(ctxt->cur, count);
9721 ctxt->cur = in;
9722 return(ret);
9723 }
9724 }
9725 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009726}
9727
Daniel Veillard2156a562001-04-28 12:24:34 +00009728
Owen Taylor3473f882001-02-23 17:55:21 +00009729/**
9730 * xmlXPathParseQName:
9731 * @ctxt: the XPath Parser context
9732 * @prefix: a xmlChar **
9733 *
9734 * parse an XML qualified name
9735 *
9736 * [NS 5] QName ::= (Prefix ':')? LocalPart
9737 *
9738 * [NS 6] Prefix ::= NCName
9739 *
9740 * [NS 7] LocalPart ::= NCName
9741 *
9742 * Returns the function returns the local part, and prefix is updated
9743 * to get the Prefix if any.
9744 */
9745
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009746static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009747xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9748 xmlChar *ret = NULL;
9749
9750 *prefix = NULL;
9751 ret = xmlXPathParseNCName(ctxt);
9752 if (CUR == ':') {
9753 *prefix = ret;
9754 NEXT;
9755 ret = xmlXPathParseNCName(ctxt);
9756 }
9757 return(ret);
9758}
9759
9760/**
9761 * xmlXPathParseName:
9762 * @ctxt: the XPath Parser context
9763 *
9764 * parse an XML name
9765 *
9766 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9767 * CombiningChar | Extender
9768 *
9769 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9770 *
9771 * Returns the namespace name or NULL
9772 */
9773
9774xmlChar *
9775xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009776 const xmlChar *in;
9777 xmlChar *ret;
9778 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009779
Daniel Veillarda82b1822004-11-08 16:24:57 +00009780 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009781 /*
9782 * Accelerator for simple ASCII names
9783 */
9784 in = ctxt->cur;
9785 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9786 ((*in >= 0x41) && (*in <= 0x5A)) ||
9787 (*in == '_') || (*in == ':')) {
9788 in++;
9789 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9790 ((*in >= 0x41) && (*in <= 0x5A)) ||
9791 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009792 (*in == '_') || (*in == '-') ||
9793 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009794 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009795 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009796 count = in - ctxt->cur;
9797 ret = xmlStrndup(ctxt->cur, count);
9798 ctxt->cur = in;
9799 return(ret);
9800 }
9801 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009802 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009803}
9804
Daniel Veillard61d80a22001-04-27 17:13:01 +00009805static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009806xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009807 xmlChar buf[XML_MAX_NAMELEN + 5];
9808 int len = 0, l;
9809 int c;
9810
9811 /*
9812 * Handler for more complex cases
9813 */
9814 c = CUR_CHAR(l);
9815 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009816 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9817 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009818 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009819 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009820 return(NULL);
9821 }
9822
9823 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9824 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9825 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009826 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009827 (IS_COMBINING(c)) ||
9828 (IS_EXTENDER(c)))) {
9829 COPY_BUF(l,buf,len,c);
9830 NEXTL(l);
9831 c = CUR_CHAR(l);
9832 if (len >= XML_MAX_NAMELEN) {
9833 /*
9834 * Okay someone managed to make a huge name, so he's ready to pay
9835 * for the processing speed.
9836 */
9837 xmlChar *buffer;
9838 int max = len * 2;
9839
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009840 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009841 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009842 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009843 }
9844 memcpy(buffer, buf, len);
9845 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9846 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009847 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009848 (IS_COMBINING(c)) ||
9849 (IS_EXTENDER(c))) {
9850 if (len + 10 > max) {
9851 max *= 2;
9852 buffer = (xmlChar *) xmlRealloc(buffer,
9853 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009854 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009855 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009856 }
9857 }
9858 COPY_BUF(l,buffer,len,c);
9859 NEXTL(l);
9860 c = CUR_CHAR(l);
9861 }
9862 buffer[len] = 0;
9863 return(buffer);
9864 }
9865 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009866 if (len == 0)
9867 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009868 return(xmlStrndup(buf, len));
9869}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009870
9871#define MAX_FRAC 20
9872
William M. Brack372a4452004-02-17 13:09:23 +00009873/*
9874 * These are used as divisors for the fractional part of a number.
9875 * Since the table includes 1.0 (representing '0' fractional digits),
9876 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9877 */
9878static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009879 1.0, 10.0, 100.0, 1000.0, 10000.0,
9880 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9881 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9882 100000000000000.0,
9883 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009884 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009885};
9886
Owen Taylor3473f882001-02-23 17:55:21 +00009887/**
9888 * xmlXPathStringEvalNumber:
9889 * @str: A string to scan
9890 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009891 * [30a] Float ::= Number ('e' Digits?)?
9892 *
Owen Taylor3473f882001-02-23 17:55:21 +00009893 * [30] Number ::= Digits ('.' Digits?)?
9894 * | '.' Digits
9895 * [31] Digits ::= [0-9]+
9896 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009897 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009898 * In complement of the Number expression, this function also handles
9899 * negative values : '-' Number.
9900 *
9901 * Returns the double value.
9902 */
9903double
9904xmlXPathStringEvalNumber(const xmlChar *str) {
9905 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009906 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009907 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009908 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009909 int exponent = 0;
9910 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009911#ifdef __GNUC__
9912 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009913 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009914#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009915 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009916 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009917 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9918 return(xmlXPathNAN);
9919 }
9920 if (*cur == '-') {
9921 isneg = 1;
9922 cur++;
9923 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009924
9925#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009926 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009927 * tmp/temp is a workaround against a gcc compiler bug
9928 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009929 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009930 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009931 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009932 ret = ret * 10;
9933 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009934 ok = 1;
9935 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009936 temp = (double) tmp;
9937 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009938 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009939#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009940 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009941 while ((*cur >= '0') && (*cur <= '9')) {
9942 ret = ret * 10 + (*cur - '0');
9943 ok = 1;
9944 cur++;
9945 }
9946#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009947
Owen Taylor3473f882001-02-23 17:55:21 +00009948 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009949 int v, frac = 0;
9950 double fraction = 0;
9951
Owen Taylor3473f882001-02-23 17:55:21 +00009952 cur++;
9953 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9954 return(xmlXPathNAN);
9955 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009956 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9957 v = (*cur - '0');
9958 fraction = fraction * 10 + v;
9959 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009960 cur++;
9961 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009962 fraction /= my_pow10[frac];
9963 ret = ret + fraction;
9964 while ((*cur >= '0') && (*cur <= '9'))
9965 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009966 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009967 if ((*cur == 'e') || (*cur == 'E')) {
9968 cur++;
9969 if (*cur == '-') {
9970 is_exponent_negative = 1;
9971 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009972 } else if (*cur == '+') {
9973 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009974 }
9975 while ((*cur >= '0') && (*cur <= '9')) {
9976 exponent = exponent * 10 + (*cur - '0');
9977 cur++;
9978 }
9979 }
William M. Brack76e95df2003-10-18 16:20:14 +00009980 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009981 if (*cur != 0) return(xmlXPathNAN);
9982 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009983 if (is_exponent_negative) exponent = -exponent;
9984 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009985 return(ret);
9986}
9987
9988/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009989 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009990 * @ctxt: the XPath Parser context
9991 *
9992 * [30] Number ::= Digits ('.' Digits?)?
9993 * | '.' Digits
9994 * [31] Digits ::= [0-9]+
9995 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009996 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009997 *
9998 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009999static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010000xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10001{
Owen Taylor3473f882001-02-23 17:55:21 +000010002 double ret = 0.0;
10003 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +000010004 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +000010005 int exponent = 0;
10006 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +000010007#ifdef __GNUC__
10008 unsigned long tmp = 0;
10009 double temp;
10010#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010011
10012 CHECK_ERROR;
10013 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10014 XP_ERROR(XPATH_NUMBER_ERROR);
10015 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010016#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010017 /*
Daniel Veillard7b416132002-03-07 08:36:03 +000010018 * tmp/temp is a workaround against a gcc compiler bug
10019 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010020 */
Daniel Veillard7b416132002-03-07 08:36:03 +000010021 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010022 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +000010023 ret = ret * 10;
10024 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010025 ok = 1;
10026 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +000010027 temp = (double) tmp;
10028 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +000010029 }
Daniel Veillard7b416132002-03-07 08:36:03 +000010030#else
10031 ret = 0;
10032 while ((CUR >= '0') && (CUR <= '9')) {
10033 ret = ret * 10 + (CUR - '0');
10034 ok = 1;
10035 NEXT;
10036 }
10037#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010038 if (CUR == '.') {
10039 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010040 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10041 XP_ERROR(XPATH_NUMBER_ERROR);
10042 }
10043 while ((CUR >= '0') && (CUR <= '9')) {
10044 mult /= 10;
10045 ret = ret + (CUR - '0') * mult;
10046 NEXT;
10047 }
Owen Taylor3473f882001-02-23 17:55:21 +000010048 }
Bjorn Reese70a9da52001-04-21 16:57:29 +000010049 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010050 NEXT;
10051 if (CUR == '-') {
10052 is_exponent_negative = 1;
10053 NEXT;
William M. Brack99127052004-05-24 02:52:28 +000010054 } else if (CUR == '+') {
10055 NEXT;
10056 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +000010057 while ((CUR >= '0') && (CUR <= '9')) {
10058 exponent = exponent * 10 + (CUR - '0');
10059 NEXT;
10060 }
10061 if (is_exponent_negative)
10062 exponent = -exponent;
10063 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +000010064 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010065 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010066 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010067}
10068
10069/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010070 * xmlXPathParseLiteral:
10071 * @ctxt: the XPath Parser context
10072 *
10073 * Parse a Literal
10074 *
10075 * [29] Literal ::= '"' [^"]* '"'
10076 * | "'" [^']* "'"
10077 *
10078 * Returns the value found or NULL in case of error
10079 */
10080static xmlChar *
10081xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10082 const xmlChar *q;
10083 xmlChar *ret = NULL;
10084
10085 if (CUR == '"') {
10086 NEXT;
10087 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010088 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010089 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010090 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010091 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010092 } else {
10093 ret = xmlStrndup(q, CUR_PTR - q);
10094 NEXT;
10095 }
10096 } else if (CUR == '\'') {
10097 NEXT;
10098 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010099 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010100 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010101 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010102 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010103 } else {
10104 ret = xmlStrndup(q, CUR_PTR - q);
10105 NEXT;
10106 }
10107 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +000010108 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010109 }
10110 return(ret);
10111}
10112
10113/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010114 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +000010115 * @ctxt: the XPath Parser context
10116 *
10117 * Parse a Literal and push it on the stack.
10118 *
10119 * [29] Literal ::= '"' [^"]* '"'
10120 * | "'" [^']* "'"
10121 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010122 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +000010123 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010124static void
10125xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010126 const xmlChar *q;
10127 xmlChar *ret = NULL;
10128
10129 if (CUR == '"') {
10130 NEXT;
10131 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010132 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +000010133 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010134 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010135 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10136 } else {
10137 ret = xmlStrndup(q, CUR_PTR - q);
10138 NEXT;
10139 }
10140 } else if (CUR == '\'') {
10141 NEXT;
10142 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +000010143 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +000010144 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +000010145 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +000010146 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10147 } else {
10148 ret = xmlStrndup(q, CUR_PTR - q);
10149 NEXT;
10150 }
10151 } else {
10152 XP_ERROR(XPATH_START_LITERAL_ERROR);
10153 }
10154 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010155 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000010156 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010157 xmlFree(ret);
10158}
10159
10160/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010161 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +000010162 * @ctxt: the XPath Parser context
10163 *
10164 * Parse a VariableReference, evaluate it and push it on the stack.
10165 *
10166 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +000010167 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +000010168 * of any of the types that are possible for the value of an expression,
10169 * and may also be of additional types not specified here.
10170 *
10171 * Early evaluation is possible since:
10172 * The variable bindings [...] used to evaluate a subexpression are
10173 * always the same as those used to evaluate the containing expression.
10174 *
10175 * [36] VariableReference ::= '$' QName
10176 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010177static void
10178xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010179 xmlChar *name;
10180 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010181
10182 SKIP_BLANKS;
10183 if (CUR != '$') {
10184 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10185 }
10186 NEXT;
10187 name = xmlXPathParseQName(ctxt, &prefix);
10188 if (name == NULL) {
10189 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10190 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010191 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010192 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10193 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010194 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +000010195 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10196 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10197 }
Owen Taylor3473f882001-02-23 17:55:21 +000010198}
10199
10200/**
10201 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +000010202 * @name: a name string
10203 *
10204 * Is the name given a NodeType one.
10205 *
10206 * [38] NodeType ::= 'comment'
10207 * | 'text'
10208 * | 'processing-instruction'
10209 * | 'node'
10210 *
10211 * Returns 1 if true 0 otherwise
10212 */
10213int
10214xmlXPathIsNodeType(const xmlChar *name) {
10215 if (name == NULL)
10216 return(0);
10217
Daniel Veillard1971ee22002-01-31 20:29:19 +000010218 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +000010219 return(1);
10220 if (xmlStrEqual(name, BAD_CAST "text"))
10221 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010222 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +000010223 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +000010224 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +000010225 return(1);
10226 return(0);
10227}
10228
10229/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010230 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +000010231 * @ctxt: the XPath Parser context
10232 *
10233 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10234 * [17] Argument ::= Expr
10235 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010236 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +000010237 * pushed on the stack
10238 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010239static void
10240xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010241 xmlChar *name;
10242 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +000010243 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010244 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010245
10246 name = xmlXPathParseQName(ctxt, &prefix);
10247 if (name == NULL) {
10248 XP_ERROR(XPATH_EXPR_ERROR);
10249 }
10250 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010251#ifdef DEBUG_EXPR
10252 if (prefix == NULL)
10253 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10254 name);
10255 else
10256 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10257 prefix, name);
10258#endif
10259
Owen Taylor3473f882001-02-23 17:55:21 +000010260 if (CUR != '(') {
10261 XP_ERROR(XPATH_EXPR_ERROR);
10262 }
10263 NEXT;
10264 SKIP_BLANKS;
10265
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010266 /*
10267 * Optimization for count(): we don't need the node-set to be sorted.
10268 */
10269 if ((prefix == NULL) && (name[0] == 'c') &&
10270 xmlStrEqual(name, BAD_CAST "count"))
10271 {
10272 sort = 0;
10273 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010274 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010275 if (CUR != ')') {
10276 while (CUR != 0) {
10277 int op1 = ctxt->comp->last;
10278 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010279 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010280 CHECK_ERROR;
10281 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10282 nbargs++;
10283 if (CUR == ')') break;
10284 if (CUR != ',') {
10285 XP_ERROR(XPATH_EXPR_ERROR);
10286 }
10287 NEXT;
10288 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010289 }
Owen Taylor3473f882001-02-23 17:55:21 +000010290 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010291 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10292 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010293 NEXT;
10294 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010295}
10296
10297/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010298 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010299 * @ctxt: the XPath Parser context
10300 *
10301 * [15] PrimaryExpr ::= VariableReference
10302 * | '(' Expr ')'
10303 * | Literal
10304 * | Number
10305 * | FunctionCall
10306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010307 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010308 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010309static void
10310xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010311 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010312 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010313 else if (CUR == '(') {
10314 NEXT;
10315 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010316 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010317 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010318 if (CUR != ')') {
10319 XP_ERROR(XPATH_EXPR_ERROR);
10320 }
10321 NEXT;
10322 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010323 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010324 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010325 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010326 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010327 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010328 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010329 }
10330 SKIP_BLANKS;
10331}
10332
10333/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010334 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010335 * @ctxt: the XPath Parser context
10336 *
10337 * [20] FilterExpr ::= PrimaryExpr
10338 * | FilterExpr Predicate
10339 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010340 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010341 * Square brackets are used to filter expressions in the same way that
10342 * they are used in location paths. It is an error if the expression to
10343 * be filtered does not evaluate to a node-set. The context node list
10344 * used for evaluating the expression in square brackets is the node-set
10345 * to be filtered listed in document order.
10346 */
10347
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010348static void
10349xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10350 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010351 CHECK_ERROR;
10352 SKIP_BLANKS;
10353
10354 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010355 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010356 SKIP_BLANKS;
10357 }
10358
10359
10360}
10361
10362/**
10363 * xmlXPathScanName:
10364 * @ctxt: the XPath Parser context
10365 *
10366 * Trickery: parse an XML name but without consuming the input flow
10367 * Needed to avoid insanity in the parser state.
10368 *
10369 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10370 * CombiningChar | Extender
10371 *
10372 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10373 *
10374 * [6] Names ::= Name (S Name)*
10375 *
10376 * Returns the Name parsed or NULL
10377 */
10378
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010379static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010380xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010381 int len = 0, l;
10382 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010383 const xmlChar *cur;
10384 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010385
Daniel Veillard03226812004-11-01 14:55:21 +000010386 cur = ctxt->cur;
10387
10388 c = CUR_CHAR(l);
10389 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10390 (!IS_LETTER(c) && (c != '_') &&
10391 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010392 return(NULL);
10393 }
10394
Daniel Veillard03226812004-11-01 14:55:21 +000010395 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10396 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10397 (c == '.') || (c == '-') ||
10398 (c == '_') || (c == ':') ||
10399 (IS_COMBINING(c)) ||
10400 (IS_EXTENDER(c)))) {
10401 len += l;
10402 NEXTL(l);
10403 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010404 }
Daniel Veillard03226812004-11-01 14:55:21 +000010405 ret = xmlStrndup(cur, ctxt->cur - cur);
10406 ctxt->cur = cur;
10407 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010408}
10409
10410/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010411 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010412 * @ctxt: the XPath Parser context
10413 *
10414 * [19] PathExpr ::= LocationPath
10415 * | FilterExpr
10416 * | FilterExpr '/' RelativeLocationPath
10417 * | FilterExpr '//' RelativeLocationPath
10418 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010419 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010420 * The / operator and // operators combine an arbitrary expression
10421 * and a relative location path. It is an error if the expression
10422 * does not evaluate to a node-set.
10423 * The / operator does composition in the same way as when / is
10424 * used in a location path. As in location paths, // is short for
10425 * /descendant-or-self::node()/.
10426 */
10427
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010428static void
10429xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010430 int lc = 1; /* Should we branch to LocationPath ? */
10431 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10432
10433 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010434 if ((CUR == '$') || (CUR == '(') ||
10435 (IS_ASCII_DIGIT(CUR)) ||
10436 (CUR == '\'') || (CUR == '"') ||
10437 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010438 lc = 0;
10439 } else if (CUR == '*') {
10440 /* relative or absolute location path */
10441 lc = 1;
10442 } else if (CUR == '/') {
10443 /* relative or absolute location path */
10444 lc = 1;
10445 } else if (CUR == '@') {
10446 /* relative abbreviated attribute location path */
10447 lc = 1;
10448 } else if (CUR == '.') {
10449 /* relative abbreviated attribute location path */
10450 lc = 1;
10451 } else {
10452 /*
10453 * Problem is finding if we have a name here whether it's:
10454 * - a nodetype
10455 * - a function call in which case it's followed by '('
10456 * - an axis in which case it's followed by ':'
10457 * - a element name
10458 * We do an a priori analysis here rather than having to
10459 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010460 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010461 * read/write/debug.
10462 */
10463 SKIP_BLANKS;
10464 name = xmlXPathScanName(ctxt);
10465 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10466#ifdef DEBUG_STEP
10467 xmlGenericError(xmlGenericErrorContext,
10468 "PathExpr: Axis\n");
10469#endif
10470 lc = 1;
10471 xmlFree(name);
10472 } else if (name != NULL) {
10473 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010474
10475
10476 while (NXT(len) != 0) {
10477 if (NXT(len) == '/') {
10478 /* element name */
10479#ifdef DEBUG_STEP
10480 xmlGenericError(xmlGenericErrorContext,
10481 "PathExpr: AbbrRelLocation\n");
10482#endif
10483 lc = 1;
10484 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010485 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010486 /* ignore blanks */
10487 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010488 } else if (NXT(len) == ':') {
10489#ifdef DEBUG_STEP
10490 xmlGenericError(xmlGenericErrorContext,
10491 "PathExpr: AbbrRelLocation\n");
10492#endif
10493 lc = 1;
10494 break;
10495 } else if ((NXT(len) == '(')) {
10496 /* Note Type or Function */
10497 if (xmlXPathIsNodeType(name)) {
10498#ifdef DEBUG_STEP
10499 xmlGenericError(xmlGenericErrorContext,
10500 "PathExpr: Type search\n");
10501#endif
10502 lc = 1;
10503 } else {
10504#ifdef DEBUG_STEP
10505 xmlGenericError(xmlGenericErrorContext,
10506 "PathExpr: function call\n");
10507#endif
10508 lc = 0;
10509 }
10510 break;
10511 } else if ((NXT(len) == '[')) {
10512 /* element name */
10513#ifdef DEBUG_STEP
10514 xmlGenericError(xmlGenericErrorContext,
10515 "PathExpr: AbbrRelLocation\n");
10516#endif
10517 lc = 1;
10518 break;
10519 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10520 (NXT(len) == '=')) {
10521 lc = 1;
10522 break;
10523 } else {
10524 lc = 1;
10525 break;
10526 }
10527 len++;
10528 }
10529 if (NXT(len) == 0) {
10530#ifdef DEBUG_STEP
10531 xmlGenericError(xmlGenericErrorContext,
10532 "PathExpr: AbbrRelLocation\n");
10533#endif
10534 /* element name */
10535 lc = 1;
10536 }
10537 xmlFree(name);
10538 } else {
William M. Brack08171912003-12-29 02:52:11 +000010539 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010540 XP_ERROR(XPATH_EXPR_ERROR);
10541 }
10542 }
10543
10544 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010545 if (CUR == '/') {
10546 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10547 } else {
10548 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010549 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010550 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010551 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010552 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010553 CHECK_ERROR;
10554 if ((CUR == '/') && (NXT(1) == '/')) {
10555 SKIP(2);
10556 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010557
10558 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10559 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10560 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10561
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010562 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010563 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010564 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010565 }
10566 }
10567 SKIP_BLANKS;
10568}
10569
10570/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010571 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010572 * @ctxt: the XPath Parser context
10573 *
10574 * [18] UnionExpr ::= PathExpr
10575 * | UnionExpr '|' PathExpr
10576 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010577 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010578 */
10579
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010580static void
10581xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10582 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010583 CHECK_ERROR;
10584 SKIP_BLANKS;
10585 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010586 int op1 = ctxt->comp->last;
10587 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010588
10589 NEXT;
10590 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010591 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010592
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010593 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10594
Owen Taylor3473f882001-02-23 17:55:21 +000010595 SKIP_BLANKS;
10596 }
Owen Taylor3473f882001-02-23 17:55:21 +000010597}
10598
10599/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010600 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010601 * @ctxt: the XPath Parser context
10602 *
10603 * [27] UnaryExpr ::= UnionExpr
10604 * | '-' UnaryExpr
10605 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010606 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010607 */
10608
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010609static void
10610xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010611 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010613
10614 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010615 while (CUR == '-') {
10616 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010617 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010618 NEXT;
10619 SKIP_BLANKS;
10620 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010621
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010622 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010623 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010624 if (found) {
10625 if (minus)
10626 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10627 else
10628 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010629 }
10630}
10631
10632/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010633 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010634 * @ctxt: the XPath Parser context
10635 *
10636 * [26] MultiplicativeExpr ::= UnaryExpr
10637 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10638 * | MultiplicativeExpr 'div' UnaryExpr
10639 * | MultiplicativeExpr 'mod' UnaryExpr
10640 * [34] MultiplyOperator ::= '*'
10641 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010642 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010643 */
10644
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010645static void
10646xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10647 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010648 CHECK_ERROR;
10649 SKIP_BLANKS;
10650 while ((CUR == '*') ||
10651 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10652 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10653 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010654 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010655
10656 if (CUR == '*') {
10657 op = 0;
10658 NEXT;
10659 } else if (CUR == 'd') {
10660 op = 1;
10661 SKIP(3);
10662 } else if (CUR == 'm') {
10663 op = 2;
10664 SKIP(3);
10665 }
10666 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010667 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010668 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010669 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010670 SKIP_BLANKS;
10671 }
10672}
10673
10674/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010675 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010676 * @ctxt: the XPath Parser context
10677 *
10678 * [25] AdditiveExpr ::= MultiplicativeExpr
10679 * | AdditiveExpr '+' MultiplicativeExpr
10680 * | AdditiveExpr '-' MultiplicativeExpr
10681 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010682 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010683 */
10684
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010685static void
10686xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010687
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010688 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010689 CHECK_ERROR;
10690 SKIP_BLANKS;
10691 while ((CUR == '+') || (CUR == '-')) {
10692 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010693 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010694
10695 if (CUR == '+') plus = 1;
10696 else plus = 0;
10697 NEXT;
10698 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010699 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010700 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010701 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010702 SKIP_BLANKS;
10703 }
10704}
10705
10706/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010707 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010708 * @ctxt: the XPath Parser context
10709 *
10710 * [24] RelationalExpr ::= AdditiveExpr
10711 * | RelationalExpr '<' AdditiveExpr
10712 * | RelationalExpr '>' AdditiveExpr
10713 * | RelationalExpr '<=' AdditiveExpr
10714 * | RelationalExpr '>=' AdditiveExpr
10715 *
10716 * A <= B > C is allowed ? Answer from James, yes with
10717 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10718 * which is basically what got implemented.
10719 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010720 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010721 * on the stack
10722 */
10723
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010724static void
10725xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10726 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010727 CHECK_ERROR;
10728 SKIP_BLANKS;
10729 while ((CUR == '<') ||
10730 (CUR == '>') ||
10731 ((CUR == '<') && (NXT(1) == '=')) ||
10732 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010733 int inf, strict;
10734 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010735
10736 if (CUR == '<') inf = 1;
10737 else inf = 0;
10738 if (NXT(1) == '=') strict = 0;
10739 else strict = 1;
10740 NEXT;
10741 if (!strict) NEXT;
10742 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010743 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010744 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010745 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010746 SKIP_BLANKS;
10747 }
10748}
10749
10750/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010751 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010752 * @ctxt: the XPath Parser context
10753 *
10754 * [23] EqualityExpr ::= RelationalExpr
10755 * | EqualityExpr '=' RelationalExpr
10756 * | EqualityExpr '!=' RelationalExpr
10757 *
10758 * A != B != C is allowed ? Answer from James, yes with
10759 * (RelationalExpr = RelationalExpr) = RelationalExpr
10760 * (RelationalExpr != RelationalExpr) != RelationalExpr
10761 * which is basically what got implemented.
10762 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010763 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010764 *
10765 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010766static void
10767xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10768 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010769 CHECK_ERROR;
10770 SKIP_BLANKS;
10771 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010772 int eq;
10773 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010774
10775 if (CUR == '=') eq = 1;
10776 else eq = 0;
10777 NEXT;
10778 if (!eq) NEXT;
10779 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010780 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010781 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010782 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010783 SKIP_BLANKS;
10784 }
10785}
10786
10787/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010788 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010789 * @ctxt: the XPath Parser context
10790 *
10791 * [22] AndExpr ::= EqualityExpr
10792 * | AndExpr 'and' EqualityExpr
10793 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010794 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010795 *
10796 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010797static void
10798xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10799 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010800 CHECK_ERROR;
10801 SKIP_BLANKS;
10802 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010804 SKIP(3);
10805 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010806 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010807 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010808 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010809 SKIP_BLANKS;
10810 }
10811}
10812
10813/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010814 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010815 * @ctxt: the XPath Parser context
10816 *
10817 * [14] Expr ::= OrExpr
10818 * [21] OrExpr ::= AndExpr
10819 * | OrExpr 'or' AndExpr
10820 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010821 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010822 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010823static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010824xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010825 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010826 CHECK_ERROR;
10827 SKIP_BLANKS;
10828 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010829 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010830 SKIP(2);
10831 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010832 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010833 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010834 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10835 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010836 SKIP_BLANKS;
10837 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010838 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010839 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010840 /*
10841 * This is the main place to eliminate sorting for
10842 * operations which don't require a sorted node-set.
10843 * E.g. count().
10844 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010845 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10846 }
Owen Taylor3473f882001-02-23 17:55:21 +000010847}
10848
10849/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010850 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010851 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010852 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010853 *
10854 * [8] Predicate ::= '[' PredicateExpr ']'
10855 * [9] PredicateExpr ::= Expr
10856 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010857 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010858 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010859static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010860xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010861 int op1 = ctxt->comp->last;
10862
10863 SKIP_BLANKS;
10864 if (CUR != '[') {
10865 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10866 }
10867 NEXT;
10868 SKIP_BLANKS;
10869
10870 ctxt->comp->last = -1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000010871 /*
10872 * This call to xmlXPathCompileExpr() will deactivate sorting
10873 * of the predicate result.
10874 * TODO: Sorting is still activated for filters, since I'm not
10875 * sure if needed. Normally sorting should not be needed, since
10876 * a filter can only diminish the number of items in a sequence,
10877 * but won't change its order; so if the initial sequence is sorted,
10878 * subsequent sorting is not needed.
10879 */
10880 if (! filter)
10881 xmlXPathCompileExpr(ctxt, 0);
10882 else
10883 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010884 CHECK_ERROR;
10885
10886 if (CUR != ']') {
10887 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10888 }
10889
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010890 if (filter)
10891 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10892 else
10893 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010894
10895 NEXT;
10896 SKIP_BLANKS;
10897}
10898
10899/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010900 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010901 * @ctxt: the XPath Parser context
10902 * @test: pointer to a xmlXPathTestVal
10903 * @type: pointer to a xmlXPathTypeVal
10904 * @prefix: placeholder for a possible name prefix
10905 *
10906 * [7] NodeTest ::= NameTest
10907 * | NodeType '(' ')'
10908 * | 'processing-instruction' '(' Literal ')'
10909 *
10910 * [37] NameTest ::= '*'
10911 * | NCName ':' '*'
10912 * | QName
10913 * [38] NodeType ::= 'comment'
10914 * | 'text'
10915 * | 'processing-instruction'
10916 * | 'node'
10917 *
William M. Brack08171912003-12-29 02:52:11 +000010918 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010919 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010920static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010921xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10922 xmlXPathTypeVal *type, const xmlChar **prefix,
10923 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010924 int blanks;
10925
10926 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10927 STRANGE;
10928 return(NULL);
10929 }
William M. Brack78637da2003-07-31 14:47:38 +000010930 *type = (xmlXPathTypeVal) 0;
10931 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010932 *prefix = NULL;
10933 SKIP_BLANKS;
10934
10935 if ((name == NULL) && (CUR == '*')) {
10936 /*
10937 * All elements
10938 */
10939 NEXT;
10940 *test = NODE_TEST_ALL;
10941 return(NULL);
10942 }
10943
10944 if (name == NULL)
10945 name = xmlXPathParseNCName(ctxt);
10946 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010947 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010948 }
10949
William M. Brack76e95df2003-10-18 16:20:14 +000010950 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010951 SKIP_BLANKS;
10952 if (CUR == '(') {
10953 NEXT;
10954 /*
10955 * NodeType or PI search
10956 */
10957 if (xmlStrEqual(name, BAD_CAST "comment"))
10958 *type = NODE_TYPE_COMMENT;
10959 else if (xmlStrEqual(name, BAD_CAST "node"))
10960 *type = NODE_TYPE_NODE;
10961 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10962 *type = NODE_TYPE_PI;
10963 else if (xmlStrEqual(name, BAD_CAST "text"))
10964 *type = NODE_TYPE_TEXT;
10965 else {
10966 if (name != NULL)
10967 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010968 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010969 }
10970
10971 *test = NODE_TEST_TYPE;
10972
10973 SKIP_BLANKS;
10974 if (*type == NODE_TYPE_PI) {
10975 /*
10976 * Specific case: search a PI by name.
10977 */
Owen Taylor3473f882001-02-23 17:55:21 +000010978 if (name != NULL)
10979 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010980 name = NULL;
10981 if (CUR != ')') {
10982 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010983 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010984 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010985 SKIP_BLANKS;
10986 }
Owen Taylor3473f882001-02-23 17:55:21 +000010987 }
10988 if (CUR != ')') {
10989 if (name != NULL)
10990 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010991 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010992 }
10993 NEXT;
10994 return(name);
10995 }
10996 *test = NODE_TEST_NAME;
10997 if ((!blanks) && (CUR == ':')) {
10998 NEXT;
10999
11000 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011001 * Since currently the parser context don't have a
11002 * namespace list associated:
11003 * The namespace name for this prefix can be computed
11004 * only at evaluation time. The compilation is done
11005 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000011006 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011007#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000011008 *prefix = xmlXPathNsLookup(ctxt->context, name);
11009 if (name != NULL)
11010 xmlFree(name);
11011 if (*prefix == NULL) {
11012 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11013 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011014#else
11015 *prefix = name;
11016#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011017
11018 if (CUR == '*') {
11019 /*
11020 * All elements
11021 */
11022 NEXT;
11023 *test = NODE_TEST_ALL;
11024 return(NULL);
11025 }
11026
11027 name = xmlXPathParseNCName(ctxt);
11028 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000011029 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000011030 }
11031 }
11032 return(name);
11033}
11034
11035/**
11036 * xmlXPathIsAxisName:
11037 * @name: a preparsed name token
11038 *
11039 * [6] AxisName ::= 'ancestor'
11040 * | 'ancestor-or-self'
11041 * | 'attribute'
11042 * | 'child'
11043 * | 'descendant'
11044 * | 'descendant-or-self'
11045 * | 'following'
11046 * | 'following-sibling'
11047 * | 'namespace'
11048 * | 'parent'
11049 * | 'preceding'
11050 * | 'preceding-sibling'
11051 * | 'self'
11052 *
11053 * Returns the axis or 0
11054 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000011055static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000011056xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000011057 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000011058 switch (name[0]) {
11059 case 'a':
11060 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11061 ret = AXIS_ANCESTOR;
11062 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11063 ret = AXIS_ANCESTOR_OR_SELF;
11064 if (xmlStrEqual(name, BAD_CAST "attribute"))
11065 ret = AXIS_ATTRIBUTE;
11066 break;
11067 case 'c':
11068 if (xmlStrEqual(name, BAD_CAST "child"))
11069 ret = AXIS_CHILD;
11070 break;
11071 case 'd':
11072 if (xmlStrEqual(name, BAD_CAST "descendant"))
11073 ret = AXIS_DESCENDANT;
11074 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11075 ret = AXIS_DESCENDANT_OR_SELF;
11076 break;
11077 case 'f':
11078 if (xmlStrEqual(name, BAD_CAST "following"))
11079 ret = AXIS_FOLLOWING;
11080 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11081 ret = AXIS_FOLLOWING_SIBLING;
11082 break;
11083 case 'n':
11084 if (xmlStrEqual(name, BAD_CAST "namespace"))
11085 ret = AXIS_NAMESPACE;
11086 break;
11087 case 'p':
11088 if (xmlStrEqual(name, BAD_CAST "parent"))
11089 ret = AXIS_PARENT;
11090 if (xmlStrEqual(name, BAD_CAST "preceding"))
11091 ret = AXIS_PRECEDING;
11092 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11093 ret = AXIS_PRECEDING_SIBLING;
11094 break;
11095 case 's':
11096 if (xmlStrEqual(name, BAD_CAST "self"))
11097 ret = AXIS_SELF;
11098 break;
11099 }
11100 return(ret);
11101}
11102
11103/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011104 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000011105 * @ctxt: the XPath Parser context
11106 *
11107 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11108 * | AbbreviatedStep
11109 *
11110 * [12] AbbreviatedStep ::= '.' | '..'
11111 *
11112 * [5] AxisSpecifier ::= AxisName '::'
11113 * | AbbreviatedAxisSpecifier
11114 *
11115 * [13] AbbreviatedAxisSpecifier ::= '@'?
11116 *
11117 * Modified for XPtr range support as:
11118 *
11119 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11120 * | AbbreviatedStep
11121 * | 'range-to' '(' Expr ')' Predicate*
11122 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011123 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000011124 * A location step of . is short for self::node(). This is
11125 * particularly useful in conjunction with //. For example, the
11126 * location path .//para is short for
11127 * self::node()/descendant-or-self::node()/child::para
11128 * and so will select all para descendant elements of the context
11129 * node.
11130 * Similarly, a location step of .. is short for parent::node().
11131 * For example, ../title is short for parent::node()/child::title
11132 * and so will select the title children of the parent of the context
11133 * node.
11134 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011135static void
11136xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011137#ifdef LIBXML_XPTR_ENABLED
11138 int rangeto = 0;
11139 int op2 = -1;
11140#endif
11141
Owen Taylor3473f882001-02-23 17:55:21 +000011142 SKIP_BLANKS;
11143 if ((CUR == '.') && (NXT(1) == '.')) {
11144 SKIP(2);
11145 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011146 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11147 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011148 } else if (CUR == '.') {
11149 NEXT;
11150 SKIP_BLANKS;
11151 } else {
11152 xmlChar *name = NULL;
11153 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011154 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000011155 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000011156 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011157 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000011158
11159 /*
11160 * The modification needed for XPointer change to the production
11161 */
11162#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011163 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000011164 name = xmlXPathParseNCName(ctxt);
11165 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011166 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000011167 xmlFree(name);
11168 SKIP_BLANKS;
11169 if (CUR != '(') {
11170 XP_ERROR(XPATH_EXPR_ERROR);
11171 }
11172 NEXT;
11173 SKIP_BLANKS;
11174
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011175 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011176 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000011177 CHECK_ERROR;
11178
11179 SKIP_BLANKS;
11180 if (CUR != ')') {
11181 XP_ERROR(XPATH_EXPR_ERROR);
11182 }
11183 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011184 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000011185 goto eval_predicates;
11186 }
11187 }
11188#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000011189 if (CUR == '*') {
11190 axis = AXIS_CHILD;
11191 } else {
11192 if (name == NULL)
11193 name = xmlXPathParseNCName(ctxt);
11194 if (name != NULL) {
11195 axis = xmlXPathIsAxisName(name);
11196 if (axis != 0) {
11197 SKIP_BLANKS;
11198 if ((CUR == ':') && (NXT(1) == ':')) {
11199 SKIP(2);
11200 xmlFree(name);
11201 name = NULL;
11202 } else {
11203 /* an element name can conflict with an axis one :-\ */
11204 axis = AXIS_CHILD;
11205 }
Owen Taylor3473f882001-02-23 17:55:21 +000011206 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000011207 axis = AXIS_CHILD;
11208 }
Daniel Veillard2156a562001-04-28 12:24:34 +000011209 } else if (CUR == '@') {
11210 NEXT;
11211 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000011212 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000011213 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000011214 }
Owen Taylor3473f882001-02-23 17:55:21 +000011215 }
11216
11217 CHECK_ERROR;
11218
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011219 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000011220 if (test == 0)
11221 return;
11222
Daniel Veillarded6c5492005-07-23 15:00:22 +000011223 if ((prefix != NULL) && (ctxt->context != NULL) &&
11224 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11225 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11226 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11227 }
11228 }
Owen Taylor3473f882001-02-23 17:55:21 +000011229#ifdef DEBUG_STEP
11230 xmlGenericError(xmlGenericErrorContext,
11231 "Basis : computing new set\n");
11232#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011233
Owen Taylor3473f882001-02-23 17:55:21 +000011234#ifdef DEBUG_STEP
11235 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011236 if (ctxt->value == NULL)
11237 xmlGenericError(xmlGenericErrorContext, "no value\n");
11238 else if (ctxt->value->nodesetval == NULL)
11239 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11240 else
11241 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011242#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011243
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011244#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000011245eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000011246#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011247 op1 = ctxt->comp->last;
11248 ctxt->comp->last = -1;
11249
Owen Taylor3473f882001-02-23 17:55:21 +000011250 SKIP_BLANKS;
11251 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011252 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000011253 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011254
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011255#ifdef LIBXML_XPTR_ENABLED
11256 if (rangeto) {
11257 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11258 } else
11259#endif
11260 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11261 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011262
Owen Taylor3473f882001-02-23 17:55:21 +000011263 }
11264#ifdef DEBUG_STEP
11265 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000011266 if (ctxt->value == NULL)
11267 xmlGenericError(xmlGenericErrorContext, "no value\n");
11268 else if (ctxt->value->nodesetval == NULL)
11269 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11270 else
11271 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11272 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000011273#endif
11274}
11275
11276/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011277 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011278 * @ctxt: the XPath Parser context
11279 *
11280 * [3] RelativeLocationPath ::= Step
11281 * | RelativeLocationPath '/' Step
11282 * | AbbreviatedRelativeLocationPath
11283 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11284 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011285 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011286 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011287static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011288xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011289(xmlXPathParserContextPtr ctxt) {
11290 SKIP_BLANKS;
11291 if ((CUR == '/') && (NXT(1) == '/')) {
11292 SKIP(2);
11293 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011294 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11295 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011296 } else if (CUR == '/') {
11297 NEXT;
11298 SKIP_BLANKS;
11299 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011300 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011301 SKIP_BLANKS;
11302 while (CUR == '/') {
11303 if ((CUR == '/') && (NXT(1) == '/')) {
11304 SKIP(2);
11305 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011306 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011307 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011308 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011309 } else if (CUR == '/') {
11310 NEXT;
11311 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011312 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011313 }
11314 SKIP_BLANKS;
11315 }
11316}
11317
11318/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011319 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011320 * @ctxt: the XPath Parser context
11321 *
11322 * [1] LocationPath ::= RelativeLocationPath
11323 * | AbsoluteLocationPath
11324 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11325 * | AbbreviatedAbsoluteLocationPath
11326 * [10] AbbreviatedAbsoluteLocationPath ::=
11327 * '//' RelativeLocationPath
11328 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011329 * Compile a location path
11330 *
Owen Taylor3473f882001-02-23 17:55:21 +000011331 * // is short for /descendant-or-self::node()/. For example,
11332 * //para is short for /descendant-or-self::node()/child::para and
11333 * so will select any para element in the document (even a para element
11334 * that is a document element will be selected by //para since the
11335 * document element node is a child of the root node); div//para is
11336 * short for div/descendant-or-self::node()/child::para and so will
11337 * select all para descendants of div children.
11338 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011339static void
11340xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011341 SKIP_BLANKS;
11342 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011343 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011344 } else {
11345 while (CUR == '/') {
11346 if ((CUR == '/') && (NXT(1) == '/')) {
11347 SKIP(2);
11348 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011349 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11350 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011351 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011352 } else if (CUR == '/') {
11353 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011354 SKIP_BLANKS;
11355 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011356 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011357 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011358 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011359 }
11360 }
11361 }
11362}
11363
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011364/************************************************************************
11365 * *
11366 * XPath precompiled expression evaluation *
11367 * *
11368 ************************************************************************/
11369
Daniel Veillardf06307e2001-07-03 10:35:50 +000011370static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011371xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11372
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011373#ifdef DEBUG_STEP
11374static void
11375xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11376 xmlXPathTestVal test,
11377 int nbNodes)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011378{
Daniel Veillardf06307e2001-07-03 10:35:50 +000011379 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011380 switch (axis) {
11381 case AXIS_ANCESTOR:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011382 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011384 case AXIS_ANCESTOR_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011385 xmlGenericError(xmlGenericErrorContext,
11386 "axis 'ancestors-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011387 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011388 case AXIS_ATTRIBUTE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011389 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011390 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011391 case AXIS_CHILD:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011392 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011394 case AXIS_DESCENDANT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011395 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011396 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011397 case AXIS_DESCENDANT_OR_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 xmlGenericError(xmlGenericErrorContext,
11399 "axis 'descendant-or-self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011400 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011401 case AXIS_FOLLOWING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011402 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011403 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011404 case AXIS_FOLLOWING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011405 xmlGenericError(xmlGenericErrorContext,
11406 "axis 'following-siblings' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011407 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011408 case AXIS_NAMESPACE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011409 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011411 case AXIS_PARENT:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011412 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011413 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011414 case AXIS_PRECEDING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011415 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011416 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011417 case AXIS_PRECEDING_SIBLING:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011418 xmlGenericError(xmlGenericErrorContext,
11419 "axis 'preceding-sibling' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011420 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011421 case AXIS_SELF:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011422 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardf06307e2001-07-03 10:35:50 +000011423 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011424 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011425 xmlGenericError(xmlGenericErrorContext,
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011426 " context contains %d nodes\n", nbNodes);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011427 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011428 case NODE_TEST_NONE:
11429 xmlGenericError(xmlGenericErrorContext,
11430 " searching for none !!!\n");
11431 break;
11432 case NODE_TEST_TYPE:
11433 xmlGenericError(xmlGenericErrorContext,
11434 " searching for type %d\n", type);
11435 break;
11436 case NODE_TEST_PI:
11437 xmlGenericError(xmlGenericErrorContext,
11438 " searching for PI !!!\n");
11439 break;
11440 case NODE_TEST_ALL:
11441 xmlGenericError(xmlGenericErrorContext,
11442 " searching for *\n");
11443 break;
11444 case NODE_TEST_NS:
11445 xmlGenericError(xmlGenericErrorContext,
11446 " searching for namespace %s\n",
11447 prefix);
11448 break;
11449 case NODE_TEST_NAME:
11450 xmlGenericError(xmlGenericErrorContext,
11451 " searching for name %s\n", name);
11452 if (prefix != NULL)
11453 xmlGenericError(xmlGenericErrorContext,
11454 " with namespace %s\n", prefix);
11455 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011456 }
11457 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011458}
11459#endif /* DEBUG_STEP */
11460
11461static int
11462xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11463 xmlXPathStepOpPtr op,
11464 xmlNodeSetPtr set,
11465 int contextSize,
11466 int hasNsNodes)
11467{
11468 if (op->ch1 != -1) {
11469 xmlXPathCompExprPtr comp = ctxt->comp;
11470 /*
11471 * Process inner predicates first.
11472 */
11473 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11474 /*
11475 * TODO: raise an internal error.
11476 */
11477 }
11478 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11479 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11480 CHECK_ERROR0;
11481 if (contextSize <= 0)
11482 return(0);
11483 }
11484 if (op->ch2 != -1) {
11485 xmlXPathContextPtr xpctxt = ctxt->context;
11486 xmlNodePtr contextNode, oldContextNode;
11487 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011488 int i, res, contextPos = 0, newContextSize;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011489 xmlXPathStepOpPtr exprOp;
11490 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11491
11492#ifdef LIBXML_XPTR_ENABLED
11493 /*
11494 * URGENT TODO: Check the following:
11495 * We don't expect location sets if evaluating prediates, right?
11496 * Only filters should expect location sets, right?
11497 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011498#endif
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011499 /*
11500 * SPEC XPath 1.0:
11501 * "For each node in the node-set to be filtered, the
11502 * PredicateExpr is evaluated with that node as the
11503 * context node, with the number of nodes in the
11504 * node-set as the context size, and with the proximity
11505 * position of the node in the node-set with respect to
11506 * the axis as the context position;"
11507 * @oldset is the node-set" to be filtered.
11508 *
11509 * SPEC XPath 1.0:
11510 * "only predicates change the context position and
11511 * context size (see [2.4 Predicates])."
11512 * Example:
11513 * node-set context pos
11514 * nA 1
11515 * nB 2
11516 * nC 3
11517 * After applying predicate [position() > 1] :
11518 * node-set context pos
11519 * nB 1
11520 * nC 2
11521 */
11522 oldContextNode = xpctxt->node;
11523 oldContextDoc = xpctxt->doc;
11524 /*
11525 * Get the expression of this predicate.
11526 */
11527 exprOp = &ctxt->comp->steps[op->ch2];
11528 newContextSize = 0;
11529 for (i = 0; i < set->nodeNr; i++) {
11530 if (set->nodeTab[i] == NULL)
11531 continue;
11532
11533 contextNode = set->nodeTab[i];
11534 xpctxt->node = contextNode;
11535 xpctxt->contextSize = contextSize;
11536 xpctxt->proximityPosition = ++contextPos;
11537
11538 /*
11539 * Also set the xpath document in case things like
11540 * key() are evaluated in the predicate.
11541 */
11542 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11543 (contextNode->doc != NULL))
11544 xpctxt->doc = contextNode->doc;
11545 /*
11546 * Evaluate the predicate expression with 1 context node
11547 * at a time; this node is packaged into a node set; this
11548 * node set is handed over to the evaluation mechanism.
11549 */
11550 if (contextObj == NULL)
11551 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11552 else
11553 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11554 contextNode);
11555
11556 valuePush(ctxt, contextObj);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011557
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011558 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011559
William M. Brack0bcec062007-02-14 02:15:19 +000011560 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11561 xmlXPathNodeSetClear(set, hasNsNodes);
11562 newContextSize = 0;
11563 goto evaluation_exit;
11564 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011565
11566 if (res != 0) {
11567 newContextSize++;
11568 } else {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011569 /*
11570 * Remove the entry from the initial node set.
11571 */
11572 set->nodeTab[i] = NULL;
11573 if (contextNode->type == XML_NAMESPACE_DECL)
11574 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011575 }
11576 if (ctxt->value == contextObj) {
11577 /*
11578 * Don't free the temporary XPath object holding the
11579 * context node, in order to avoid massive recreation
11580 * inside this loop.
11581 */
11582 valuePop(ctxt);
11583 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11584 } else {
11585 /*
11586 * TODO: The object was lost in the evaluation machinery.
11587 * Can this happen? Maybe in internal-error cases.
11588 */
11589 contextObj = NULL;
11590 }
11591 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011592
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011593 if (contextObj != NULL) {
11594 if (ctxt->value == contextObj)
11595 valuePop(ctxt);
11596 xmlXPathReleaseObject(xpctxt, contextObj);
11597 }
William M. Brack0bcec062007-02-14 02:15:19 +000011598evaluation_exit:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011599 if (exprRes != NULL)
11600 xmlXPathReleaseObject(ctxt->context, exprRes);
11601 /*
11602 * Reset/invalidate the context.
11603 */
11604 xpctxt->node = oldContextNode;
11605 xpctxt->doc = oldContextDoc;
11606 xpctxt->contextSize = -1;
11607 xpctxt->proximityPosition = -1;
11608 return(newContextSize);
11609 }
11610 return(contextSize);
11611}
11612
11613static int
11614xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11615 xmlXPathStepOpPtr op,
11616 xmlNodeSetPtr set,
11617 int contextSize,
11618 int minPos,
11619 int maxPos,
11620 int hasNsNodes)
11621{
11622 if (op->ch1 != -1) {
11623 xmlXPathCompExprPtr comp = ctxt->comp;
11624 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11625 /*
11626 * TODO: raise an internal error.
11627 */
11628 }
11629 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11630 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11631 CHECK_ERROR0;
11632 if (contextSize <= 0)
11633 return(0);
11634 }
11635 /*
11636 * Check if the node set contains a sufficient number of nodes for
11637 * the requested range.
11638 */
11639 if (contextSize < minPos) {
11640 xmlXPathNodeSetClear(set, hasNsNodes);
11641 return(0);
11642 }
11643 if (op->ch2 == -1) {
11644 /*
11645 * TODO: Can this ever happen?
11646 */
11647 return (contextSize);
11648 } else {
11649 xmlDocPtr oldContextDoc;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011650 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011651 xmlXPathStepOpPtr exprOp;
11652 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11653 xmlNodePtr oldContextNode, contextNode = NULL;
11654 xmlXPathContextPtr xpctxt = ctxt->context;
11655
11656#ifdef LIBXML_XPTR_ENABLED
11657 /*
11658 * URGENT TODO: Check the following:
11659 * We don't expect location sets if evaluating prediates, right?
11660 * Only filters should expect location sets, right?
11661 */
11662#endif /* LIBXML_XPTR_ENABLED */
11663
11664 /*
11665 * Save old context.
11666 */
11667 oldContextNode = xpctxt->node;
11668 oldContextDoc = xpctxt->doc;
11669 /*
11670 * Get the expression of this predicate.
11671 */
11672 exprOp = &ctxt->comp->steps[op->ch2];
11673 for (i = 0; i < set->nodeNr; i++) {
11674 if (set->nodeTab[i] == NULL)
11675 continue;
11676
11677 contextNode = set->nodeTab[i];
11678 xpctxt->node = contextNode;
11679 xpctxt->contextSize = contextSize;
11680 xpctxt->proximityPosition = ++contextPos;
11681
11682 /*
11683 * Initialize the new set.
11684 * Also set the xpath document in case things like
11685 * key() evaluation are attempted on the predicate
11686 */
11687 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11688 (contextNode->doc != NULL))
11689 xpctxt->doc = contextNode->doc;
11690 /*
11691 * Evaluate the predicate expression with 1 context node
11692 * at a time; this node is packaged into a node set; this
11693 * node set is handed over to the evaluation mechanism.
11694 */
11695 if (contextObj == NULL)
11696 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11697 else
11698 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11699 contextNode);
11700
11701 valuePush(ctxt, contextObj);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000011702 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011703
11704 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011705 goto evaluation_error;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011706
11707 if (res)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011708 pos++;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011709
11710 if (res && (pos >= minPos) && (pos <= maxPos)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011711 /*
11712 * Fits in the requested range.
11713 */
11714 newContextSize++;
11715 if (minPos == maxPos) {
11716 /*
11717 * Only 1 node was requested.
11718 */
11719 if (contextNode->type == XML_NAMESPACE_DECL) {
11720 /*
11721 * As always: take care of those nasty
11722 * namespace nodes.
11723 */
11724 set->nodeTab[i] = NULL;
11725 }
11726 xmlXPathNodeSetClear(set, hasNsNodes);
11727 set->nodeNr = 1;
11728 set->nodeTab[0] = contextNode;
11729 goto evaluation_exit;
11730 }
11731 if (pos == maxPos) {
11732 /*
11733 * We are done.
11734 */
11735 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11736 goto evaluation_exit;
11737 }
11738 } else {
11739 /*
11740 * Remove the entry from the initial node set.
11741 */
11742 set->nodeTab[i] = NULL;
11743 if (contextNode->type == XML_NAMESPACE_DECL)
11744 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11745 }
11746 if (exprRes != NULL) {
11747 xmlXPathReleaseObject(ctxt->context, exprRes);
11748 exprRes = NULL;
11749 }
11750 if (ctxt->value == contextObj) {
11751 /*
11752 * Don't free the temporary XPath object holding the
11753 * context node, in order to avoid massive recreation
11754 * inside this loop.
11755 */
11756 valuePop(ctxt);
11757 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11758 } else {
11759 /*
11760 * The object was lost in the evaluation machinery.
11761 * Can this happen? Maybe in case of internal-errors.
11762 */
11763 contextObj = NULL;
11764 }
11765 }
11766 goto evaluation_exit;
11767
11768evaluation_error:
11769 xmlXPathNodeSetClear(set, hasNsNodes);
11770 newContextSize = 0;
11771
11772evaluation_exit:
11773 if (contextObj != NULL) {
11774 if (ctxt->value == contextObj)
11775 valuePop(ctxt);
11776 xmlXPathReleaseObject(xpctxt, contextObj);
11777 }
11778 if (exprRes != NULL)
11779 xmlXPathReleaseObject(ctxt->context, exprRes);
11780 /*
11781 * Reset/invalidate the context.
11782 */
11783 xpctxt->node = oldContextNode;
11784 xpctxt->doc = oldContextDoc;
11785 xpctxt->contextSize = -1;
11786 xpctxt->proximityPosition = -1;
11787 return(newContextSize);
11788 }
11789 return(contextSize);
11790}
11791
11792static int
11793xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11794 xmlXPathStepOpPtr op,
11795 int *maxPos)
11796{
11797
11798 xmlXPathStepOpPtr exprOp;
11799
11800 /*
11801 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11802 */
11803
11804 /*
11805 * If not -1, then ch1 will point to:
11806 * 1) For predicates (XPATH_OP_PREDICATE):
11807 * - an inner predicate operator
11808 * 2) For filters (XPATH_OP_FILTER):
11809 * - an inner filter operater OR
11810 * - an expression selecting the node set.
11811 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11812 */
11813 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11814 return(0);
11815
11816 if (op->ch2 != -1) {
11817 exprOp = &ctxt->comp->steps[op->ch2];
11818 } else
11819 return(0);
11820
11821 if ((exprOp != NULL) &&
11822 (exprOp->op == XPATH_OP_VALUE) &&
11823 (exprOp->value4 != NULL) &&
11824 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11825 {
11826 /*
11827 * We have a "[n]" predicate here.
11828 * TODO: Unfortunately this simplistic test here is not
11829 * able to detect a position() predicate in compound
11830 * expressions like "[@attr = 'a" and position() = 1],
11831 * and even not the usage of position() in
11832 * "[position() = 1]"; thus - obviously - a position-range,
11833 * like it "[position() < 5]", is also not detected.
11834 * Maybe we could rewrite the AST to ease the optimization.
11835 */
11836 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11837
11838 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11839 (float) *maxPos)
11840 {
11841 return(1);
11842 }
11843 }
11844 return(0);
11845}
11846
11847static int
11848xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11849 xmlXPathStepOpPtr op,
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011850 xmlNodePtr * first, xmlNodePtr * last,
11851 int toBool)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011852{
11853
11854#define XP_TEST_HIT \
11855 if (hasAxisRange != 0) { \
11856 if (++pos == maxPos) { \
11857 addNode(seq, cur); \
11858 goto axis_range_end; } \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011859 } else { \
11860 addNode(seq, cur); \
11861 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011862
11863#define XP_TEST_HIT_NS \
11864 if (hasAxisRange != 0) { \
11865 if (++pos == maxPos) { \
11866 hasNsNodes = 1; \
11867 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11868 goto axis_range_end; } \
11869 } else { \
11870 hasNsNodes = 1; \
11871 xmlXPathNodeSetAddNs(seq, \
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011872 xpctxt->node, (xmlNsPtr) cur); \
11873 if (breakOnFirstHit) goto first_hit; }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011874
11875 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11876 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11877 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11878 const xmlChar *prefix = op->value4;
11879 const xmlChar *name = op->value5;
11880 const xmlChar *URI = NULL;
11881
11882#ifdef DEBUG_STEP
11883 int nbMatches = 0, prevMatches = 0;
11884#endif
11885 int total = 0, hasNsNodes = 0;
11886 /* The popped object holding the context nodes */
11887 xmlXPathObjectPtr obj;
11888 /* The set of context nodes for the node tests */
11889 xmlNodeSetPtr contextSeq;
11890 int contextIdx;
11891 xmlNodePtr contextNode;
11892 /* The context node for a compound traversal */
11893 xmlNodePtr outerContextNode;
11894 /* The final resulting node set wrt to all context nodes */
11895 xmlNodeSetPtr outSeq;
11896 /*
11897 * The temporary resulting node set wrt 1 context node.
11898 * Used to feed predicate evaluation.
11899 */
11900 xmlNodeSetPtr seq;
11901 xmlNodePtr cur;
11902 /* First predicate operator */
11903 xmlXPathStepOpPtr predOp;
11904 int maxPos; /* The requested position() (when a "[n]" predicate) */
11905 int hasPredicateRange, hasAxisRange, pos, size, newSize;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000011906 int breakOnFirstHit;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000011907
11908 xmlXPathTraversalFunction next = NULL;
11909 /* compound axis traversal */
11910 xmlXPathTraversalFunctionExt outerNext = NULL;
11911 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11912 xmlXPathNodeSetMergeFunction mergeAndClear;
11913 xmlNodePtr oldContextNode;
11914 xmlXPathContextPtr xpctxt = ctxt->context;
11915
11916
11917 CHECK_TYPE0(XPATH_NODESET);
11918 obj = valuePop(ctxt);
11919 /*
11920 * Setup namespaces.
11921 */
11922 if (prefix != NULL) {
11923 URI = xmlXPathNsLookup(xpctxt, prefix);
11924 if (URI == NULL) {
11925 xmlXPathReleaseObject(xpctxt, obj);
11926 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11927 }
11928 }
11929 /*
11930 * Setup axis.
11931 *
11932 * MAYBE FUTURE TODO: merging optimizations:
11933 * - If the nodes to be traversed wrt to the initial nodes and
11934 * the current axis cannot overlap, then we could avoid searching
11935 * for duplicates during the merge.
11936 * But the question is how/when to evaluate if they cannot overlap.
11937 * Example: if we know that for two initial nodes, the one is
11938 * not in the ancestor-or-self axis of the other, then we could safely
11939 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11940 * the descendant-or-self axis.
11941 */
11942 addNode = xmlXPathNodeSetAdd;
11943 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11944 switch (axis) {
11945 case AXIS_ANCESTOR:
11946 first = NULL;
11947 next = xmlXPathNextAncestor;
11948 break;
11949 case AXIS_ANCESTOR_OR_SELF:
11950 first = NULL;
11951 next = xmlXPathNextAncestorOrSelf;
11952 break;
11953 case AXIS_ATTRIBUTE:
11954 first = NULL;
11955 last = NULL;
11956 next = xmlXPathNextAttribute;
11957 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11958 break;
11959 case AXIS_CHILD:
11960 last = NULL;
11961 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11962 /*
11963 * This iterator will give us only nodes which can
11964 * hold element nodes.
11965 */
11966 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11967 }
11968 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11969 (type == NODE_TYPE_NODE))
11970 {
11971 /*
11972 * Optimization if an element node type is 'element'.
11973 */
11974 next = xmlXPathNextChildElement;
11975 } else
11976 next = xmlXPathNextChild;
11977 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11978 break;
11979 case AXIS_DESCENDANT:
11980 last = NULL;
11981 next = xmlXPathNextDescendant;
11982 break;
11983 case AXIS_DESCENDANT_OR_SELF:
11984 last = NULL;
11985 next = xmlXPathNextDescendantOrSelf;
11986 break;
11987 case AXIS_FOLLOWING:
11988 last = NULL;
11989 next = xmlXPathNextFollowing;
11990 break;
11991 case AXIS_FOLLOWING_SIBLING:
11992 last = NULL;
11993 next = xmlXPathNextFollowingSibling;
11994 break;
11995 case AXIS_NAMESPACE:
11996 first = NULL;
11997 last = NULL;
11998 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11999 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12000 break;
12001 case AXIS_PARENT:
12002 first = NULL;
12003 next = xmlXPathNextParent;
12004 break;
12005 case AXIS_PRECEDING:
12006 first = NULL;
12007 next = xmlXPathNextPrecedingInternal;
12008 break;
12009 case AXIS_PRECEDING_SIBLING:
12010 first = NULL;
12011 next = xmlXPathNextPrecedingSibling;
12012 break;
12013 case AXIS_SELF:
12014 first = NULL;
12015 last = NULL;
12016 next = xmlXPathNextSelf;
12017 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12018 break;
12019 }
12020
12021#ifdef DEBUG_STEP
12022 xmlXPathDebugDumpStepAxis(axis, test,
12023 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12024#endif
12025
12026 if (next == NULL) {
12027 xmlXPathReleaseObject(xpctxt, obj);
12028 return(0);
12029 }
12030 contextSeq = obj->nodesetval;
12031 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12032 xmlXPathReleaseObject(xpctxt, obj);
12033 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12034 return(0);
12035 }
12036 /*
12037 * Predicate optimization ---------------------------------------------
12038 * If this step has a last predicate, which contains a position(),
12039 * then we'll optimize (although not exactly "position()", but only
12040 * the short-hand form, i.e., "[n]".
12041 *
12042 * Example - expression "/foo[parent::bar][1]":
12043 *
12044 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12045 * ROOT -- op->ch1
12046 * PREDICATE -- op->ch2 (predOp)
12047 * PREDICATE -- predOp->ch1 = [parent::bar]
12048 * SORT
12049 * COLLECT 'parent' 'name' 'node' bar
12050 * NODE
12051 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12052 *
12053 */
12054 maxPos = 0;
12055 predOp = NULL;
12056 hasPredicateRange = 0;
12057 hasAxisRange = 0;
12058 if (op->ch2 != -1) {
12059 /*
12060 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12061 */
12062 predOp = &ctxt->comp->steps[op->ch2];
12063 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12064 if (predOp->ch1 != -1) {
12065 /*
12066 * Use the next inner predicate operator.
12067 */
12068 predOp = &ctxt->comp->steps[predOp->ch1];
12069 hasPredicateRange = 1;
12070 } else {
12071 /*
12072 * There's no other predicate than the [n] predicate.
12073 */
12074 predOp = NULL;
12075 hasAxisRange = 1;
12076 }
12077 }
12078 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012079 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012080 /*
12081 * Axis traversal -----------------------------------------------------
12082 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012083 /*
12084 * 2.3 Node Tests
12085 * - For the attribute axis, the principal node type is attribute.
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012086 * - For the namespace axis, the principal node type is namespace.
12087 * - For other axes, the principal node type is element.
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012088 *
12089 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012090 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012091 * select all element children of the context node
12092 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012093 oldContextNode = xpctxt->node;
12094 addNode = xmlXPathNodeSetAddUnique;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012095 outSeq = NULL;
12096 seq = NULL;
12097 outerContextNode = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012098 contextNode = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012099 contextIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012100
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012101
12102 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12103 if (outerNext != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012104 /*
12105 * This is a compound traversal.
12106 */
12107 if (contextNode == NULL) {
12108 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012109 * Set the context for the outer traversal.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012110 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012111 outerContextNode = contextSeq->nodeTab[contextIdx++];
12112 contextNode = outerNext(NULL, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012113 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012114 contextNode = outerNext(contextNode, outerContextNode);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012115 if (contextNode == NULL)
12116 continue;
12117 /*
12118 * Set the context for the main traversal.
12119 */
12120 xpctxt->node = contextNode;
12121 } else
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012122 xpctxt->node = contextSeq->nodeTab[contextIdx++];
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012123
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012124 if (seq == NULL) {
12125 seq = xmlXPathNodeSetCreate(NULL);
12126 if (seq == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012127 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012128 goto error;
12129 }
12130 }
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012131 /*
12132 * Traverse the axis and test the nodes.
12133 */
12134 pos = 0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012135 cur = NULL;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012136 hasNsNodes = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012137 do {
12138 cur = next(ctxt, cur);
12139 if (cur == NULL)
12140 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012141
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012142 /*
12143 * QUESTION TODO: What does the "first" and "last" stuff do?
12144 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012145 if ((first != NULL) && (*first != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012146 if (*first == cur)
12147 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012148 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012149#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012150 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012151#else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012152 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012153#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012154 {
12155 break;
12156 }
12157 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012158 if ((last != NULL) && (*last != NULL)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012159 if (*last == cur)
12160 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012161 if (((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012162#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012163 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012164#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012165 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012166#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000012167 {
12168 break;
12169 }
12170 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012171
12172 total++;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012173
Daniel Veillardf06307e2001-07-03 10:35:50 +000012174#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012175 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12176#endif
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012177
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012178 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012179 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012180 total = 0;
12181 STRANGE
12182 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012183 case NODE_TEST_TYPE:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012184 /*
12185 * TODO: Don't we need to use
12186 * xmlXPathNodeSetAddNs() for namespace nodes here?
12187 * Surprisingly, some c14n tests fail, if we do this.
12188 */
12189 if (type == NODE_TYPE_NODE) {
12190 switch (cur->type) {
12191 case XML_DOCUMENT_NODE:
12192 case XML_HTML_DOCUMENT_NODE:
12193#ifdef LIBXML_DOCB_ENABLED
12194 case XML_DOCB_DOCUMENT_NODE:
12195#endif
12196 case XML_ELEMENT_NODE:
12197 case XML_ATTRIBUTE_NODE:
12198 case XML_PI_NODE:
12199 case XML_COMMENT_NODE:
12200 case XML_CDATA_SECTION_NODE:
12201 case XML_TEXT_NODE:
12202 case XML_NAMESPACE_DECL:
12203 XP_TEST_HIT
12204 break;
12205 default:
12206 break;
12207 }
12208 } else if (cur->type == type) {
Kasimier T. Buchcik889b7622006-07-03 11:44:13 +000012209 if (type == XML_NAMESPACE_DECL)
12210 XP_TEST_HIT_NS
12211 else
12212 XP_TEST_HIT
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012213 } else if ((type == NODE_TYPE_TEXT) &&
12214 (cur->type == XML_CDATA_SECTION_NODE))
12215 {
12216 XP_TEST_HIT
12217 }
12218 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012219 case NODE_TEST_PI:
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012220 if ((cur->type == XML_PI_NODE) &&
12221 ((name == NULL) || xmlStrEqual(name, cur->name)))
12222 {
12223 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012224 }
12225 break;
12226 case NODE_TEST_ALL:
12227 if (axis == AXIS_ATTRIBUTE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012228 if (cur->type == XML_ATTRIBUTE_NODE)
12229 {
12230 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012231 }
12232 } else if (axis == AXIS_NAMESPACE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012233 if (cur->type == XML_NAMESPACE_DECL)
12234 {
12235 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012236 }
12237 } else {
12238 if (cur->type == XML_ELEMENT_NODE) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012239 if (prefix == NULL)
12240 {
12241 XP_TEST_HIT
12242
Daniel Veillardf06307e2001-07-03 10:35:50 +000012243 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012244 (xmlStrEqual(URI, cur->ns->href)))
12245 {
12246 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012247 }
12248 }
12249 }
12250 break;
12251 case NODE_TEST_NS:{
12252 TODO;
12253 break;
12254 }
12255 case NODE_TEST_NAME:
Daniel Veillardfe3970e2006-11-23 16:08:30 +000012256 if (axis == AXIS_ATTRIBUTE) {
12257 if (cur->type != XML_ATTRIBUTE_NODE)
12258 break;
12259 } else if (axis == AXIS_NAMESPACE) {
12260 if (cur->type != XML_NAMESPACE_DECL)
12261 break;
12262 } else {
12263 if (cur->type != XML_ELEMENT_NODE)
12264 break;
12265 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012266 switch (cur->type) {
12267 case XML_ELEMENT_NODE:
12268 if (xmlStrEqual(name, cur->name)) {
12269 if (prefix == NULL) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012270 if (cur->ns == NULL)
12271 {
12272 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012273 }
12274 } else {
12275 if ((cur->ns != NULL) &&
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012276 (xmlStrEqual(URI, cur->ns->href)))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012277 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012278 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012279 }
12280 }
12281 }
12282 break;
12283 case XML_ATTRIBUTE_NODE:{
12284 xmlAttrPtr attr = (xmlAttrPtr) cur;
12285
12286 if (xmlStrEqual(name, attr->name)) {
12287 if (prefix == NULL) {
12288 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012289 (attr->ns->prefix == NULL))
12290 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012291 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012292 }
12293 } else {
12294 if ((attr->ns != NULL) &&
12295 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012296 attr->ns->href)))
12297 {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012298 XP_TEST_HIT
Daniel Veillardf06307e2001-07-03 10:35:50 +000012299 }
12300 }
12301 }
12302 break;
12303 }
12304 case XML_NAMESPACE_DECL:
12305 if (cur->type == XML_NAMESPACE_DECL) {
12306 xmlNsPtr ns = (xmlNsPtr) cur;
12307
12308 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012309 && (xmlStrEqual(ns->prefix, name)))
12310 {
12311 XP_TEST_HIT_NS
Daniel Veillardf06307e2001-07-03 10:35:50 +000012312 }
12313 }
12314 break;
12315 default:
12316 break;
12317 }
12318 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012319 } /* switch(test) */
12320 } while (cur != NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012321
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012322 goto apply_predicates;
12323
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012324axis_range_end: /* ----------------------------------------------------- */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012325 /*
12326 * We have a "/foo[n]", and position() = n was reached.
12327 * Note that we can have as well "/foo/::parent::foo[1]", so
12328 * a duplicate-aware merge is still needed.
12329 * Merge with the result.
12330 */
12331 if (outSeq == NULL) {
12332 outSeq = seq;
12333 seq = NULL;
12334 } else
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012335 outSeq = mergeAndClear(outSeq, seq, 0);
12336 /*
12337 * Break if only a true/false result was requested.
12338 */
12339 if (toBool)
12340 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012341 continue;
12342
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012343first_hit: /* ---------------------------------------------------------- */
12344 /*
12345 * Break if only a true/false result was requested and
12346 * no predicates existed and a node test succeeded.
12347 */
12348 if (outSeq == NULL) {
12349 outSeq = seq;
12350 seq = NULL;
12351 } else
12352 outSeq = mergeAndClear(outSeq, seq, 0);
12353 break;
12354
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012355#ifdef DEBUG_STEP
12356 if (seq != NULL)
12357 nbMatches += seq->nodeNr;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012358#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012359
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012360apply_predicates: /* --------------------------------------------------- */
12361 /*
12362 * Apply predicates.
12363 */
12364 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12365 /*
12366 * E.g. when we have a "/foo[some expression][n]".
12367 */
12368 /*
12369 * QUESTION TODO: The old predicate evaluation took into
12370 * account location-sets.
12371 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12372 * Do we expect such a set here?
12373 * All what I learned now from the evaluation semantics
12374 * does not indicate that a location-set will be processed
12375 * here, so this looks OK.
12376 */
12377 /*
12378 * Iterate over all predicates, starting with the outermost
12379 * predicate.
12380 * TODO: Problem: we cannot execute the inner predicates first
12381 * since we cannot go back *up* the operator tree!
12382 * Options we have:
12383 * 1) Use of recursive functions (like is it currently done
12384 * via xmlXPathCompOpEval())
12385 * 2) Add a predicate evaluation information stack to the
12386 * context struct
12387 * 3) Change the way the operators are linked; we need a
12388 * "parent" field on xmlXPathStepOp
12389 *
12390 * For the moment, I'll try to solve this with a recursive
12391 * function: xmlXPathCompOpEvalPredicate().
12392 */
12393 size = seq->nodeNr;
12394 if (hasPredicateRange != 0)
12395 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12396 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12397 else
12398 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12399 predOp, seq, size, hasNsNodes);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012400
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012401 if (ctxt->error != XPATH_EXPRESSION_OK) {
12402 total = 0;
12403 goto error;
12404 }
12405 /*
12406 * Add the filtered set of nodes to the result node set.
12407 */
12408 if (newSize == 0) {
12409 /*
12410 * The predicates filtered all nodes out.
12411 */
12412 xmlXPathNodeSetClear(seq, hasNsNodes);
12413 } else if (seq->nodeNr > 0) {
12414 /*
12415 * Add to result set.
12416 */
12417 if (outSeq == NULL) {
12418 if (size != newSize) {
12419 /*
12420 * We need to merge and clear here, since
12421 * the sequence will contained NULLed entries.
12422 */
12423 outSeq = mergeAndClear(NULL, seq, 1);
12424 } else {
12425 outSeq = seq;
12426 seq = NULL;
12427 }
12428 } else
12429 outSeq = mergeAndClear(outSeq, seq,
12430 (size != newSize) ? 1: 0);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012431 /*
12432 * Break if only a true/false result was requested.
12433 */
12434 if (toBool)
12435 break;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012436 }
12437 } else if (seq->nodeNr > 0) {
12438 /*
12439 * Add to result set.
12440 */
12441 if (outSeq == NULL) {
12442 outSeq = seq;
12443 seq = NULL;
12444 } else {
12445 outSeq = mergeAndClear(outSeq, seq, 0);
12446 }
12447 }
12448 }
12449
12450error:
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012451 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012452 /*
12453 * QUESTION TODO: What does this do and why?
12454 * TODO: Do we have to do this also for the "error"
12455 * cleanup further down?
12456 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012457 ctxt->value->boolval = 1;
12458 ctxt->value->user = obj->user;
12459 obj->user = NULL;
12460 obj->boolval = 0;
12461 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012462 xmlXPathReleaseObject(xpctxt, obj);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012463
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012464 /*
12465 * Ensure we return at least an emtpy set.
12466 */
12467 if (outSeq == NULL) {
12468 if ((seq != NULL) && (seq->nodeNr == 0))
12469 outSeq = seq;
12470 else
12471 outSeq = xmlXPathNodeSetCreate(NULL);
12472 }
12473 if ((seq != NULL) && (seq != outSeq)) {
12474 xmlXPathFreeNodeSet(seq);
12475 }
12476 /*
12477 * Hand over the result. Better to push the set also in
12478 * case of errors.
12479 */
12480 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12481 /*
12482 * Reset the context node.
12483 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012484 xpctxt->node = oldContextNode;
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012485
12486#ifdef DEBUG_STEP
12487 xmlGenericError(xmlGenericErrorContext,
12488 "\nExamined %d nodes, found %d nodes at that step\n",
12489 total, nbMatches);
12490#endif
12491
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012492 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012493}
12494
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012495static int
12496xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12497 xmlXPathStepOpPtr op, xmlNodePtr * first);
12498
Daniel Veillardf06307e2001-07-03 10:35:50 +000012499/**
12500 * xmlXPathCompOpEvalFirst:
12501 * @ctxt: the XPath parser context with the compiled expression
12502 * @op: an XPath compiled operation
12503 * @first: the first elem found so far
12504 *
12505 * Evaluate the Precompiled XPath operation searching only the first
12506 * element in document order
12507 *
12508 * Returns the number of examined objects.
12509 */
12510static int
12511xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12512 xmlXPathStepOpPtr op, xmlNodePtr * first)
12513{
12514 int total = 0, cur;
12515 xmlXPathCompExprPtr comp;
12516 xmlXPathObjectPtr arg1, arg2;
12517
Daniel Veillard556c6682001-10-06 09:59:51 +000012518 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012519 comp = ctxt->comp;
12520 switch (op->op) {
12521 case XPATH_OP_END:
12522 return (0);
12523 case XPATH_OP_UNION:
12524 total =
12525 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12526 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012527 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012528 if ((ctxt->value != NULL)
12529 && (ctxt->value->type == XPATH_NODESET)
12530 && (ctxt->value->nodesetval != NULL)
12531 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12532 /*
12533 * limit tree traversing to first node in the result
12534 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012535 /*
12536 * OPTIMIZE TODO: This implicitely sorts
12537 * the result, even if not needed. E.g. if the argument
12538 * of the count() function, no sorting is needed.
12539 * OPTIMIZE TODO: How do we know if the node-list wasn't
12540 * aready sorted?
12541 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012542 if (ctxt->value->nodesetval->nodeNr > 1)
12543 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012544 *first = ctxt->value->nodesetval->nodeTab[0];
12545 }
12546 cur =
12547 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12548 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012549 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012550 CHECK_TYPE0(XPATH_NODESET);
12551 arg2 = valuePop(ctxt);
12552
12553 CHECK_TYPE0(XPATH_NODESET);
12554 arg1 = valuePop(ctxt);
12555
12556 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12557 arg2->nodesetval);
12558 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012559 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012560 /* optimizer */
12561 if (total > cur)
12562 xmlXPathCompSwap(op);
12563 return (total + cur);
12564 case XPATH_OP_ROOT:
12565 xmlXPathRoot(ctxt);
12566 return (0);
12567 case XPATH_OP_NODE:
12568 if (op->ch1 != -1)
12569 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012570 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012571 if (op->ch2 != -1)
12572 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012573 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012574 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12575 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012576 return (total);
12577 case XPATH_OP_RESET:
12578 if (op->ch1 != -1)
12579 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012580 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012581 if (op->ch2 != -1)
12582 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012583 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012584 ctxt->context->node = NULL;
12585 return (total);
12586 case XPATH_OP_COLLECT:{
12587 if (op->ch1 == -1)
12588 return (total);
12589
12590 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012591 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012592
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012593 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012594 return (total);
12595 }
12596 case XPATH_OP_VALUE:
12597 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012598 xmlXPathCacheObjectCopy(ctxt->context,
12599 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012600 return (0);
12601 case XPATH_OP_SORT:
12602 if (op->ch1 != -1)
12603 total +=
12604 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12605 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012606 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012607 if ((ctxt->value != NULL)
12608 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012609 && (ctxt->value->nodesetval != NULL)
12610 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012611 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12612 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012613#ifdef XP_OPTIMIZED_FILTER_FIRST
12614 case XPATH_OP_FILTER:
12615 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12616 return (total);
12617#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012618 default:
12619 return (xmlXPathCompOpEval(ctxt, op));
12620 }
12621}
12622
12623/**
12624 * xmlXPathCompOpEvalLast:
12625 * @ctxt: the XPath parser context with the compiled expression
12626 * @op: an XPath compiled operation
12627 * @last: the last elem found so far
12628 *
12629 * Evaluate the Precompiled XPath operation searching only the last
12630 * element in document order
12631 *
William M. Brack08171912003-12-29 02:52:11 +000012632 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012633 */
12634static int
12635xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12636 xmlNodePtr * last)
12637{
12638 int total = 0, cur;
12639 xmlXPathCompExprPtr comp;
12640 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012641 xmlNodePtr bak;
12642 xmlDocPtr bakd;
12643 int pp;
12644 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012645
Daniel Veillard556c6682001-10-06 09:59:51 +000012646 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012647 comp = ctxt->comp;
12648 switch (op->op) {
12649 case XPATH_OP_END:
12650 return (0);
12651 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012652 bakd = ctxt->context->doc;
12653 bak = ctxt->context->node;
12654 pp = ctxt->context->proximityPosition;
12655 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656 total =
12657 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012658 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012659 if ((ctxt->value != NULL)
12660 && (ctxt->value->type == XPATH_NODESET)
12661 && (ctxt->value->nodesetval != NULL)
12662 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12663 /*
12664 * limit tree traversing to first node in the result
12665 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012666 if (ctxt->value->nodesetval->nodeNr > 1)
12667 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012668 *last =
12669 ctxt->value->nodesetval->nodeTab[ctxt->value->
12670 nodesetval->nodeNr -
12671 1];
12672 }
William M. Brackce4fc562004-01-22 02:47:18 +000012673 ctxt->context->doc = bakd;
12674 ctxt->context->node = bak;
12675 ctxt->context->proximityPosition = pp;
12676 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012677 cur =
12678 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012679 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012680 if ((ctxt->value != NULL)
12681 && (ctxt->value->type == XPATH_NODESET)
12682 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012683 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012684 }
12685 CHECK_TYPE0(XPATH_NODESET);
12686 arg2 = valuePop(ctxt);
12687
12688 CHECK_TYPE0(XPATH_NODESET);
12689 arg1 = valuePop(ctxt);
12690
12691 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12692 arg2->nodesetval);
12693 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012694 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012695 /* optimizer */
12696 if (total > cur)
12697 xmlXPathCompSwap(op);
12698 return (total + cur);
12699 case XPATH_OP_ROOT:
12700 xmlXPathRoot(ctxt);
12701 return (0);
12702 case XPATH_OP_NODE:
12703 if (op->ch1 != -1)
12704 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012705 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012706 if (op->ch2 != -1)
12707 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012708 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012709 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12710 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012711 return (total);
12712 case XPATH_OP_RESET:
12713 if (op->ch1 != -1)
12714 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012715 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012716 if (op->ch2 != -1)
12717 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012718 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012719 ctxt->context->node = NULL;
12720 return (total);
12721 case XPATH_OP_COLLECT:{
12722 if (op->ch1 == -1)
12723 return (0);
12724
12725 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012726 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012727
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000012728 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012729 return (total);
12730 }
12731 case XPATH_OP_VALUE:
12732 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012733 xmlXPathCacheObjectCopy(ctxt->context,
12734 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012735 return (0);
12736 case XPATH_OP_SORT:
12737 if (op->ch1 != -1)
12738 total +=
12739 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12740 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012741 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012742 if ((ctxt->value != NULL)
12743 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012744 && (ctxt->value->nodesetval != NULL)
12745 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012746 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12747 return (total);
12748 default:
12749 return (xmlXPathCompOpEval(ctxt, op));
12750 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012751}
12752
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012753#ifdef XP_OPTIMIZED_FILTER_FIRST
12754static int
12755xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12756 xmlXPathStepOpPtr op, xmlNodePtr * first)
12757{
12758 int total = 0;
12759 xmlXPathCompExprPtr comp;
12760 xmlXPathObjectPtr res;
12761 xmlXPathObjectPtr obj;
12762 xmlNodeSetPtr oldset;
12763 xmlNodePtr oldnode;
12764 xmlDocPtr oldDoc;
12765 int i;
12766
12767 CHECK_ERROR0;
12768 comp = ctxt->comp;
12769 /*
12770 * Optimization for ()[last()] selection i.e. the last elem
12771 */
12772 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12773 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12774 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12775 int f = comp->steps[op->ch2].ch1;
12776
12777 if ((f != -1) &&
12778 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12779 (comp->steps[f].value5 == NULL) &&
12780 (comp->steps[f].value == 0) &&
12781 (comp->steps[f].value4 != NULL) &&
12782 (xmlStrEqual
12783 (comp->steps[f].value4, BAD_CAST "last"))) {
12784 xmlNodePtr last = NULL;
12785
12786 total +=
12787 xmlXPathCompOpEvalLast(ctxt,
12788 &comp->steps[op->ch1],
12789 &last);
12790 CHECK_ERROR0;
12791 /*
12792 * The nodeset should be in document order,
12793 * Keep only the last value
12794 */
12795 if ((ctxt->value != NULL) &&
12796 (ctxt->value->type == XPATH_NODESET) &&
12797 (ctxt->value->nodesetval != NULL) &&
12798 (ctxt->value->nodesetval->nodeTab != NULL) &&
12799 (ctxt->value->nodesetval->nodeNr > 1)) {
12800 ctxt->value->nodesetval->nodeTab[0] =
12801 ctxt->value->nodesetval->nodeTab[ctxt->
12802 value->
12803 nodesetval->
12804 nodeNr -
12805 1];
12806 ctxt->value->nodesetval->nodeNr = 1;
12807 *first = *(ctxt->value->nodesetval->nodeTab);
12808 }
12809 return (total);
12810 }
12811 }
12812
12813 if (op->ch1 != -1)
12814 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12815 CHECK_ERROR0;
12816 if (op->ch2 == -1)
12817 return (total);
12818 if (ctxt->value == NULL)
12819 return (total);
12820
12821#ifdef LIBXML_XPTR_ENABLED
12822 oldnode = ctxt->context->node;
12823 /*
12824 * Hum are we filtering the result of an XPointer expression
12825 */
12826 if (ctxt->value->type == XPATH_LOCATIONSET) {
12827 xmlXPathObjectPtr tmp = NULL;
12828 xmlLocationSetPtr newlocset = NULL;
12829 xmlLocationSetPtr oldlocset;
12830
12831 /*
12832 * Extract the old locset, and then evaluate the result of the
12833 * expression for all the element in the locset. use it to grow
12834 * up a new locset.
12835 */
12836 CHECK_TYPE0(XPATH_LOCATIONSET);
12837 obj = valuePop(ctxt);
12838 oldlocset = obj->user;
12839 ctxt->context->node = NULL;
12840
12841 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12842 ctxt->context->contextSize = 0;
12843 ctxt->context->proximityPosition = 0;
12844 if (op->ch2 != -1)
12845 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12846 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012847 if (res != NULL) {
12848 xmlXPathReleaseObject(ctxt->context, res);
12849 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012850 valuePush(ctxt, obj);
12851 CHECK_ERROR0;
12852 return (total);
12853 }
12854 newlocset = xmlXPtrLocationSetCreate(NULL);
12855
12856 for (i = 0; i < oldlocset->locNr; i++) {
12857 /*
12858 * Run the evaluation with a node list made of a
12859 * single item in the nodelocset.
12860 */
12861 ctxt->context->node = oldlocset->locTab[i]->user;
12862 ctxt->context->contextSize = oldlocset->locNr;
12863 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012864 if (tmp == NULL) {
12865 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12866 ctxt->context->node);
12867 } else {
12868 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12869 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012870 }
12871 valuePush(ctxt, tmp);
12872 if (op->ch2 != -1)
12873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12874 if (ctxt->error != XPATH_EXPRESSION_OK) {
12875 xmlXPathFreeObject(obj);
12876 return(0);
12877 }
12878 /*
12879 * The result of the evaluation need to be tested to
12880 * decided whether the filter succeeded or not
12881 */
12882 res = valuePop(ctxt);
12883 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12884 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012885 xmlXPathCacheObjectCopy(ctxt->context,
12886 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012887 }
12888 /*
12889 * Cleanup
12890 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012891 if (res != NULL) {
12892 xmlXPathReleaseObject(ctxt->context, res);
12893 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012894 if (ctxt->value == tmp) {
12895 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000012896 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012897 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012898 * REVISIT TODO: Don't create a temporary nodeset
12899 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012900 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012901 /* OLD: xmlXPathFreeObject(res); */
12902 } else
12903 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012904 ctxt->context->node = NULL;
12905 /*
12906 * Only put the first node in the result, then leave.
12907 */
12908 if (newlocset->locNr > 0) {
12909 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12910 break;
12911 }
12912 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012913 if (tmp != NULL) {
12914 xmlXPathReleaseObject(ctxt->context, tmp);
12915 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012916 /*
12917 * The result is used as the new evaluation locset.
12918 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012919 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012920 ctxt->context->node = NULL;
12921 ctxt->context->contextSize = -1;
12922 ctxt->context->proximityPosition = -1;
12923 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12924 ctxt->context->node = oldnode;
12925 return (total);
12926 }
12927#endif /* LIBXML_XPTR_ENABLED */
12928
12929 /*
12930 * Extract the old set, and then evaluate the result of the
12931 * expression for all the element in the set. use it to grow
12932 * up a new set.
12933 */
12934 CHECK_TYPE0(XPATH_NODESET);
12935 obj = valuePop(ctxt);
12936 oldset = obj->nodesetval;
12937
12938 oldnode = ctxt->context->node;
12939 oldDoc = ctxt->context->doc;
12940 ctxt->context->node = NULL;
12941
12942 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12943 ctxt->context->contextSize = 0;
12944 ctxt->context->proximityPosition = 0;
12945 /* QUESTION TODO: Why was this code commented out?
12946 if (op->ch2 != -1)
12947 total +=
12948 xmlXPathCompOpEval(ctxt,
12949 &comp->steps[op->ch2]);
12950 CHECK_ERROR0;
12951 res = valuePop(ctxt);
12952 if (res != NULL)
12953 xmlXPathFreeObject(res);
12954 */
12955 valuePush(ctxt, obj);
12956 ctxt->context->node = oldnode;
12957 CHECK_ERROR0;
12958 } else {
12959 xmlNodeSetPtr newset;
12960 xmlXPathObjectPtr tmp = NULL;
12961 /*
12962 * Initialize the new set.
12963 * Also set the xpath document in case things like
12964 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012965 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012966 newset = xmlXPathNodeSetCreate(NULL);
12967
12968 for (i = 0; i < oldset->nodeNr; i++) {
12969 /*
12970 * Run the evaluation with a node list made of
12971 * a single item in the nodeset.
12972 */
12973 ctxt->context->node = oldset->nodeTab[i];
12974 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12975 (oldset->nodeTab[i]->doc != NULL))
12976 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012977 if (tmp == NULL) {
12978 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12979 ctxt->context->node);
12980 } else {
12981 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12982 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012983 }
12984 valuePush(ctxt, tmp);
12985 ctxt->context->contextSize = oldset->nodeNr;
12986 ctxt->context->proximityPosition = i + 1;
12987 if (op->ch2 != -1)
12988 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12989 if (ctxt->error != XPATH_EXPRESSION_OK) {
12990 xmlXPathFreeNodeSet(newset);
12991 xmlXPathFreeObject(obj);
12992 return(0);
12993 }
12994 /*
12995 * The result of the evaluation needs to be tested to
12996 * decide whether the filter succeeded or not
12997 */
12998 res = valuePop(ctxt);
12999 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13000 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13001 }
13002 /*
13003 * Cleanup
13004 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013005 if (res != NULL) {
13006 xmlXPathReleaseObject(ctxt->context, res);
13007 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013008 if (ctxt->value == tmp) {
13009 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013010 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013011 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013012 * in order to avoid massive recreation inside this
13013 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013014 */
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013015 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013016 } else
13017 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013018 ctxt->context->node = NULL;
13019 /*
13020 * Only put the first node in the result, then leave.
13021 */
13022 if (newset->nodeNr > 0) {
13023 *first = *(newset->nodeTab);
13024 break;
13025 }
13026 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013027 if (tmp != NULL) {
13028 xmlXPathReleaseObject(ctxt->context, tmp);
13029 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013030 /*
13031 * The result is used as the new evaluation set.
13032 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013033 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013034 ctxt->context->node = NULL;
13035 ctxt->context->contextSize = -1;
13036 ctxt->context->proximityPosition = -1;
13037 /* may want to move this past the '}' later */
13038 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013039 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013040 }
13041 ctxt->context->node = oldnode;
13042 return(total);
13043}
13044#endif /* XP_OPTIMIZED_FILTER_FIRST */
13045
Owen Taylor3473f882001-02-23 17:55:21 +000013046/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013047 * xmlXPathCompOpEval:
13048 * @ctxt: the XPath parser context with the compiled expression
13049 * @op: an XPath compiled operation
13050 *
13051 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000013052 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013053 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013054static int
13055xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13056{
13057 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013058 int equal, ret;
13059 xmlXPathCompExprPtr comp;
13060 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013061 xmlNodePtr bak;
13062 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000013063 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000013064 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013065
Daniel Veillard556c6682001-10-06 09:59:51 +000013066 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013067 comp = ctxt->comp;
13068 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013069 case XPATH_OP_END:
13070 return (0);
13071 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013072 bakd = ctxt->context->doc;
13073 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013074 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013075 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013076 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013077 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013078 xmlXPathBooleanFunction(ctxt, 1);
13079 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13080 return (total);
13081 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013082 ctxt->context->doc = bakd;
13083 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013084 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013085 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013087 if (ctxt->error) {
13088 xmlXPathFreeObject(arg2);
13089 return(0);
13090 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013091 xmlXPathBooleanFunction(ctxt, 1);
13092 arg1 = valuePop(ctxt);
13093 arg1->boolval &= arg2->boolval;
13094 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013095 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013096 return (total);
13097 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013098 bakd = ctxt->context->doc;
13099 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013100 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013101 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013102 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013103 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013104 xmlXPathBooleanFunction(ctxt, 1);
13105 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13106 return (total);
13107 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013108 ctxt->context->doc = bakd;
13109 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013110 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013111 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013113 if (ctxt->error) {
13114 xmlXPathFreeObject(arg2);
13115 return(0);
13116 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013117 xmlXPathBooleanFunction(ctxt, 1);
13118 arg1 = valuePop(ctxt);
13119 arg1->boolval |= arg2->boolval;
13120 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013121 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013122 return (total);
13123 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013124 bakd = ctxt->context->doc;
13125 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013126 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013127 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013129 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013130 ctxt->context->doc = bakd;
13131 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013132 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013133 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013134 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013135 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000013136 if (op->value)
13137 equal = xmlXPathEqualValues(ctxt);
13138 else
13139 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013140 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013141 return (total);
13142 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013143 bakd = ctxt->context->doc;
13144 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013145 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013146 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013147 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013148 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013149 ctxt->context->doc = bakd;
13150 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013151 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013152 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013153 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013154 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013155 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013156 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013157 return (total);
13158 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013159 bakd = ctxt->context->doc;
13160 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013161 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013162 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013163 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013164 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013165 if (op->ch2 != -1) {
13166 ctxt->context->doc = bakd;
13167 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013168 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013169 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013171 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013172 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013173 if (op->value == 0)
13174 xmlXPathSubValues(ctxt);
13175 else if (op->value == 1)
13176 xmlXPathAddValues(ctxt);
13177 else if (op->value == 2)
13178 xmlXPathValueFlipSign(ctxt);
13179 else if (op->value == 3) {
13180 CAST_TO_NUMBER;
13181 CHECK_TYPE0(XPATH_NUMBER);
13182 }
13183 return (total);
13184 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013185 bakd = ctxt->context->doc;
13186 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013187 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013188 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013189 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013190 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013191 ctxt->context->doc = bakd;
13192 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013193 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013194 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013195 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013196 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013197 if (op->value == 0)
13198 xmlXPathMultValues(ctxt);
13199 else if (op->value == 1)
13200 xmlXPathDivValues(ctxt);
13201 else if (op->value == 2)
13202 xmlXPathModValues(ctxt);
13203 return (total);
13204 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013205 bakd = ctxt->context->doc;
13206 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000013207 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000013208 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013210 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000013211 ctxt->context->doc = bakd;
13212 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000013213 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000013214 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013216 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013217 CHECK_TYPE0(XPATH_NODESET);
13218 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013219
Daniel Veillardf06307e2001-07-03 10:35:50 +000013220 CHECK_TYPE0(XPATH_NODESET);
13221 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013222
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013223 if ((arg1->nodesetval == NULL) ||
13224 ((arg2->nodesetval != NULL) &&
13225 (arg2->nodesetval->nodeNr != 0)))
13226 {
13227 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13228 arg2->nodesetval);
13229 }
13230
Daniel Veillardf06307e2001-07-03 10:35:50 +000013231 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013232 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013233 return (total);
13234 case XPATH_OP_ROOT:
13235 xmlXPathRoot(ctxt);
13236 return (total);
13237 case XPATH_OP_NODE:
13238 if (op->ch1 != -1)
13239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013240 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013241 if (op->ch2 != -1)
13242 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013243 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013244 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13245 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013246 return (total);
13247 case XPATH_OP_RESET:
13248 if (op->ch1 != -1)
13249 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013250 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013251 if (op->ch2 != -1)
13252 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013253 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013254 ctxt->context->node = NULL;
13255 return (total);
13256 case XPATH_OP_COLLECT:{
13257 if (op->ch1 == -1)
13258 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013259
Daniel Veillardf06307e2001-07-03 10:35:50 +000013260 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013261 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013262
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013263 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013264 return (total);
13265 }
13266 case XPATH_OP_VALUE:
13267 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013268 xmlXPathCacheObjectCopy(ctxt->context,
13269 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013270 return (total);
13271 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000013272 xmlXPathObjectPtr val;
13273
Daniel Veillardf06307e2001-07-03 10:35:50 +000013274 if (op->ch1 != -1)
13275 total +=
13276 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013277 if (op->value5 == NULL) {
13278 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13279 if (val == NULL) {
13280 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13281 return(0);
13282 }
13283 valuePush(ctxt, val);
13284 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013285 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013286
Daniel Veillardf06307e2001-07-03 10:35:50 +000013287 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13288 if (URI == NULL) {
13289 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013290 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013291 op->value4, op->value5);
13292 return (total);
13293 }
Daniel Veillard556c6682001-10-06 09:59:51 +000013294 val = xmlXPathVariableLookupNS(ctxt->context,
13295 op->value4, URI);
13296 if (val == NULL) {
13297 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13298 return(0);
13299 }
13300 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013301 }
13302 return (total);
13303 }
13304 case XPATH_OP_FUNCTION:{
13305 xmlXPathFunction func;
13306 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000013307 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013308
13309 if (op->ch1 != -1)
13310 total +=
13311 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013312 if (ctxt->valueNr < op->value) {
13313 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013314 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013315 ctxt->error = XPATH_INVALID_OPERAND;
13316 return (total);
13317 }
13318 for (i = 0; i < op->value; i++)
13319 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13320 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013321 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013322 ctxt->error = XPATH_INVALID_OPERAND;
13323 return (total);
13324 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013325 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013326 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013327 else {
13328 const xmlChar *URI = NULL;
13329
13330 if (op->value5 == NULL)
13331 func =
13332 xmlXPathFunctionLookup(ctxt->context,
13333 op->value4);
13334 else {
13335 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13336 if (URI == NULL) {
13337 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013338 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013339 op->value4, op->value5);
13340 return (total);
13341 }
13342 func = xmlXPathFunctionLookupNS(ctxt->context,
13343 op->value4, URI);
13344 }
13345 if (func == NULL) {
13346 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013347 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013348 op->value4);
13349 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013350 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013351 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013352 op->cacheURI = (void *) URI;
13353 }
13354 oldFunc = ctxt->context->function;
13355 oldFuncURI = ctxt->context->functionURI;
13356 ctxt->context->function = op->value4;
13357 ctxt->context->functionURI = op->cacheURI;
13358 func(ctxt, op->value);
13359 ctxt->context->function = oldFunc;
13360 ctxt->context->functionURI = oldFuncURI;
13361 return (total);
13362 }
13363 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013364 bakd = ctxt->context->doc;
13365 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013366 pp = ctxt->context->proximityPosition;
13367 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013368 if (op->ch1 != -1)
13369 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013370 ctxt->context->contextSize = cs;
13371 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013372 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013373 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013374 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013375 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013376 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013377 ctxt->context->doc = bakd;
13378 ctxt->context->node = bak;
13379 CHECK_ERROR0;
13380 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013381 return (total);
13382 case XPATH_OP_PREDICATE:
13383 case XPATH_OP_FILTER:{
13384 xmlXPathObjectPtr res;
13385 xmlXPathObjectPtr obj, tmp;
13386 xmlNodeSetPtr newset = NULL;
13387 xmlNodeSetPtr oldset;
13388 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013389 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013390 int i;
13391
13392 /*
13393 * Optimization for ()[1] selection i.e. the first elem
13394 */
13395 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013396#ifdef XP_OPTIMIZED_FILTER_FIRST
13397 /*
13398 * FILTER TODO: Can we assume that the inner processing
13399 * will result in an ordered list if we have an
13400 * XPATH_OP_FILTER?
13401 * What about an additional field or flag on
13402 * xmlXPathObject like @sorted ? This way we wouln'd need
13403 * to assume anything, so it would be more robust and
13404 * easier to optimize.
13405 */
13406 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13407 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13408#else
13409 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13410#endif
13411 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013412 xmlXPathObjectPtr val;
13413
13414 val = comp->steps[op->ch2].value4;
13415 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13416 (val->floatval == 1.0)) {
13417 xmlNodePtr first = NULL;
13418
13419 total +=
13420 xmlXPathCompOpEvalFirst(ctxt,
13421 &comp->steps[op->ch1],
13422 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013423 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013424 /*
13425 * The nodeset should be in document order,
13426 * Keep only the first value
13427 */
13428 if ((ctxt->value != NULL) &&
13429 (ctxt->value->type == XPATH_NODESET) &&
13430 (ctxt->value->nodesetval != NULL) &&
13431 (ctxt->value->nodesetval->nodeNr > 1))
13432 ctxt->value->nodesetval->nodeNr = 1;
13433 return (total);
13434 }
13435 }
13436 /*
13437 * Optimization for ()[last()] selection i.e. the last elem
13438 */
13439 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13440 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13441 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13442 int f = comp->steps[op->ch2].ch1;
13443
13444 if ((f != -1) &&
13445 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13446 (comp->steps[f].value5 == NULL) &&
13447 (comp->steps[f].value == 0) &&
13448 (comp->steps[f].value4 != NULL) &&
13449 (xmlStrEqual
13450 (comp->steps[f].value4, BAD_CAST "last"))) {
13451 xmlNodePtr last = NULL;
13452
13453 total +=
13454 xmlXPathCompOpEvalLast(ctxt,
13455 &comp->steps[op->ch1],
13456 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013457 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013458 /*
13459 * The nodeset should be in document order,
13460 * Keep only the last value
13461 */
13462 if ((ctxt->value != NULL) &&
13463 (ctxt->value->type == XPATH_NODESET) &&
13464 (ctxt->value->nodesetval != NULL) &&
13465 (ctxt->value->nodesetval->nodeTab != NULL) &&
13466 (ctxt->value->nodesetval->nodeNr > 1)) {
13467 ctxt->value->nodesetval->nodeTab[0] =
13468 ctxt->value->nodesetval->nodeTab[ctxt->
13469 value->
13470 nodesetval->
13471 nodeNr -
13472 1];
13473 ctxt->value->nodesetval->nodeNr = 1;
13474 }
13475 return (total);
13476 }
13477 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013478 /*
13479 * Process inner predicates first.
13480 * Example "index[parent::book][1]":
13481 * ...
13482 * PREDICATE <-- we are here "[1]"
13483 * PREDICATE <-- process "[parent::book]" first
13484 * SORT
13485 * COLLECT 'parent' 'name' 'node' book
13486 * NODE
13487 * ELEM Object is a number : 1
13488 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013489 if (op->ch1 != -1)
13490 total +=
13491 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013492 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013493 if (op->ch2 == -1)
13494 return (total);
13495 if (ctxt->value == NULL)
13496 return (total);
13497
13498 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013499
13500#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013501 /*
13502 * Hum are we filtering the result of an XPointer expression
13503 */
13504 if (ctxt->value->type == XPATH_LOCATIONSET) {
13505 xmlLocationSetPtr newlocset = NULL;
13506 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013507
Daniel Veillardf06307e2001-07-03 10:35:50 +000013508 /*
13509 * Extract the old locset, and then evaluate the result of the
13510 * expression for all the element in the locset. use it to grow
13511 * up a new locset.
13512 */
13513 CHECK_TYPE0(XPATH_LOCATIONSET);
13514 obj = valuePop(ctxt);
13515 oldlocset = obj->user;
13516 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013517
Daniel Veillardf06307e2001-07-03 10:35:50 +000013518 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13519 ctxt->context->contextSize = 0;
13520 ctxt->context->proximityPosition = 0;
13521 if (op->ch2 != -1)
13522 total +=
13523 xmlXPathCompOpEval(ctxt,
13524 &comp->steps[op->ch2]);
13525 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013526 if (res != NULL) {
13527 xmlXPathReleaseObject(ctxt->context, res);
13528 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013529 valuePush(ctxt, obj);
13530 CHECK_ERROR0;
13531 return (total);
13532 }
13533 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013534
Daniel Veillardf06307e2001-07-03 10:35:50 +000013535 for (i = 0; i < oldlocset->locNr; i++) {
13536 /*
13537 * Run the evaluation with a node list made of a
13538 * single item in the nodelocset.
13539 */
13540 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013541 ctxt->context->contextSize = oldlocset->locNr;
13542 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013543 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13544 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013545 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013546
Daniel Veillardf06307e2001-07-03 10:35:50 +000013547 if (op->ch2 != -1)
13548 total +=
13549 xmlXPathCompOpEval(ctxt,
13550 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013551 if (ctxt->error != XPATH_EXPRESSION_OK) {
13552 xmlXPathFreeObject(obj);
13553 return(0);
13554 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013555
Daniel Veillardf06307e2001-07-03 10:35:50 +000013556 /*
13557 * The result of the evaluation need to be tested to
13558 * decided whether the filter succeeded or not
13559 */
13560 res = valuePop(ctxt);
13561 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13562 xmlXPtrLocationSetAdd(newlocset,
13563 xmlXPathObjectCopy
13564 (oldlocset->locTab[i]));
13565 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013566
Daniel Veillardf06307e2001-07-03 10:35:50 +000013567 /*
13568 * Cleanup
13569 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013570 if (res != NULL) {
13571 xmlXPathReleaseObject(ctxt->context, res);
13572 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013573 if (ctxt->value == tmp) {
13574 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013575 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013576 }
13577
13578 ctxt->context->node = NULL;
13579 }
13580
13581 /*
13582 * The result is used as the new evaluation locset.
13583 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013584 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013585 ctxt->context->node = NULL;
13586 ctxt->context->contextSize = -1;
13587 ctxt->context->proximityPosition = -1;
13588 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13589 ctxt->context->node = oldnode;
13590 return (total);
13591 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013592#endif /* LIBXML_XPTR_ENABLED */
13593
Daniel Veillardf06307e2001-07-03 10:35:50 +000013594 /*
13595 * Extract the old set, and then evaluate the result of the
13596 * expression for all the element in the set. use it to grow
13597 * up a new set.
13598 */
13599 CHECK_TYPE0(XPATH_NODESET);
13600 obj = valuePop(ctxt);
13601 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013602
Daniel Veillardf06307e2001-07-03 10:35:50 +000013603 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013604 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013605 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013606
Daniel Veillardf06307e2001-07-03 10:35:50 +000013607 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13608 ctxt->context->contextSize = 0;
13609 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013610/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013611 if (op->ch2 != -1)
13612 total +=
13613 xmlXPathCompOpEval(ctxt,
13614 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013615 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013616 res = valuePop(ctxt);
13617 if (res != NULL)
13618 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013619*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013620 valuePush(ctxt, obj);
13621 ctxt->context->node = oldnode;
13622 CHECK_ERROR0;
13623 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013624 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013625 /*
13626 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013627 * Also set the xpath document in case things like
13628 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013629 */
13630 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013631 /*
13632 * SPEC XPath 1.0:
13633 * "For each node in the node-set to be filtered, the
13634 * PredicateExpr is evaluated with that node as the
13635 * context node, with the number of nodes in the
13636 * node-set as the context size, and with the proximity
13637 * position of the node in the node-set with respect to
13638 * the axis as the context position;"
13639 * @oldset is the node-set" to be filtered.
13640 *
13641 * SPEC XPath 1.0:
13642 * "only predicates change the context position and
13643 * context size (see [2.4 Predicates])."
13644 * Example:
13645 * node-set context pos
13646 * nA 1
13647 * nB 2
13648 * nC 3
13649 * After applying predicate [position() > 1] :
13650 * node-set context pos
13651 * nB 1
13652 * nC 2
13653 *
13654 * removed the first node in the node-set, then
13655 * the context position of the
13656 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013657 for (i = 0; i < oldset->nodeNr; i++) {
13658 /*
13659 * Run the evaluation with a node list made of
13660 * a single item in the nodeset.
13661 */
13662 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013663 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13664 (oldset->nodeTab[i]->doc != NULL))
13665 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013666 if (tmp == NULL) {
13667 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13668 ctxt->context->node);
13669 } else {
13670 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13671 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013672 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013673 valuePush(ctxt, tmp);
13674 ctxt->context->contextSize = oldset->nodeNr;
13675 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013676 /*
13677 * Evaluate the predicate against the context node.
13678 * Can/should we optimize position() predicates
13679 * here (e.g. "[1]")?
13680 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013681 if (op->ch2 != -1)
13682 total +=
13683 xmlXPathCompOpEval(ctxt,
13684 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013685 if (ctxt->error != XPATH_EXPRESSION_OK) {
13686 xmlXPathFreeNodeSet(newset);
13687 xmlXPathFreeObject(obj);
13688 return(0);
13689 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013690
Daniel Veillardf06307e2001-07-03 10:35:50 +000013691 /*
William M. Brack08171912003-12-29 02:52:11 +000013692 * The result of the evaluation needs to be tested to
13693 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013694 */
13695 /*
13696 * OPTIMIZE TODO: Can we use
13697 * xmlXPathNodeSetAdd*Unique()* instead?
13698 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013699 res = valuePop(ctxt);
13700 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13701 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13702 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013703
Daniel Veillardf06307e2001-07-03 10:35:50 +000013704 /*
13705 * Cleanup
13706 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013707 if (res != NULL) {
13708 xmlXPathReleaseObject(ctxt->context, res);
13709 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013710 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013711 valuePop(ctxt);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000013712 xmlXPathNodeSetClear(tmp->nodesetval, 1);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013713 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013714 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013715 * in order to avoid massive recreation inside this
13716 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013717 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013718 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013719 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013720 ctxt->context->node = NULL;
13721 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013722 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013723 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013724 /*
13725 * The result is used as the new evaluation set.
13726 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013727 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013728 ctxt->context->node = NULL;
13729 ctxt->context->contextSize = -1;
13730 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013731 /* may want to move this past the '}' later */
13732 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013733 valuePush(ctxt,
13734 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013735 }
13736 ctxt->context->node = oldnode;
13737 return (total);
13738 }
13739 case XPATH_OP_SORT:
13740 if (op->ch1 != -1)
13741 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013742 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013743 if ((ctxt->value != NULL) &&
13744 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013745 (ctxt->value->nodesetval != NULL) &&
13746 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013747 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013748 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013749 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013750 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013751#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013752 case XPATH_OP_RANGETO:{
13753 xmlXPathObjectPtr range;
13754 xmlXPathObjectPtr res, obj;
13755 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013756 xmlLocationSetPtr newlocset = NULL;
13757 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013758 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013759 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013760
Daniel Veillardf06307e2001-07-03 10:35:50 +000013761 if (op->ch1 != -1)
13762 total +=
13763 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13764 if (op->ch2 == -1)
13765 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013766
William M. Brack08171912003-12-29 02:52:11 +000013767 if (ctxt->value->type == XPATH_LOCATIONSET) {
13768 /*
13769 * Extract the old locset, and then evaluate the result of the
13770 * expression for all the element in the locset. use it to grow
13771 * up a new locset.
13772 */
13773 CHECK_TYPE0(XPATH_LOCATIONSET);
13774 obj = valuePop(ctxt);
13775 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013776
William M. Brack08171912003-12-29 02:52:11 +000013777 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013778 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013779 ctxt->context->contextSize = 0;
13780 ctxt->context->proximityPosition = 0;
13781 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13782 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013783 if (res != NULL) {
13784 xmlXPathReleaseObject(ctxt->context, res);
13785 }
William M. Brack08171912003-12-29 02:52:11 +000013786 valuePush(ctxt, obj);
13787 CHECK_ERROR0;
13788 return (total);
13789 }
13790 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013791
William M. Brack08171912003-12-29 02:52:11 +000013792 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013793 /*
William M. Brack08171912003-12-29 02:52:11 +000013794 * Run the evaluation with a node list made of a
13795 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013796 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013797 ctxt->context->node = oldlocset->locTab[i]->user;
13798 ctxt->context->contextSize = oldlocset->locNr;
13799 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013800 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013802 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013803
Daniel Veillardf06307e2001-07-03 10:35:50 +000013804 if (op->ch2 != -1)
13805 total +=
13806 xmlXPathCompOpEval(ctxt,
13807 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013808 if (ctxt->error != XPATH_EXPRESSION_OK) {
13809 xmlXPathFreeObject(obj);
13810 return(0);
13811 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013812
Daniel Veillardf06307e2001-07-03 10:35:50 +000013813 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013814 if (res->type == XPATH_LOCATIONSET) {
13815 xmlLocationSetPtr rloc =
13816 (xmlLocationSetPtr)res->user;
13817 for (j=0; j<rloc->locNr; j++) {
13818 range = xmlXPtrNewRange(
13819 oldlocset->locTab[i]->user,
13820 oldlocset->locTab[i]->index,
13821 rloc->locTab[j]->user2,
13822 rloc->locTab[j]->index2);
13823 if (range != NULL) {
13824 xmlXPtrLocationSetAdd(newlocset, range);
13825 }
13826 }
13827 } else {
13828 range = xmlXPtrNewRangeNodeObject(
13829 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13830 if (range != NULL) {
13831 xmlXPtrLocationSetAdd(newlocset,range);
13832 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013833 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013834
Daniel Veillardf06307e2001-07-03 10:35:50 +000013835 /*
13836 * Cleanup
13837 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013838 if (res != NULL) {
13839 xmlXPathReleaseObject(ctxt->context, res);
13840 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013841 if (ctxt->value == tmp) {
13842 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013843 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013844 }
13845
13846 ctxt->context->node = NULL;
13847 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013848 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013849 CHECK_TYPE0(XPATH_NODESET);
13850 obj = valuePop(ctxt);
13851 oldset = obj->nodesetval;
13852 ctxt->context->node = NULL;
13853
13854 newlocset = xmlXPtrLocationSetCreate(NULL);
13855
13856 if (oldset != NULL) {
13857 for (i = 0; i < oldset->nodeNr; i++) {
13858 /*
13859 * Run the evaluation with a node list made of a single item
13860 * in the nodeset.
13861 */
13862 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013863 /*
13864 * OPTIMIZE TODO: Avoid recreation for every iteration.
13865 */
13866 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13867 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013868 valuePush(ctxt, tmp);
13869
13870 if (op->ch2 != -1)
13871 total +=
13872 xmlXPathCompOpEval(ctxt,
13873 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013874 if (ctxt->error != XPATH_EXPRESSION_OK) {
13875 xmlXPathFreeObject(obj);
13876 return(0);
13877 }
William M. Brack08171912003-12-29 02:52:11 +000013878
William M. Brack08171912003-12-29 02:52:11 +000013879 res = valuePop(ctxt);
13880 range =
13881 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13882 res);
13883 if (range != NULL) {
13884 xmlXPtrLocationSetAdd(newlocset, range);
13885 }
13886
13887 /*
13888 * Cleanup
13889 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013890 if (res != NULL) {
13891 xmlXPathReleaseObject(ctxt->context, res);
13892 }
William M. Brack08171912003-12-29 02:52:11 +000013893 if (ctxt->value == tmp) {
13894 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013895 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013896 }
13897
13898 ctxt->context->node = NULL;
13899 }
13900 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013901 }
13902
13903 /*
13904 * The result is used as the new evaluation set.
13905 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013906 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013907 ctxt->context->node = NULL;
13908 ctxt->context->contextSize = -1;
13909 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013910 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013911 return (total);
13912 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013913#endif /* LIBXML_XPTR_ENABLED */
13914 }
13915 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013916 "XPath: unknown precompiled operation %d\n", op->op);
13917 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013918}
13919
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013920/**
13921 * xmlXPathCompOpEvalToBoolean:
13922 * @ctxt: the XPath parser context
13923 *
13924 * Evaluates if the expression evaluates to true.
13925 *
13926 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13927 */
13928static int
13929xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013930 xmlXPathStepOpPtr op,
13931 int isPredicate)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013932{
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013933 xmlXPathObjectPtr resObj = NULL;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013934
13935start:
13936 /* comp = ctxt->comp; */
13937 switch (op->op) {
13938 case XPATH_OP_END:
13939 return (0);
13940 case XPATH_OP_VALUE:
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013941 resObj = (xmlXPathObjectPtr) op->value4;
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013942 if (isPredicate)
13943 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13944 return(xmlXPathCastToBoolean(resObj));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013945 case XPATH_OP_SORT:
13946 /*
13947 * We don't need sorting for boolean results. Skip this one.
13948 */
13949 if (op->ch1 != -1) {
13950 op = &ctxt->comp->steps[op->ch1];
13951 goto start;
13952 }
13953 return(0);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013954 case XPATH_OP_COLLECT:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013955 if (op->ch1 == -1)
13956 return(0);
13957
13958 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13959 if (ctxt->error != XPATH_EXPRESSION_OK)
13960 return(-1);
13961
13962 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13963 if (ctxt->error != XPATH_EXPRESSION_OK)
13964 return(-1);
13965
13966 resObj = valuePop(ctxt);
13967 if (resObj == NULL)
13968 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013969 break;
13970 default:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013971 /*
13972 * Fallback to call xmlXPathCompOpEval().
13973 */
13974 xmlXPathCompOpEval(ctxt, op);
13975 if (ctxt->error != XPATH_EXPRESSION_OK)
13976 return(-1);
13977
13978 resObj = valuePop(ctxt);
13979 if (resObj == NULL)
Kasimier T. Buchcik2bdb12f2006-06-29 10:49:59 +000013980 return(-1);
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013981 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000013982 }
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000013983
13984 if (resObj) {
13985 int res;
13986
13987 if (resObj->type == XPATH_BOOLEAN) {
13988 res = resObj->boolval;
13989 } else if (isPredicate) {
13990 /*
13991 * For predicates a result of type "number" is handled
13992 * differently:
13993 * SPEC XPath 1.0:
13994 * "If the result is a number, the result will be converted
13995 * to true if the number is equal to the context position
13996 * and will be converted to false otherwise;"
13997 */
13998 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13999 } else {
14000 res = xmlXPathCastToBoolean(resObj);
14001 }
14002 xmlXPathReleaseObject(ctxt->context, resObj);
14003 return(res);
14004 }
14005
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014006 return(0);
14007}
14008
Daniel Veillard56de87e2005-02-16 00:22:29 +000014009#ifdef XPATH_STREAMING
14010/**
14011 * xmlXPathRunStreamEval:
14012 * @ctxt: the XPath parser context with the compiled expression
14013 *
14014 * Evaluate the Precompiled Streamable XPath expression in the given context.
14015 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014016static int
14017xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14018 xmlXPathObjectPtr *resultSeq, int toBool)
14019{
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014020 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014021 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014022 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014023 int eval_all_nodes;
William M. Brack12d37ab2005-02-21 13:54:07 +000014024 xmlNodePtr cur = NULL, limit = NULL;
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014025 xmlStreamCtxtPtr patstream = NULL;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014026
14027 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014028
14029 if ((ctxt == NULL) || (comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014030 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014031 max_depth = xmlPatternMaxDepth(comp);
14032 if (max_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014033 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014034 if (max_depth == -2)
14035 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014036 min_depth = xmlPatternMinDepth(comp);
14037 if (min_depth == -1)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014038 return(-1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014039 from_root = xmlPatternFromRoot(comp);
14040 if (from_root < 0)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014041 return(-1);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014042#if 0
14043 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14044#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000014045
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014046 if (! toBool) {
14047 if (resultSeq == NULL)
14048 return(-1);
14049 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14050 if (*resultSeq == NULL)
14051 return(-1);
14052 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014053
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014054 /*
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014055 * handle the special cases of "/" amd "." being matched
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014056 */
14057 if (min_depth == 0) {
14058 if (from_root) {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014059 /* Select "/" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014060 if (toBool)
14061 return(1);
14062 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14063 (xmlNodePtr) ctxt->doc);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014064 } else {
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014065 /* Select "self::node()" */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014066 if (toBool)
14067 return(1);
14068 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014069 }
14070 }
14071 if (max_depth == 0) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014072 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014073 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000014074
Daniel Veillard56de87e2005-02-16 00:22:29 +000014075 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000014076 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014077 } else if (ctxt->node != NULL) {
14078 switch (ctxt->node->type) {
14079 case XML_ELEMENT_NODE:
14080 case XML_DOCUMENT_NODE:
14081 case XML_DOCUMENT_FRAG_NODE:
14082 case XML_HTML_DOCUMENT_NODE:
14083#ifdef LIBXML_DOCB_ENABLED
14084 case XML_DOCB_DOCUMENT_NODE:
14085#endif
14086 cur = ctxt->node;
14087 break;
14088 case XML_ATTRIBUTE_NODE:
14089 case XML_TEXT_NODE:
14090 case XML_CDATA_SECTION_NODE:
14091 case XML_ENTITY_REF_NODE:
14092 case XML_ENTITY_NODE:
14093 case XML_PI_NODE:
14094 case XML_COMMENT_NODE:
14095 case XML_NOTATION_NODE:
14096 case XML_DTD_NODE:
14097 case XML_DOCUMENT_TYPE_NODE:
14098 case XML_ELEMENT_DECL:
14099 case XML_ATTRIBUTE_DECL:
14100 case XML_ENTITY_DECL:
14101 case XML_NAMESPACE_DECL:
14102 case XML_XINCLUDE_START:
14103 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000014104 break;
14105 }
14106 limit = cur;
14107 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014108 if (cur == NULL) {
14109 return(0);
14110 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014111
14112 patstream = xmlPatternGetStreamCtxt(comp);
14113 if (patstream == NULL) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014114 /*
14115 * QUESTION TODO: Is this an error?
14116 */
14117 return(0);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014118 }
14119
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014120 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014121
Daniel Veillard56de87e2005-02-16 00:22:29 +000014122 if (from_root) {
14123 ret = xmlStreamPush(patstream, NULL, NULL);
14124 if (ret < 0) {
14125 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014126 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014127 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014128 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014129 }
14130 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014131 depth = 0;
14132 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014133next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000014134 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014135 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014136
14137 switch (cur->type) {
14138 case XML_ELEMENT_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014139 case XML_TEXT_NODE:
14140 case XML_CDATA_SECTION_NODE:
14141 case XML_COMMENT_NODE:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014142 case XML_PI_NODE:
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014143 if (cur->type == XML_ELEMENT_NODE) {
14144 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000014145 (cur->ns ? cur->ns->href : NULL));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014146 } else if (eval_all_nodes)
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014147 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14148 else
14149 break;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014150
14151 if (ret < 0) {
14152 /* NOP. */
14153 } else if (ret == 1) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014154 if (toBool)
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014155 goto return_1;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014156 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014157 }
14158 if ((cur->children == NULL) || (depth >= max_depth)) {
14159 ret = xmlStreamPop(patstream);
14160 while (cur->next != NULL) {
14161 cur = cur->next;
14162 if ((cur->type != XML_ENTITY_DECL) &&
14163 (cur->type != XML_DTD_NODE))
14164 goto next_node;
14165 }
14166 }
14167 default:
14168 break;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014169 }
14170
Daniel Veillard56de87e2005-02-16 00:22:29 +000014171scan_children:
14172 if ((cur->children != NULL) && (depth < max_depth)) {
14173 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014174 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000014175 */
14176 if (cur->children->type != XML_ENTITY_DECL) {
14177 cur = cur->children;
14178 depth++;
14179 /*
14180 * Skip DTDs
14181 */
14182 if (cur->type != XML_DTD_NODE)
14183 continue;
14184 }
14185 }
14186
14187 if (cur == limit)
14188 break;
14189
14190 while (cur->next != NULL) {
14191 cur = cur->next;
14192 if ((cur->type != XML_ENTITY_DECL) &&
14193 (cur->type != XML_DTD_NODE))
14194 goto next_node;
14195 }
14196
14197 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014198 cur = cur->parent;
14199 depth--;
14200 if ((cur == NULL) || (cur == limit))
14201 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014202 if (cur->type == XML_ELEMENT_NODE) {
14203 ret = xmlStreamPop(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014204 } else if ((eval_all_nodes) &&
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000014205 ((cur->type == XML_TEXT_NODE) ||
14206 (cur->type == XML_CDATA_SECTION_NODE) ||
14207 (cur->type == XML_COMMENT_NODE) ||
14208 (cur->type == XML_PI_NODE)))
14209 {
14210 ret = xmlStreamPop(patstream);
14211 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014212 if (cur->next != NULL) {
14213 cur = cur->next;
14214 break;
14215 }
14216 } while (cur != NULL);
14217
14218 } while ((cur != NULL) && (depth >= 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014219
Daniel Veillard56de87e2005-02-16 00:22:29 +000014220done:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014221
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014222#if 0
14223 printf("stream eval: checked %d nodes selected %d\n",
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014224 nb_nodes, retObj->nodesetval->nodeNr);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000014225#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014226
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014227 if (patstream)
14228 xmlFreeStreamCtxt(patstream);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014229 return(0);
Kasimier T. Buchcik8af1f0b2006-06-28 17:13:19 +000014230
14231return_1:
14232 if (patstream)
14233 xmlFreeStreamCtxt(patstream);
14234 return(1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014235}
14236#endif /* XPATH_STREAMING */
14237
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014238/**
14239 * xmlXPathRunEval:
14240 * @ctxt: the XPath parser context with the compiled expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014241 * @toBool: evaluate to a boolean result
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014242 *
14243 * Evaluate the Precompiled XPath expression in the given context.
14244 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014245static int
14246xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14247{
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014248 xmlXPathCompExprPtr comp;
14249
14250 if ((ctxt == NULL) || (ctxt->comp == NULL))
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014251 return(-1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014252
14253 if (ctxt->valueTab == NULL) {
14254 /* Allocate the value stack */
14255 ctxt->valueTab = (xmlXPathObjectPtr *)
14256 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14257 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000014258 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014259 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014260 }
14261 ctxt->valueNr = 0;
14262 ctxt->valueMax = 10;
14263 ctxt->value = NULL;
14264 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014265#ifdef XPATH_STREAMING
14266 if (ctxt->comp->stream) {
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014267 int res;
14268
14269 if (toBool) {
14270 /*
14271 * Evaluation to boolean result.
14272 */
14273 res = xmlXPathRunStreamEval(ctxt->context,
14274 ctxt->comp->stream, NULL, 1);
14275 if (res != -1)
14276 return(res);
14277 } else {
14278 xmlXPathObjectPtr resObj = NULL;
14279
14280 /*
14281 * Evaluation to a sequence.
14282 */
14283 res = xmlXPathRunStreamEval(ctxt->context,
14284 ctxt->comp->stream, &resObj, 0);
14285
14286 if ((res != -1) && (resObj != NULL)) {
14287 valuePush(ctxt, resObj);
14288 return(0);
14289 }
14290 if (resObj != NULL)
14291 xmlXPathReleaseObject(ctxt->context, resObj);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014292 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014293 /*
14294 * QUESTION TODO: This falls back to normal XPath evaluation
14295 * if res == -1. Is this intended?
14296 */
Daniel Veillard56de87e2005-02-16 00:22:29 +000014297 }
14298#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014299 comp = ctxt->comp;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014300 if (comp->last < 0) {
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014301 xmlGenericError(xmlGenericErrorContext,
14302 "xmlXPathRunEval: last is less than zero\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014303 return(-1);
Aleksey Sanin29b6f762002-05-05 06:59:57 +000014304 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014305 if (toBool)
Kasimier T. Buchcik324c75b2006-06-29 10:31:35 +000014306 return(xmlXPathCompOpEvalToBoolean(ctxt,
14307 &comp->steps[comp->last], 0));
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014308 else
14309 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14310
14311 return(0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014312}
14313
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014314/************************************************************************
14315 * *
14316 * Public interfaces *
14317 * *
14318 ************************************************************************/
14319
14320/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014321 * xmlXPathEvalPredicate:
14322 * @ctxt: the XPath context
14323 * @res: the Predicate Expression evaluation result
14324 *
14325 * Evaluate a predicate result for the current node.
14326 * A PredicateExpr is evaluated by evaluating the Expr and converting
14327 * the result to a boolean. If the result is a number, the result will
14328 * be converted to true if the number is equal to the position of the
14329 * context node in the context node list (as returned by the position
14330 * function) and will be converted to false otherwise; if the result
14331 * is not a number, then the result will be converted as if by a call
14332 * to the boolean function.
14333 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014334 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014335 */
14336int
14337xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014338 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014339 switch (res->type) {
14340 case XPATH_BOOLEAN:
14341 return(res->boolval);
14342 case XPATH_NUMBER:
14343 return(res->floatval == ctxt->proximityPosition);
14344 case XPATH_NODESET:
14345 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000014346 if (res->nodesetval == NULL)
14347 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000014348 return(res->nodesetval->nodeNr != 0);
14349 case XPATH_STRING:
14350 return((res->stringval != NULL) &&
14351 (xmlStrlen(res->stringval) != 0));
14352 default:
14353 STRANGE
14354 }
14355 return(0);
14356}
14357
14358/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014359 * xmlXPathEvaluatePredicateResult:
14360 * @ctxt: the XPath Parser context
14361 * @res: the Predicate Expression evaluation result
14362 *
14363 * Evaluate a predicate result for the current node.
14364 * A PredicateExpr is evaluated by evaluating the Expr and converting
14365 * the result to a boolean. If the result is a number, the result will
14366 * be converted to true if the number is equal to the position of the
14367 * context node in the context node list (as returned by the position
14368 * function) and will be converted to false otherwise; if the result
14369 * is not a number, then the result will be converted as if by a call
14370 * to the boolean function.
14371 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014372 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014373 */
14374int
14375xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14376 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000014377 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014378 switch (res->type) {
14379 case XPATH_BOOLEAN:
14380 return(res->boolval);
14381 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000014382#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000014383 return((res->floatval == ctxt->context->proximityPosition) &&
14384 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000014385#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014386 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000014387#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014388 case XPATH_NODESET:
14389 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000014390 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000014391 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014392 return(res->nodesetval->nodeNr != 0);
14393 case XPATH_STRING:
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014394 return((res->stringval != NULL) && (res->stringval[0] != 0));
William M. Brack08171912003-12-29 02:52:11 +000014395#ifdef LIBXML_XPTR_ENABLED
14396 case XPATH_LOCATIONSET:{
14397 xmlLocationSetPtr ptr = res->user;
14398 if (ptr == NULL)
14399 return(0);
14400 return (ptr->locNr != 0);
14401 }
14402#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014403 default:
14404 STRANGE
14405 }
14406 return(0);
14407}
14408
Daniel Veillard56de87e2005-02-16 00:22:29 +000014409#ifdef XPATH_STREAMING
14410/**
14411 * xmlXPathTryStreamCompile:
14412 * @ctxt: an XPath context
14413 * @str: the XPath expression
14414 *
14415 * Try to compile the XPath expression as a streamable subset.
14416 *
14417 * Returns the compiled expression or NULL if failed to compile.
14418 */
14419static xmlXPathCompExprPtr
14420xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14421 /*
14422 * Optimization: use streaming patterns when the XPath expression can
14423 * be compiled to a stream lookup
14424 */
14425 xmlPatternPtr stream;
14426 xmlXPathCompExprPtr comp;
14427 xmlDictPtr dict = NULL;
14428 const xmlChar **namespaces = NULL;
14429 xmlNsPtr ns;
14430 int i, j;
14431
14432 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14433 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014434 const xmlChar *tmp;
14435
14436 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014437 * We don't try to handle expressions using the verbose axis
14438 * specifiers ("::"), just the simplied form at this point.
14439 * Additionally, if there is no list of namespaces available and
14440 * there's a ":" in the expression, indicating a prefixed QName,
14441 * then we won't try to compile either. xmlPatterncompile() needs
14442 * to have a list of namespaces at compilation time in order to
14443 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014444 */
14445 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014446 if ((tmp != NULL) &&
14447 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14448 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000014449
Daniel Veillard56de87e2005-02-16 00:22:29 +000014450 if (ctxt != NULL) {
14451 dict = ctxt->dict;
14452 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000014453 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000014454 if (namespaces == NULL) {
14455 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14456 return(NULL);
14457 }
14458 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14459 ns = ctxt->namespaces[j];
14460 namespaces[i++] = ns->href;
14461 namespaces[i++] = ns->prefix;
14462 }
14463 namespaces[i++] = NULL;
14464 namespaces[i++] = NULL;
14465 }
14466 }
14467
William M. Brackea152c02005-06-09 18:12:28 +000014468 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14469 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014470 if (namespaces != NULL) {
14471 xmlFree((xmlChar **)namespaces);
14472 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014473 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14474 comp = xmlXPathNewCompExpr();
14475 if (comp == NULL) {
14476 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14477 return(NULL);
14478 }
14479 comp->stream = stream;
14480 comp->dict = dict;
14481 if (comp->dict)
14482 xmlDictReference(comp->dict);
14483 return(comp);
14484 }
14485 xmlFreePattern(stream);
14486 }
14487 return(NULL);
14488}
14489#endif /* XPATH_STREAMING */
14490
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014491static int
14492xmlXPathCanRewriteDosExpression(xmlChar *expr)
14493{
14494 if (expr == NULL)
14495 return(0);
14496 do {
14497 if ((*expr == '/') && (*(++expr) == '/'))
14498 return(1);
14499 } while (*expr++);
14500 return(0);
14501}
14502static void
14503xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14504{
14505 /*
14506 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14507 * internal representation.
14508 */
14509 if (op->ch1 != -1) {
14510 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14511 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14512 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14513 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14514 {
14515 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014516 * This is a "child::foo"
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014517 */
14518 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14519
14520 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14521 (prevop->ch1 != -1) &&
14522 ((xmlXPathAxisVal) prevop->value ==
14523 AXIS_DESCENDANT_OR_SELF) &&
14524 (prevop->ch2 == -1) &&
14525 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014526 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14527 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014528 {
14529 /*
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014530 * This is a "/descendant-or-self::node()" without predicates.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014531 * Eliminate it.
14532 */
14533 op->ch1 = prevop->ch1;
14534 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14535 }
14536 }
14537 if (op->ch1 != -1)
14538 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14539 }
14540 if (op->ch2 != -1)
14541 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14542}
14543
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014544/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014545 * xmlXPathCtxtCompile:
14546 * @ctxt: an XPath context
14547 * @str: the XPath expression
14548 *
14549 * Compile an XPath expression
14550 *
14551 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14552 * the caller has to free the object.
14553 */
14554xmlXPathCompExprPtr
14555xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14556 xmlXPathParserContextPtr pctxt;
14557 xmlXPathCompExprPtr comp;
14558
Daniel Veillard56de87e2005-02-16 00:22:29 +000014559#ifdef XPATH_STREAMING
14560 comp = xmlXPathTryStreamCompile(ctxt, str);
14561 if (comp != NULL)
14562 return(comp);
14563#endif
14564
Daniel Veillard4773df22004-01-23 13:15:13 +000014565 xmlXPathInit();
14566
14567 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014568 if (pctxt == NULL)
14569 return NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014570 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014571
14572 if( pctxt->error != XPATH_EXPRESSION_OK )
14573 {
14574 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014575 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014576 }
14577
14578 if (*pctxt->cur != 0) {
14579 /*
14580 * aleksey: in some cases this line prints *second* error message
14581 * (see bug #78858) and probably this should be fixed.
14582 * However, we are not sure that all error messages are printed
14583 * out in other places. It's not critical so we leave it as-is for now
14584 */
14585 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14586 comp = NULL;
14587 } else {
14588 comp = pctxt->comp;
14589 pctxt->comp = NULL;
14590 }
14591 xmlXPathFreeParserContext(pctxt);
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014592
Daniel Veillard4773df22004-01-23 13:15:13 +000014593 if (comp != NULL) {
14594 comp->expr = xmlStrdup(str);
14595#ifdef DEBUG_EVAL_COUNTS
14596 comp->string = xmlStrdup(str);
14597 comp->nb = 0;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014598#endif
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014599 if ((comp->expr != NULL) &&
14600 (comp->nbStep > 2) &&
14601 (comp->last >= 0) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014602 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14603 {
14604 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
Kasimier T. Buchcik9bca9332006-06-19 10:26:42 +000014605 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014606 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014607 return(comp);
14608}
14609
14610/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014611 * xmlXPathCompile:
14612 * @str: the XPath expression
14613 *
14614 * Compile an XPath expression
14615 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014616 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014617 * the caller has to free the object.
14618 */
14619xmlXPathCompExprPtr
14620xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014621 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014622}
14623
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014624/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014625 * xmlXPathCompiledEvalInternal:
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014626 * @comp: the compiled XPath expression
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014627 * @ctxt: the XPath context
14628 * @resObj: the resulting XPath object or NULL
14629 * @toBool: 1 if only a boolean result is requested
Owen Taylor3473f882001-02-23 17:55:21 +000014630 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014631 * Evaluate the Precompiled XPath expression in the given context.
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014632 * The caller has to free @resObj.
Owen Taylor3473f882001-02-23 17:55:21 +000014633 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014634 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014635 * the caller has to free the object.
14636 */
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014637static int
14638xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14639 xmlXPathContextPtr ctxt,
14640 xmlXPathObjectPtr *resObj,
14641 int toBool)
14642{
14643 xmlXPathParserContextPtr pctxt;
Daniel Veillard81463942001-10-16 12:34:39 +000014644#ifndef LIBXML_THREAD_ENABLED
14645 static int reentance = 0;
14646#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014647 int res;
Owen Taylor3473f882001-02-23 17:55:21 +000014648
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014649 CHECK_CTXT_NEG(ctxt)
William M. Brackf13f77f2004-11-12 16:03:48 +000014650
14651 if (comp == NULL)
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014652 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +000014653 xmlXPathInit();
14654
Daniel Veillard81463942001-10-16 12:34:39 +000014655#ifndef LIBXML_THREAD_ENABLED
14656 reentance++;
14657 if (reentance > 1)
14658 xmlXPathDisableOptimizer = 1;
14659#endif
14660
Daniel Veillardf06307e2001-07-03 10:35:50 +000014661#ifdef DEBUG_EVAL_COUNTS
14662 comp->nb++;
14663 if ((comp->string != NULL) && (comp->nb > 100)) {
14664 fprintf(stderr, "100 x %s\n", comp->string);
14665 comp->nb = 0;
14666 }
14667#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014668 pctxt = xmlXPathCompParserContext(comp, ctxt);
14669 res = xmlXPathRunEval(pctxt, toBool);
Owen Taylor3473f882001-02-23 17:55:21 +000014670
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014671 if (resObj) {
14672 if (pctxt->value == NULL) {
14673 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014674 "xmlXPathCompiledEval: evaluation failed\n");
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014675 *resObj = NULL;
14676 } else {
14677 *resObj = valuePop(pctxt);
14678 }
Owen Taylor3473f882001-02-23 17:55:21 +000014679 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000014680
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014681 /*
14682 * Pop all remaining objects from the stack.
14683 */
14684 if (pctxt->valueNr > 0) {
14685 xmlXPathObjectPtr tmp;
14686 int stack = 0;
14687
14688 do {
14689 tmp = valuePop(pctxt);
14690 if (tmp != NULL) {
14691 if (tmp != NULL)
14692 stack++;
14693 xmlXPathReleaseObject(ctxt, tmp);
14694 }
14695 } while (tmp != NULL);
14696 if ((stack != 0) &&
14697 ((toBool) || ((resObj) && (*resObj))))
14698 {
14699 xmlGenericError(xmlGenericErrorContext,
14700 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14701 stack);
14702 }
Owen Taylor3473f882001-02-23 17:55:21 +000014703 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014704
14705 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14706 xmlXPathFreeObject(*resObj);
14707 *resObj = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014708 }
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014709 pctxt->comp = NULL;
14710 xmlXPathFreeParserContext(pctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014711#ifndef LIBXML_THREAD_ENABLED
14712 reentance--;
14713#endif
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014714
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014715 return(res);
14716}
14717
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014718/**
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014719 * xmlXPathCompiledEval:
14720 * @comp: the compiled XPath expression
14721 * @ctx: the XPath context
14722 *
14723 * Evaluate the Precompiled XPath expression in the given context.
14724 *
14725 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14726 * the caller has to free the object.
14727 */
14728xmlXPathObjectPtr
14729xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14730{
14731 xmlXPathObjectPtr res = NULL;
14732
14733 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14734 return(res);
14735}
14736
14737/**
14738 * xmlXPathCompiledEvalToBoolean:
14739 * @comp: the compiled XPath expression
14740 * @ctxt: the XPath context
14741 *
14742 * Applies the XPath boolean() function on the result of the given
14743 * compiled expression.
14744 *
14745 * Returns 1 if the expression evaluated to true, 0 if to false and
14746 * -1 in API and internal errors.
14747 */
14748int
14749xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14750 xmlXPathContextPtr ctxt)
14751{
14752 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14753}
14754
14755/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014756 * xmlXPathEvalExpr:
14757 * @ctxt: the XPath Parser context
14758 *
14759 * Parse and evaluate an XPath expression in the given context,
14760 * then push the result on the context stack
14761 */
14762void
14763xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014764#ifdef XPATH_STREAMING
14765 xmlXPathCompExprPtr comp;
14766#endif
14767
Daniel Veillarda82b1822004-11-08 16:24:57 +000014768 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014769
14770#ifdef XPATH_STREAMING
14771 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14772 if (comp != NULL) {
14773 if (ctxt->comp != NULL)
14774 xmlXPathFreeCompExpr(ctxt->comp);
14775 ctxt->comp = comp;
14776 if (ctxt->cur != NULL)
14777 while (*ctxt->cur != 0) ctxt->cur++;
14778 } else
14779#endif
14780 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014781 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014782 /*
14783 * In this scenario the expression string will sit in ctxt->base.
14784 */
14785 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14786 (ctxt->comp != NULL) &&
14787 (ctxt->base != NULL) &&
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014788 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014789 (ctxt->comp->last >= 0) &&
14790 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014791 {
14792 xmlXPathRewriteDOSExpression(ctxt->comp,
Kasimier T. Buchcik766ed7e2006-06-23 16:32:41 +000014793 &ctxt->comp->steps[ctxt->comp->last]);
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014794 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014795 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014796 CHECK_ERROR;
Kasimier T. Buchcik631ea812006-06-26 16:47:25 +000014797 xmlXPathRunEval(ctxt, 0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014798}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014799
14800/**
14801 * xmlXPathEval:
14802 * @str: the XPath expression
14803 * @ctx: the XPath context
14804 *
14805 * Evaluate the XPath Location Path in the given context.
14806 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014807 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014808 * the caller has to free the object.
14809 */
14810xmlXPathObjectPtr
14811xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14812 xmlXPathParserContextPtr ctxt;
14813 xmlXPathObjectPtr res, tmp, init = NULL;
14814 int stack = 0;
14815
William M. Brackf13f77f2004-11-12 16:03:48 +000014816 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014817
William M. Brackf13f77f2004-11-12 16:03:48 +000014818 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014819
14820 ctxt = xmlXPathNewParserContext(str, ctx);
William M. Brack11be2d02007-01-24 19:17:19 +000014821 if (ctxt == NULL)
14822 return NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014823 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014824
14825 if (ctxt->value == NULL) {
14826 xmlGenericError(xmlGenericErrorContext,
14827 "xmlXPathEval: evaluation failed\n");
14828 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014829 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14830#ifdef XPATH_STREAMING
14831 && (ctxt->comp->stream == NULL)
14832#endif
14833 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014834 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14835 res = NULL;
14836 } else {
14837 res = valuePop(ctxt);
14838 }
14839
14840 do {
14841 tmp = valuePop(ctxt);
14842 if (tmp != NULL) {
14843 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014844 stack++;
14845 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014846 }
14847 } while (tmp != NULL);
14848 if ((stack != 0) && (res != NULL)) {
14849 xmlGenericError(xmlGenericErrorContext,
14850 "xmlXPathEval: %d object left on the stack\n",
14851 stack);
14852 }
14853 if (ctxt->error != XPATH_EXPRESSION_OK) {
14854 xmlXPathFreeObject(res);
14855 res = NULL;
14856 }
14857
Owen Taylor3473f882001-02-23 17:55:21 +000014858 xmlXPathFreeParserContext(ctxt);
14859 return(res);
14860}
14861
14862/**
14863 * xmlXPathEvalExpression:
14864 * @str: the XPath expression
14865 * @ctxt: the XPath context
14866 *
14867 * Evaluate the XPath expression in the given context.
14868 *
14869 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14870 * the caller has to free the object.
14871 */
14872xmlXPathObjectPtr
14873xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14874 xmlXPathParserContextPtr pctxt;
14875 xmlXPathObjectPtr res, tmp;
14876 int stack = 0;
14877
William M. Brackf13f77f2004-11-12 16:03:48 +000014878 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014879
William M. Brackf13f77f2004-11-12 16:03:48 +000014880 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014881
14882 pctxt = xmlXPathNewParserContext(str, ctxt);
William M. Brack11be2d02007-01-24 19:17:19 +000014883 if (pctxt == NULL)
14884 return NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014885 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014886
Daniel Veillardc465ffc2006-10-17 19:39:33 +000014887 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
Owen Taylor3473f882001-02-23 17:55:21 +000014888 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14889 res = NULL;
14890 } else {
14891 res = valuePop(pctxt);
14892 }
14893 do {
14894 tmp = valuePop(pctxt);
14895 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014896 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014897 stack++;
14898 }
14899 } while (tmp != NULL);
14900 if ((stack != 0) && (res != NULL)) {
14901 xmlGenericError(xmlGenericErrorContext,
14902 "xmlXPathEvalExpression: %d object left on the stack\n",
14903 stack);
14904 }
14905 xmlXPathFreeParserContext(pctxt);
14906 return(res);
14907}
14908
Daniel Veillard42766c02002-08-22 20:52:17 +000014909/************************************************************************
14910 * *
14911 * Extra functions not pertaining to the XPath spec *
14912 * *
14913 ************************************************************************/
14914/**
14915 * xmlXPathEscapeUriFunction:
14916 * @ctxt: the XPath Parser context
14917 * @nargs: the number of arguments
14918 *
14919 * Implement the escape-uri() XPath function
14920 * string escape-uri(string $str, bool $escape-reserved)
14921 *
14922 * This function applies the URI escaping rules defined in section 2 of [RFC
14923 * 2396] to the string supplied as $uri-part, which typically represents all
14924 * or part of a URI. The effect of the function is to replace any special
14925 * character in the string by an escape sequence of the form %xx%yy...,
14926 * where xxyy... is the hexadecimal representation of the octets used to
14927 * represent the character in UTF-8.
14928 *
14929 * The set of characters that are escaped depends on the setting of the
14930 * boolean argument $escape-reserved.
14931 *
14932 * If $escape-reserved is true, all characters are escaped other than lower
14933 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14934 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14935 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14936 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14937 * A-F).
14938 *
14939 * If $escape-reserved is false, the behavior differs in that characters
14940 * referred to in [RFC 2396] as reserved characters are not escaped. These
14941 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14942 *
14943 * [RFC 2396] does not define whether escaped URIs should use lower case or
14944 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14945 * compared using string comparison functions, this function must always use
14946 * the upper-case letters A-F.
14947 *
14948 * Generally, $escape-reserved should be set to true when escaping a string
14949 * that is to form a single part of a URI, and to false when escaping an
14950 * entire URI or URI reference.
14951 *
14952 * In the case of non-ascii characters, the string is encoded according to
14953 * utf-8 and then converted according to RFC 2396.
14954 *
14955 * Examples
14956 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14957 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14958 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14959 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14960 *
14961 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014962static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014963xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14964 xmlXPathObjectPtr str;
14965 int escape_reserved;
14966 xmlBufferPtr target;
14967 xmlChar *cptr;
14968 xmlChar escape[4];
14969
14970 CHECK_ARITY(2);
14971
14972 escape_reserved = xmlXPathPopBoolean(ctxt);
14973
14974 CAST_TO_STRING;
14975 str = valuePop(ctxt);
14976
14977 target = xmlBufferCreate();
14978
14979 escape[0] = '%';
14980 escape[3] = 0;
14981
14982 if (target) {
14983 for (cptr = str->stringval; *cptr; cptr++) {
14984 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14985 (*cptr >= 'a' && *cptr <= 'z') ||
14986 (*cptr >= '0' && *cptr <= '9') ||
14987 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14988 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14989 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14990 (*cptr == '%' &&
14991 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14992 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14993 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14994 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14995 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14996 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14997 (!escape_reserved &&
14998 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14999 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15000 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15001 *cptr == ','))) {
15002 xmlBufferAdd(target, cptr, 1);
15003 } else {
15004 if ((*cptr >> 4) < 10)
15005 escape[1] = '0' + (*cptr >> 4);
15006 else
15007 escape[1] = 'A' - 10 + (*cptr >> 4);
15008 if ((*cptr & 0xF) < 10)
15009 escape[2] = '0' + (*cptr & 0xF);
15010 else
15011 escape[2] = 'A' - 10 + (*cptr & 0xF);
15012
15013 xmlBufferAdd(target, &escape[0], 3);
15014 }
15015 }
15016 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015017 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15018 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000015019 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000015020 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000015021}
15022
Owen Taylor3473f882001-02-23 17:55:21 +000015023/**
15024 * xmlXPathRegisterAllFunctions:
15025 * @ctxt: the XPath context
15026 *
15027 * Registers all default XPath functions in this context
15028 */
15029void
15030xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15031{
15032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15033 xmlXPathBooleanFunction);
15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15035 xmlXPathCeilingFunction);
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15037 xmlXPathCountFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15039 xmlXPathConcatFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15041 xmlXPathContainsFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15043 xmlXPathIdFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15045 xmlXPathFalseFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15047 xmlXPathFloorFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15049 xmlXPathLastFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15051 xmlXPathLangFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15053 xmlXPathLocalNameFunction);
15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15055 xmlXPathNotFunction);
15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15057 xmlXPathNameFunction);
15058 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15059 xmlXPathNamespaceURIFunction);
15060 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15061 xmlXPathNormalizeFunction);
15062 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15063 xmlXPathNumberFunction);
15064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15065 xmlXPathPositionFunction);
15066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15067 xmlXPathRoundFunction);
15068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15069 xmlXPathStringFunction);
15070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15071 xmlXPathStringLengthFunction);
15072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15073 xmlXPathStartsWithFunction);
15074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15075 xmlXPathSubstringFunction);
15076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15077 xmlXPathSubstringBeforeFunction);
15078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15079 xmlXPathSubstringAfterFunction);
15080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15081 xmlXPathSumFunction);
15082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15083 xmlXPathTrueFunction);
15084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15085 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000015086
15087 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15088 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15089 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000015090}
15091
15092#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000015093#define bottom_xpath
15094#include "elfgcchack.h"