blob: 5ee0e08a0e01dcd5cc5c06dedc47a4f26b0814a5 [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. Buchcik97258712006-01-05 12:30:43 +000068* XP_PATTERN_TO_ANY_NODE_ENABLED: when an XPath expression can be
69* evaluated using the streaming mode (pattern.c) then this is used to
70* enable resolution to nodes of type text-node, cdata-section-node,
71* comment-node and pi-node. The only known scenario where this is
72* needed is an expression like "foo//.", "//.", etc.; i.e. an expression
73* where the final node to be selected can be of any type.
74* Disabling this #define will result in an incorrect evaluation to
75* only element-nodes and the document node.
76*/
77#define XP_PATTERN_TO_ANY_NODE_ENABLED
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000078
79/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000080* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000081* If defined, this will use xmlXPathCmpNodesExt() instead of
82* xmlXPathCmpNodes(). The new function is optimized comparison of
83* non-element nodes; actually it will speed up comparison only if
84* xmlXPathOrderDocElems() was called in order to index the elements of
85* a tree in document order; Libxslt does such an indexing, thus it will
86* benefit from this optimization.
87*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000088#define XP_OPTIMIZED_NON_ELEM_COMPARISON
89
90/*
91* XP_OPTIMIZED_FILTER_FIRST:
92* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
93* in a way, that it stop evaluation at the first node.
94*/
95#define XP_OPTIMIZED_FILTER_FIRST
96
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000097/*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000098* XP_DEBUG_OBJ_USAGE:
99* Internal flag to enable tracking of how much XPath objects have been
100* created.
101*/
102/* #define XP_DEBUG_OBJ_USAGE */
103
104/*
William M. Brackd1757ab2004-10-02 22:07:48 +0000105 * TODO:
106 * There are a few spots where some tests are done which depend upon ascii
107 * data. These should be enhanced for full UTF8 support (see particularly
108 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
109 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000110
William M. Brack21e4ef22005-01-02 09:53:13 +0000111#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000112/************************************************************************
113 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000114 * Forward declarations *
115 * *
116 ************************************************************************/
117static void
118xmlXPathFreeValueTree(xmlNodeSetPtr obj);
119static void
120xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
121
122/************************************************************************
123 * *
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000124 * Floating point stuff *
125 * *
126 ************************************************************************/
127
Daniel Veillardc0631a62001-09-20 13:56:06 +0000128#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000129#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000130#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000131#include "trionan.c"
132
Owen Taylor3473f882001-02-23 17:55:21 +0000133/*
Owen Taylor3473f882001-02-23 17:55:21 +0000134 * The lack of portability of this section of the libc is annoying !
135 */
136double xmlXPathNAN = 0;
137double xmlXPathPINF = 1;
138double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000139static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000140static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000141
Owen Taylor3473f882001-02-23 17:55:21 +0000142/**
143 * xmlXPathInit:
144 *
145 * Initialize the XPath environment
146 */
147void
148xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000149 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000150
Bjorn Reese45029602001-08-21 09:23:53 +0000151 xmlXPathPINF = trio_pinf();
152 xmlXPathNINF = trio_ninf();
153 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000154 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000155
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000156 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000157}
158
Daniel Veillardcda96922001-08-21 10:56:31 +0000159/**
160 * xmlXPathIsNaN:
161 * @val: a double value
162 *
163 * Provides a portable isnan() function to detect whether a double
164 * is a NotaNumber. Based on trio code
165 * http://sourceforge.net/projects/ctrio/
166 *
167 * Returns 1 if the value is a NaN, 0 otherwise
168 */
169int
170xmlXPathIsNaN(double val) {
171 return(trio_isnan(val));
172}
173
174/**
175 * xmlXPathIsInf:
176 * @val: a double value
177 *
178 * Provides a portable isinf() function to detect whether a double
179 * is a +Infinite or -Infinite. Based on trio code
180 * http://sourceforge.net/projects/ctrio/
181 *
182 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
183 */
184int
185xmlXPathIsInf(double val) {
186 return(trio_isinf(val));
187}
188
Daniel Veillard4432df22003-09-28 18:58:27 +0000189#endif /* SCHEMAS or XPATH */
190#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000191/**
192 * xmlXPathGetSign:
193 * @val: a double value
194 *
195 * Provides a portable function to detect the sign of a double
196 * Modified from trio code
197 * http://sourceforge.net/projects/ctrio/
198 *
199 * Returns 1 if the value is Negative, 0 if positive
200 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000201static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000202xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000203 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000204}
205
206
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000207/*
208 * TODO: when compatibility allows remove all "fake node libxslt" strings
209 * the test should just be name[0] = ' '
210 */
211/* #define DEBUG */
212/* #define DEBUG_STEP */
213/* #define DEBUG_STEP_NTH */
214/* #define DEBUG_EXPR */
215/* #define DEBUG_EVAL_COUNTS */
216
217static xmlNs xmlXPathXMLNamespaceStruct = {
218 NULL,
219 XML_NAMESPACE_DECL,
220 XML_XML_NAMESPACE,
221 BAD_CAST "xml",
222 NULL
223};
224static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
225#ifndef LIBXML_THREAD_ENABLED
226/*
227 * Optimizer is disabled only when threaded apps are detected while
228 * the library ain't compiled for thread safety.
229 */
230static int xmlXPathDisableOptimizer = 0;
231#endif
232
Owen Taylor3473f882001-02-23 17:55:21 +0000233/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000234 * *
235 * Error handling routines *
236 * *
237 ************************************************************************/
238
Daniel Veillard24505b02005-07-28 23:49:35 +0000239/**
240 * XP_ERRORNULL:
241 * @X: the error code
242 *
243 * Macro to raise an XPath error and return NULL.
244 */
245#define XP_ERRORNULL(X) \
246 { xmlXPathErr(ctxt, X); return(NULL); }
247
William M. Brack08171912003-12-29 02:52:11 +0000248/*
249 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
250 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000251static const char *xmlXPathErrorMessages[] = {
252 "Ok\n",
253 "Number encoding\n",
254 "Unfinished literal\n",
255 "Start of literal\n",
256 "Expected $ for variable reference\n",
257 "Undefined variable\n",
258 "Invalid predicate\n",
259 "Invalid expression\n",
260 "Missing closing curly brace\n",
261 "Unregistered function\n",
262 "Invalid operand\n",
263 "Invalid type\n",
264 "Invalid number of arguments\n",
265 "Invalid context size\n",
266 "Invalid context position\n",
267 "Memory allocation error\n",
268 "Syntax error\n",
269 "Resource error\n",
270 "Sub resource error\n",
271 "Undefined namespace prefix\n",
272 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000273 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000274 "Invalid or incomplete context\n",
275 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000276};
William M. Brackcd65bc92005-01-06 09:39:18 +0000277#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
278 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000279/**
280 * xmlXPathErrMemory:
281 * @ctxt: an XPath context
282 * @extra: extra informations
283 *
284 * Handle a redefinition of attribute error
285 */
286static void
287xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
288{
289 if (ctxt != NULL) {
290 if (extra) {
291 xmlChar buf[200];
292
293 xmlStrPrintf(buf, 200,
294 BAD_CAST "Memory allocation failed : %s\n",
295 extra);
296 ctxt->lastError.message = (char *) xmlStrdup(buf);
297 } else {
298 ctxt->lastError.message = (char *)
299 xmlStrdup(BAD_CAST "Memory allocation failed\n");
300 }
301 ctxt->lastError.domain = XML_FROM_XPATH;
302 ctxt->lastError.code = XML_ERR_NO_MEMORY;
303 if (ctxt->error != NULL)
304 ctxt->error(ctxt->userData, &ctxt->lastError);
305 } else {
306 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000307 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 NULL, NULL, XML_FROM_XPATH,
309 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
310 extra, NULL, NULL, 0, 0,
311 "Memory allocation failed : %s\n", extra);
312 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000313 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 NULL, NULL, XML_FROM_XPATH,
315 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
316 NULL, NULL, NULL, 0, 0,
317 "Memory allocation failed\n");
318 }
319}
320
321/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000322 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 * @ctxt: an XPath parser context
324 * @extra: extra informations
325 *
326 * Handle a redefinition of attribute error
327 */
328static void
329xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
330{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000331 if (ctxt == NULL)
332 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000333 else {
334 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000335 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000336 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000337}
338
339/**
340 * xmlXPathErr:
341 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000342 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000343 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000344 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000345 */
346void
347xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
348{
William M. Brackcd65bc92005-01-06 09:39:18 +0000349 if ((error < 0) || (error > MAXERRNO))
350 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000351 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000352 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000353 NULL, NULL, XML_FROM_XPATH,
354 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
355 XML_ERR_ERROR, NULL, 0,
356 NULL, NULL, NULL, 0, 0,
357 xmlXPathErrorMessages[error]);
358 return;
359 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000360 ctxt->error = error;
361 if (ctxt->context == NULL) {
362 __xmlRaiseError(NULL, NULL, NULL,
363 NULL, NULL, XML_FROM_XPATH,
364 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
365 XML_ERR_ERROR, NULL, 0,
366 (const char *) ctxt->base, NULL, NULL,
367 ctxt->cur - ctxt->base, 0,
368 xmlXPathErrorMessages[error]);
369 return;
370 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000371 ctxt->context->lastError.domain = XML_FROM_XPATH;
372 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
373 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000374 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000375 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
376 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
377 ctxt->context->lastError.node = ctxt->context->debugNode;
378 if (ctxt->context->error != NULL) {
379 ctxt->context->error(ctxt->context->userData,
380 &ctxt->context->lastError);
381 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000382 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000383 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
384 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
385 XML_ERR_ERROR, NULL, 0,
386 (const char *) ctxt->base, NULL, NULL,
387 ctxt->cur - ctxt->base, 0,
388 xmlXPathErrorMessages[error]);
389 }
390
391}
392
393/**
394 * xmlXPatherror:
395 * @ctxt: the XPath Parser context
396 * @file: the file name
397 * @line: the line number
398 * @no: the error number
399 *
400 * Formats an error message.
401 */
402void
403xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
404 int line ATTRIBUTE_UNUSED, int no) {
405 xmlXPathErr(ctxt, no);
406}
407
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000408/************************************************************************
409 * *
410 * Utilities *
411 * *
412 ************************************************************************/
413
414/**
415 * xsltPointerList:
416 *
417 * Pointer-list for various purposes.
418 */
419typedef struct _xmlPointerList xmlPointerList;
420typedef xmlPointerList *xmlPointerListPtr;
421struct _xmlPointerList {
422 void **items;
423 int number;
424 int size;
425};
426/*
427* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
428* and here, we should make the functions public.
429*/
430static int
431xmlPointerListAddSize(xmlPointerListPtr list,
432 void *item,
433 int initialSize)
434{
435 if (list->items == NULL) {
436 if (initialSize <= 0)
437 initialSize = 1;
438 list->items = (void **) xmlMalloc(
439 initialSize * sizeof(void *));
440 if (list->items == NULL) {
441 xmlXPathErrMemory(NULL,
442 "xmlPointerListCreate: allocating item\n");
443 return(-1);
444 }
445 list->number = 0;
446 list->size = initialSize;
447 } else if (list->size <= list->number) {
448 list->size *= 2;
449 list->items = (void **) xmlRealloc(list->items,
450 list->size * sizeof(void *));
451 if (list->items == NULL) {
452 xmlXPathErrMemory(NULL,
453 "xmlPointerListCreate: re-allocating item\n");
454 list->size = 0;
455 return(-1);
456 }
457 }
458 list->items[list->number++] = item;
459 return(0);
460}
461
462/**
463 * xsltPointerListCreate:
464 *
465 * Creates an xsltPointerList structure.
466 *
467 * Returns a xsltPointerList structure or NULL in case of an error.
468 */
469static xmlPointerListPtr
470xmlPointerListCreate(int initialSize)
471{
472 xmlPointerListPtr ret;
473
474 ret = xmlMalloc(sizeof(xmlPointerList));
475 if (ret == NULL) {
476 xmlXPathErrMemory(NULL,
477 "xmlPointerListCreate: allocating item\n");
478 return (NULL);
479 }
480 memset(ret, 0, sizeof(xmlPointerList));
481 if (initialSize > 0) {
482 xmlPointerListAddSize(ret, NULL, initialSize);
483 ret->number = 0;
484 }
485 return (ret);
486}
487
488/**
489 * xsltPointerListFree:
490 *
491 * Frees the xsltPointerList structure. This does not free
492 * the content of the list.
493 */
494static void
495xmlPointerListFree(xmlPointerListPtr list)
496{
497 if (list == NULL)
498 return;
499 if (list->items != NULL)
500 xmlFree(list->items);
501 xmlFree(list);
502}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000503
504/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000505 * *
506 * Parser Types *
507 * *
508 ************************************************************************/
509
510/*
511 * Types are private:
512 */
513
514typedef enum {
515 XPATH_OP_END=0,
516 XPATH_OP_AND,
517 XPATH_OP_OR,
518 XPATH_OP_EQUAL,
519 XPATH_OP_CMP,
520 XPATH_OP_PLUS,
521 XPATH_OP_MULT,
522 XPATH_OP_UNION,
523 XPATH_OP_ROOT,
524 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000525 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000526 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000527 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000528 XPATH_OP_VARIABLE,
529 XPATH_OP_FUNCTION,
530 XPATH_OP_ARG,
531 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000532 XPATH_OP_FILTER, /* 17 */
533 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000534#ifdef LIBXML_XPTR_ENABLED
535 ,XPATH_OP_RANGETO
536#endif
537} xmlXPathOp;
538
539typedef enum {
540 AXIS_ANCESTOR = 1,
541 AXIS_ANCESTOR_OR_SELF,
542 AXIS_ATTRIBUTE,
543 AXIS_CHILD,
544 AXIS_DESCENDANT,
545 AXIS_DESCENDANT_OR_SELF,
546 AXIS_FOLLOWING,
547 AXIS_FOLLOWING_SIBLING,
548 AXIS_NAMESPACE,
549 AXIS_PARENT,
550 AXIS_PRECEDING,
551 AXIS_PRECEDING_SIBLING,
552 AXIS_SELF
553} xmlXPathAxisVal;
554
555typedef enum {
556 NODE_TEST_NONE = 0,
557 NODE_TEST_TYPE = 1,
558 NODE_TEST_PI = 2,
559 NODE_TEST_ALL = 3,
560 NODE_TEST_NS = 4,
561 NODE_TEST_NAME = 5
562} xmlXPathTestVal;
563
564typedef enum {
565 NODE_TYPE_NODE = 0,
566 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
567 NODE_TYPE_TEXT = XML_TEXT_NODE,
568 NODE_TYPE_PI = XML_PI_NODE
569} xmlXPathTypeVal;
570
571
572typedef struct _xmlXPathStepOp xmlXPathStepOp;
573typedef xmlXPathStepOp *xmlXPathStepOpPtr;
574struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000575 xmlXPathOp op; /* The identifier of the operation */
576 int ch1; /* First child */
577 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000578 int value;
579 int value2;
580 int value3;
581 void *value4;
582 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000583 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000584 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000585};
586
587struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000588 int nbStep; /* Number of steps in this expression */
589 int maxStep; /* Maximum number of steps allocated */
590 xmlXPathStepOp *steps; /* ops for computation of this expression */
591 int last; /* index of last step in expression */
592 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000593 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000594#ifdef DEBUG_EVAL_COUNTS
595 int nb;
596 xmlChar *string;
597#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000598#ifdef XPATH_STREAMING
599 xmlPatternPtr stream;
600#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000601};
602
603/************************************************************************
604 * *
605 * Parser Type functions *
606 * *
607 ************************************************************************/
608
609/**
610 * xmlXPathNewCompExpr:
611 *
612 * Create a new Xpath component
613 *
614 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
615 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000616static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000617xmlXPathNewCompExpr(void) {
618 xmlXPathCompExprPtr cur;
619
620 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
621 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000622 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000623 return(NULL);
624 }
625 memset(cur, 0, sizeof(xmlXPathCompExpr));
626 cur->maxStep = 10;
627 cur->nbStep = 0;
628 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
629 sizeof(xmlXPathStepOp));
630 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000631 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000632 xmlFree(cur);
633 return(NULL);
634 }
635 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
636 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000637#ifdef DEBUG_EVAL_COUNTS
638 cur->nb = 0;
639#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000640 return(cur);
641}
642
643/**
644 * xmlXPathFreeCompExpr:
645 * @comp: an XPATH comp
646 *
647 * Free up the memory allocated by @comp
648 */
649void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000650xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
651{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000652 xmlXPathStepOpPtr op;
653 int i;
654
655 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000656 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000657 if (comp->dict == NULL) {
658 for (i = 0; i < comp->nbStep; i++) {
659 op = &comp->steps[i];
660 if (op->value4 != NULL) {
661 if (op->op == XPATH_OP_VALUE)
662 xmlXPathFreeObject(op->value4);
663 else
664 xmlFree(op->value4);
665 }
666 if (op->value5 != NULL)
667 xmlFree(op->value5);
668 }
669 } else {
670 for (i = 0; i < comp->nbStep; i++) {
671 op = &comp->steps[i];
672 if (op->value4 != NULL) {
673 if (op->op == XPATH_OP_VALUE)
674 xmlXPathFreeObject(op->value4);
675 }
676 }
677 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 }
679 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000680 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000681 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000682#ifdef DEBUG_EVAL_COUNTS
683 if (comp->string != NULL) {
684 xmlFree(comp->string);
685 }
686#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000687#ifdef XPATH_STREAMING
688 if (comp->stream != NULL) {
689 xmlFreePatternList(comp->stream);
690 }
691#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000692 if (comp->expr != NULL) {
693 xmlFree(comp->expr);
694 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000695
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000696 xmlFree(comp);
697}
698
699/**
700 * xmlXPathCompExprAdd:
701 * @comp: the compiled expression
702 * @ch1: first child index
703 * @ch2: second child index
704 * @op: an op
705 * @value: the first int value
706 * @value2: the second int value
707 * @value3: the third int value
708 * @value4: the first string value
709 * @value5: the second string value
710 *
William M. Brack08171912003-12-29 02:52:11 +0000711 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000712 *
713 * Returns -1 in case of failure, the index otherwise
714 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000715static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000716xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
717 xmlXPathOp op, int value,
718 int value2, int value3, void *value4, void *value5) {
719 if (comp->nbStep >= comp->maxStep) {
720 xmlXPathStepOp *real;
721
722 comp->maxStep *= 2;
723 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
724 comp->maxStep * sizeof(xmlXPathStepOp));
725 if (real == NULL) {
726 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000727 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000728 return(-1);
729 }
730 comp->steps = real;
731 }
732 comp->last = comp->nbStep;
733 comp->steps[comp->nbStep].ch1 = ch1;
734 comp->steps[comp->nbStep].ch2 = ch2;
735 comp->steps[comp->nbStep].op = op;
736 comp->steps[comp->nbStep].value = value;
737 comp->steps[comp->nbStep].value2 = value2;
738 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000739 if ((comp->dict != NULL) &&
740 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
741 (op == XPATH_OP_COLLECT))) {
742 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000743 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000744 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000745 xmlFree(value4);
746 } else
747 comp->steps[comp->nbStep].value4 = NULL;
748 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000749 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000750 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000751 xmlFree(value5);
752 } else
753 comp->steps[comp->nbStep].value5 = NULL;
754 } else {
755 comp->steps[comp->nbStep].value4 = value4;
756 comp->steps[comp->nbStep].value5 = value5;
757 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000758 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000759 return(comp->nbStep++);
760}
761
Daniel Veillardf06307e2001-07-03 10:35:50 +0000762/**
763 * xmlXPathCompSwap:
764 * @comp: the compiled expression
765 * @op: operation index
766 *
767 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000768 */
769static void
770xmlXPathCompSwap(xmlXPathStepOpPtr op) {
771 int tmp;
772
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000773#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000774 /*
775 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000776 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000777 * application
778 */
779 if (xmlXPathDisableOptimizer)
780 return;
781#endif
782
Daniel Veillardf06307e2001-07-03 10:35:50 +0000783 tmp = op->ch1;
784 op->ch1 = op->ch2;
785 op->ch2 = tmp;
786}
787
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000788#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
789 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
790 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000791#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
792 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
793 (op), (val), (val2), (val3), (val4), (val5))
794
795#define PUSH_LEAVE_EXPR(op, val, val2) \
796xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
797
798#define PUSH_UNARY_EXPR(op, ch, val, val2) \
799xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
800
801#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000802xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
803 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804
805/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000806 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000807 * XPath object cache structures *
808 * *
809 ************************************************************************/
810
811/* #define XP_DEFAULT_CACHE_ON */
812
813#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->objCache != NULL))
814
815typedef struct _xmlXPathObjectCache xmlXPathObjectCache;
816typedef xmlXPathObjectCache *xmlXPathObjectCachePtr;
817struct _xmlXPathObjectCache {
818 xmlPointerListPtr nodesetObjs;
819 xmlPointerListPtr stringObjs;
820 xmlPointerListPtr booleanObjs;
821 xmlPointerListPtr numberObjs;
822 xmlPointerListPtr miscObjs;
823 int maxNodeset;
824 int maxString;
825 int maxBoolean;
826 int maxNumber;
827 int maxMisc;
828#ifdef XP_DEBUG_OBJ_USAGE
829 int dbgCachedAll;
830 int dbgCachedNodeset;
831 int dbgCachedString;
832 int dbgCachedBool;
833 int dbgCachedNumber;
834 int dbgCachedPoint;
835 int dbgCachedRange;
836 int dbgCachedLocset;
837 int dbgCachedUsers;
838 int dbgCachedXSLTTree;
839 int dbgCachedUndefined;
840
841
842 int dbgReusedAll;
843 int dbgReusedNodeset;
844 int dbgReusedString;
845 int dbgReusedBool;
846 int dbgReusedNumber;
847 int dbgReusedPoint;
848 int dbgReusedRange;
849 int dbgReusedLocset;
850 int dbgReusedUsers;
851 int dbgReusedXSLTTree;
852 int dbgReusedUndefined;
853
854#endif
855};
856
857/************************************************************************
858 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000859 * Debugging related functions *
860 * *
861 ************************************************************************/
862
Owen Taylor3473f882001-02-23 17:55:21 +0000863#define STRANGE \
864 xmlGenericError(xmlGenericErrorContext, \
865 "Internal error at %s:%d\n", \
866 __FILE__, __LINE__);
867
868#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000869static void
870xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000871 int i;
872 char shift[100];
873
874 for (i = 0;((i < depth) && (i < 25));i++)
875 shift[2 * i] = shift[2 * i + 1] = ' ';
876 shift[2 * i] = shift[2 * i + 1] = 0;
877 if (cur == NULL) {
878 fprintf(output, shift);
879 fprintf(output, "Node is NULL !\n");
880 return;
881
882 }
883
884 if ((cur->type == XML_DOCUMENT_NODE) ||
885 (cur->type == XML_HTML_DOCUMENT_NODE)) {
886 fprintf(output, shift);
887 fprintf(output, " /\n");
888 } else if (cur->type == XML_ATTRIBUTE_NODE)
889 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
890 else
891 xmlDebugDumpOneNode(output, cur, depth);
892}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000893static void
894xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000895 xmlNodePtr tmp;
896 int i;
897 char shift[100];
898
899 for (i = 0;((i < depth) && (i < 25));i++)
900 shift[2 * i] = shift[2 * i + 1] = ' ';
901 shift[2 * i] = shift[2 * i + 1] = 0;
902 if (cur == NULL) {
903 fprintf(output, shift);
904 fprintf(output, "Node is NULL !\n");
905 return;
906
907 }
908
909 while (cur != NULL) {
910 tmp = cur;
911 cur = cur->next;
912 xmlDebugDumpOneNode(output, tmp, depth);
913 }
914}
Owen Taylor3473f882001-02-23 17:55:21 +0000915
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000916static void
917xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000918 int i;
919 char shift[100];
920
921 for (i = 0;((i < depth) && (i < 25));i++)
922 shift[2 * i] = shift[2 * i + 1] = ' ';
923 shift[2 * i] = shift[2 * i + 1] = 0;
924
925 if (cur == NULL) {
926 fprintf(output, shift);
927 fprintf(output, "NodeSet is NULL !\n");
928 return;
929
930 }
931
Daniel Veillard911f49a2001-04-07 15:39:35 +0000932 if (cur != NULL) {
933 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
934 for (i = 0;i < cur->nodeNr;i++) {
935 fprintf(output, shift);
936 fprintf(output, "%d", i + 1);
937 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
938 }
Owen Taylor3473f882001-02-23 17:55:21 +0000939 }
940}
941
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000942static void
943xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000944 int i;
945 char shift[100];
946
947 for (i = 0;((i < depth) && (i < 25));i++)
948 shift[2 * i] = shift[2 * i + 1] = ' ';
949 shift[2 * i] = shift[2 * i + 1] = 0;
950
951 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
952 fprintf(output, shift);
953 fprintf(output, "Value Tree is NULL !\n");
954 return;
955
956 }
957
958 fprintf(output, shift);
959 fprintf(output, "%d", i + 1);
960 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
961}
Owen Taylor3473f882001-02-23 17:55:21 +0000962#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000963static void
964xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000965 int i;
966 char shift[100];
967
968 for (i = 0;((i < depth) && (i < 25));i++)
969 shift[2 * i] = shift[2 * i + 1] = ' ';
970 shift[2 * i] = shift[2 * i + 1] = 0;
971
972 if (cur == NULL) {
973 fprintf(output, shift);
974 fprintf(output, "LocationSet is NULL !\n");
975 return;
976
977 }
978
979 for (i = 0;i < cur->locNr;i++) {
980 fprintf(output, shift);
981 fprintf(output, "%d : ", i + 1);
982 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
983 }
984}
Daniel Veillard017b1082001-06-21 11:20:21 +0000985#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000986
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000987/**
988 * xmlXPathDebugDumpObject:
989 * @output: the FILE * to dump the output
990 * @cur: the object to inspect
991 * @depth: indentation level
992 *
993 * Dump the content of the object for debugging purposes
994 */
995void
996xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000997 int i;
998 char shift[100];
999
Daniel Veillarda82b1822004-11-08 16:24:57 +00001000 if (output == NULL) return;
1001
Owen Taylor3473f882001-02-23 17:55:21 +00001002 for (i = 0;((i < depth) && (i < 25));i++)
1003 shift[2 * i] = shift[2 * i + 1] = ' ';
1004 shift[2 * i] = shift[2 * i + 1] = 0;
1005
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001006
1007 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001008
1009 if (cur == NULL) {
1010 fprintf(output, "Object is empty (NULL)\n");
1011 return;
1012 }
1013 switch(cur->type) {
1014 case XPATH_UNDEFINED:
1015 fprintf(output, "Object is uninitialized\n");
1016 break;
1017 case XPATH_NODESET:
1018 fprintf(output, "Object is a Node Set :\n");
1019 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1020 break;
1021 case XPATH_XSLT_TREE:
1022 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001023 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001024 break;
1025 case XPATH_BOOLEAN:
1026 fprintf(output, "Object is a Boolean : ");
1027 if (cur->boolval) fprintf(output, "true\n");
1028 else fprintf(output, "false\n");
1029 break;
1030 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001031 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001032 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001033 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001034 break;
1035 case -1:
1036 fprintf(output, "Object is a number : -Infinity\n");
1037 break;
1038 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001039 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001040 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001041 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1042 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001043 } else {
1044 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1045 }
1046 }
Owen Taylor3473f882001-02-23 17:55:21 +00001047 break;
1048 case XPATH_STRING:
1049 fprintf(output, "Object is a string : ");
1050 xmlDebugDumpString(output, cur->stringval);
1051 fprintf(output, "\n");
1052 break;
1053 case XPATH_POINT:
1054 fprintf(output, "Object is a point : index %d in node", cur->index);
1055 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1056 fprintf(output, "\n");
1057 break;
1058 case XPATH_RANGE:
1059 if ((cur->user2 == NULL) ||
1060 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1061 fprintf(output, "Object is a collapsed range :\n");
1062 fprintf(output, shift);
1063 if (cur->index >= 0)
1064 fprintf(output, "index %d in ", cur->index);
1065 fprintf(output, "node\n");
1066 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1067 depth + 1);
1068 } else {
1069 fprintf(output, "Object is a range :\n");
1070 fprintf(output, shift);
1071 fprintf(output, "From ");
1072 if (cur->index >= 0)
1073 fprintf(output, "index %d in ", cur->index);
1074 fprintf(output, "node\n");
1075 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1076 depth + 1);
1077 fprintf(output, shift);
1078 fprintf(output, "To ");
1079 if (cur->index2 >= 0)
1080 fprintf(output, "index %d in ", cur->index2);
1081 fprintf(output, "node\n");
1082 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1083 depth + 1);
1084 fprintf(output, "\n");
1085 }
1086 break;
1087 case XPATH_LOCATIONSET:
1088#if defined(LIBXML_XPTR_ENABLED)
1089 fprintf(output, "Object is a Location Set:\n");
1090 xmlXPathDebugDumpLocationSet(output,
1091 (xmlLocationSetPtr) cur->user, depth);
1092#endif
1093 break;
1094 case XPATH_USERS:
1095 fprintf(output, "Object is user defined\n");
1096 break;
1097 }
1098}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001099
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001100static void
1101xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001102 xmlXPathStepOpPtr op, int depth) {
1103 int i;
1104 char shift[100];
1105
1106 for (i = 0;((i < depth) && (i < 25));i++)
1107 shift[2 * i] = shift[2 * i + 1] = ' ';
1108 shift[2 * i] = shift[2 * i + 1] = 0;
1109
1110 fprintf(output, shift);
1111 if (op == NULL) {
1112 fprintf(output, "Step is NULL\n");
1113 return;
1114 }
1115 switch (op->op) {
1116 case XPATH_OP_END:
1117 fprintf(output, "END"); break;
1118 case XPATH_OP_AND:
1119 fprintf(output, "AND"); break;
1120 case XPATH_OP_OR:
1121 fprintf(output, "OR"); break;
1122 case XPATH_OP_EQUAL:
1123 if (op->value)
1124 fprintf(output, "EQUAL =");
1125 else
1126 fprintf(output, "EQUAL !=");
1127 break;
1128 case XPATH_OP_CMP:
1129 if (op->value)
1130 fprintf(output, "CMP <");
1131 else
1132 fprintf(output, "CMP >");
1133 if (!op->value2)
1134 fprintf(output, "=");
1135 break;
1136 case XPATH_OP_PLUS:
1137 if (op->value == 0)
1138 fprintf(output, "PLUS -");
1139 else if (op->value == 1)
1140 fprintf(output, "PLUS +");
1141 else if (op->value == 2)
1142 fprintf(output, "PLUS unary -");
1143 else if (op->value == 3)
1144 fprintf(output, "PLUS unary - -");
1145 break;
1146 case XPATH_OP_MULT:
1147 if (op->value == 0)
1148 fprintf(output, "MULT *");
1149 else if (op->value == 1)
1150 fprintf(output, "MULT div");
1151 else
1152 fprintf(output, "MULT mod");
1153 break;
1154 case XPATH_OP_UNION:
1155 fprintf(output, "UNION"); break;
1156 case XPATH_OP_ROOT:
1157 fprintf(output, "ROOT"); break;
1158 case XPATH_OP_NODE:
1159 fprintf(output, "NODE"); break;
1160 case XPATH_OP_RESET:
1161 fprintf(output, "RESET"); break;
1162 case XPATH_OP_SORT:
1163 fprintf(output, "SORT"); break;
1164 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001165 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1166 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1167 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001168 const xmlChar *prefix = op->value4;
1169 const xmlChar *name = op->value5;
1170
1171 fprintf(output, "COLLECT ");
1172 switch (axis) {
1173 case AXIS_ANCESTOR:
1174 fprintf(output, " 'ancestors' "); break;
1175 case AXIS_ANCESTOR_OR_SELF:
1176 fprintf(output, " 'ancestors-or-self' "); break;
1177 case AXIS_ATTRIBUTE:
1178 fprintf(output, " 'attributes' "); break;
1179 case AXIS_CHILD:
1180 fprintf(output, " 'child' "); break;
1181 case AXIS_DESCENDANT:
1182 fprintf(output, " 'descendant' "); break;
1183 case AXIS_DESCENDANT_OR_SELF:
1184 fprintf(output, " 'descendant-or-self' "); break;
1185 case AXIS_FOLLOWING:
1186 fprintf(output, " 'following' "); break;
1187 case AXIS_FOLLOWING_SIBLING:
1188 fprintf(output, " 'following-siblings' "); break;
1189 case AXIS_NAMESPACE:
1190 fprintf(output, " 'namespace' "); break;
1191 case AXIS_PARENT:
1192 fprintf(output, " 'parent' "); break;
1193 case AXIS_PRECEDING:
1194 fprintf(output, " 'preceding' "); break;
1195 case AXIS_PRECEDING_SIBLING:
1196 fprintf(output, " 'preceding-sibling' "); break;
1197 case AXIS_SELF:
1198 fprintf(output, " 'self' "); break;
1199 }
1200 switch (test) {
1201 case NODE_TEST_NONE:
1202 fprintf(output, "'none' "); break;
1203 case NODE_TEST_TYPE:
1204 fprintf(output, "'type' "); break;
1205 case NODE_TEST_PI:
1206 fprintf(output, "'PI' "); break;
1207 case NODE_TEST_ALL:
1208 fprintf(output, "'all' "); break;
1209 case NODE_TEST_NS:
1210 fprintf(output, "'namespace' "); break;
1211 case NODE_TEST_NAME:
1212 fprintf(output, "'name' "); break;
1213 }
1214 switch (type) {
1215 case NODE_TYPE_NODE:
1216 fprintf(output, "'node' "); break;
1217 case NODE_TYPE_COMMENT:
1218 fprintf(output, "'comment' "); break;
1219 case NODE_TYPE_TEXT:
1220 fprintf(output, "'text' "); break;
1221 case NODE_TYPE_PI:
1222 fprintf(output, "'PI' "); break;
1223 }
1224 if (prefix != NULL)
1225 fprintf(output, "%s:", prefix);
1226 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001227 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001228 break;
1229
1230 }
1231 case XPATH_OP_VALUE: {
1232 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1233
1234 fprintf(output, "ELEM ");
1235 xmlXPathDebugDumpObject(output, object, 0);
1236 goto finish;
1237 }
1238 case XPATH_OP_VARIABLE: {
1239 const xmlChar *prefix = op->value5;
1240 const xmlChar *name = op->value4;
1241
1242 if (prefix != NULL)
1243 fprintf(output, "VARIABLE %s:%s", prefix, name);
1244 else
1245 fprintf(output, "VARIABLE %s", name);
1246 break;
1247 }
1248 case XPATH_OP_FUNCTION: {
1249 int nbargs = op->value;
1250 const xmlChar *prefix = op->value5;
1251 const xmlChar *name = op->value4;
1252
1253 if (prefix != NULL)
1254 fprintf(output, "FUNCTION %s:%s(%d args)",
1255 prefix, name, nbargs);
1256 else
1257 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1258 break;
1259 }
1260 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1261 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001262 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001263#ifdef LIBXML_XPTR_ENABLED
1264 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1265#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001266 default:
1267 fprintf(output, "UNKNOWN %d\n", op->op); return;
1268 }
1269 fprintf(output, "\n");
1270finish:
1271 if (op->ch1 >= 0)
1272 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1273 if (op->ch2 >= 0)
1274 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1275}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001276
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001277/**
1278 * xmlXPathDebugDumpCompExpr:
1279 * @output: the FILE * for the output
1280 * @comp: the precompiled XPath expression
1281 * @depth: the indentation level.
1282 *
1283 * Dumps the tree of the compiled XPath expression.
1284 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001285void
1286xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1287 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001288 int i;
1289 char shift[100];
1290
Daniel Veillarda82b1822004-11-08 16:24:57 +00001291 if ((output == NULL) || (comp == NULL)) return;
1292
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001293 for (i = 0;((i < depth) && (i < 25));i++)
1294 shift[2 * i] = shift[2 * i + 1] = ' ';
1295 shift[2 * i] = shift[2 * i + 1] = 0;
1296
1297 fprintf(output, shift);
1298
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001299 fprintf(output, "Compiled Expression : %d elements\n",
1300 comp->nbStep);
1301 i = comp->last;
1302 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1303}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001304
1305#ifdef XP_DEBUG_OBJ_USAGE
1306
1307/*
1308* XPath object usage related debugging variables.
1309*/
1310static int xmlXPathDebugObjCounterUndefined = 0;
1311static int xmlXPathDebugObjCounterNodeset = 0;
1312static int xmlXPathDebugObjCounterBool = 0;
1313static int xmlXPathDebugObjCounterNumber = 0;
1314static int xmlXPathDebugObjCounterString = 0;
1315static int xmlXPathDebugObjCounterPoint = 0;
1316static int xmlXPathDebugObjCounterRange = 0;
1317static int xmlXPathDebugObjCounterLocset = 0;
1318static int xmlXPathDebugObjCounterUsers = 0;
1319static int xmlXPathDebugObjCounterXSLTTree = 0;
1320static int xmlXPathDebugObjCounterAll = 0;
1321
1322static int xmlXPathDebugObjTotalUndefined = 0;
1323static int xmlXPathDebugObjTotalNodeset = 0;
1324static int xmlXPathDebugObjTotalBool = 0;
1325static int xmlXPathDebugObjTotalNumber = 0;
1326static int xmlXPathDebugObjTotalString = 0;
1327static int xmlXPathDebugObjTotalPoint = 0;
1328static int xmlXPathDebugObjTotalRange = 0;
1329static int xmlXPathDebugObjTotalLocset = 0;
1330static int xmlXPathDebugObjTotalUsers = 0;
1331static int xmlXPathDebugObjTotalXSLTTree = 0;
1332static int xmlXPathDebugObjTotalAll = 0;
1333
1334static int xmlXPathDebugObjMaxUndefined = 0;
1335static int xmlXPathDebugObjMaxNodeset = 0;
1336static int xmlXPathDebugObjMaxBool = 0;
1337static int xmlXPathDebugObjMaxNumber = 0;
1338static int xmlXPathDebugObjMaxString = 0;
1339static int xmlXPathDebugObjMaxPoint = 0;
1340static int xmlXPathDebugObjMaxRange = 0;
1341static int xmlXPathDebugObjMaxLocset = 0;
1342static int xmlXPathDebugObjMaxUsers = 0;
1343static int xmlXPathDebugObjMaxXSLTTree = 0;
1344static int xmlXPathDebugObjMaxAll = 0;
1345
1346/* REVISIT TODO: Make this static when committing */
1347static void
1348xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1349{
1350 if (ctxt != NULL) {
1351 if (ctxt->objCache != NULL) {
1352 xmlXPathObjectCachePtr cache =
1353 (xmlXPathObjectCachePtr) ctxt->objCache;
1354
1355 cache->dbgCachedAll = 0;
1356 cache->dbgCachedNodeset = 0;
1357 cache->dbgCachedString = 0;
1358 cache->dbgCachedBool = 0;
1359 cache->dbgCachedNumber = 0;
1360 cache->dbgCachedPoint = 0;
1361 cache->dbgCachedRange = 0;
1362 cache->dbgCachedLocset = 0;
1363 cache->dbgCachedUsers = 0;
1364 cache->dbgCachedXSLTTree = 0;
1365 cache->dbgCachedUndefined = 0;
1366
1367 cache->dbgReusedAll = 0;
1368 cache->dbgReusedNodeset = 0;
1369 cache->dbgReusedString = 0;
1370 cache->dbgReusedBool = 0;
1371 cache->dbgReusedNumber = 0;
1372 cache->dbgReusedPoint = 0;
1373 cache->dbgReusedRange = 0;
1374 cache->dbgReusedLocset = 0;
1375 cache->dbgReusedUsers = 0;
1376 cache->dbgReusedXSLTTree = 0;
1377 cache->dbgReusedUndefined = 0;
1378 }
1379 }
1380
1381 xmlXPathDebugObjCounterUndefined = 0;
1382 xmlXPathDebugObjCounterNodeset = 0;
1383 xmlXPathDebugObjCounterBool = 0;
1384 xmlXPathDebugObjCounterNumber = 0;
1385 xmlXPathDebugObjCounterString = 0;
1386 xmlXPathDebugObjCounterPoint = 0;
1387 xmlXPathDebugObjCounterRange = 0;
1388 xmlXPathDebugObjCounterLocset = 0;
1389 xmlXPathDebugObjCounterUsers = 0;
1390 xmlXPathDebugObjCounterXSLTTree = 0;
1391 xmlXPathDebugObjCounterAll = 0;
1392
1393 xmlXPathDebugObjTotalUndefined = 0;
1394 xmlXPathDebugObjTotalNodeset = 0;
1395 xmlXPathDebugObjTotalBool = 0;
1396 xmlXPathDebugObjTotalNumber = 0;
1397 xmlXPathDebugObjTotalString = 0;
1398 xmlXPathDebugObjTotalPoint = 0;
1399 xmlXPathDebugObjTotalRange = 0;
1400 xmlXPathDebugObjTotalLocset = 0;
1401 xmlXPathDebugObjTotalUsers = 0;
1402 xmlXPathDebugObjTotalXSLTTree = 0;
1403 xmlXPathDebugObjTotalAll = 0;
1404
1405 xmlXPathDebugObjMaxUndefined = 0;
1406 xmlXPathDebugObjMaxNodeset = 0;
1407 xmlXPathDebugObjMaxBool = 0;
1408 xmlXPathDebugObjMaxNumber = 0;
1409 xmlXPathDebugObjMaxString = 0;
1410 xmlXPathDebugObjMaxPoint = 0;
1411 xmlXPathDebugObjMaxRange = 0;
1412 xmlXPathDebugObjMaxLocset = 0;
1413 xmlXPathDebugObjMaxUsers = 0;
1414 xmlXPathDebugObjMaxXSLTTree = 0;
1415 xmlXPathDebugObjMaxAll = 0;
1416
1417}
1418
1419static void
1420xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1421 xmlXPathObjectType objType)
1422{
1423 int isCached = 0;
1424
1425 if (ctxt != NULL) {
1426 if (ctxt->objCache != NULL) {
1427 xmlXPathObjectCachePtr cache =
1428 (xmlXPathObjectCachePtr) ctxt->objCache;
1429
1430 isCached = 1;
1431
1432 cache->dbgReusedAll++;
1433 switch (objType) {
1434 case XPATH_UNDEFINED:
1435 cache->dbgReusedUndefined++;
1436 break;
1437 case XPATH_NODESET:
1438 cache->dbgReusedNodeset++;
1439 break;
1440 case XPATH_BOOLEAN:
1441 cache->dbgReusedBool++;
1442 break;
1443 case XPATH_NUMBER:
1444 cache->dbgReusedNumber++;
1445 break;
1446 case XPATH_STRING:
1447 cache->dbgReusedString++;
1448 break;
1449 case XPATH_POINT:
1450 cache->dbgReusedPoint++;
1451 break;
1452 case XPATH_RANGE:
1453 cache->dbgReusedRange++;
1454 break;
1455 case XPATH_LOCATIONSET:
1456 cache->dbgReusedLocset++;
1457 break;
1458 case XPATH_USERS:
1459 cache->dbgReusedUsers++;
1460 break;
1461 case XPATH_XSLT_TREE:
1462 cache->dbgReusedXSLTTree++;
1463 break;
1464 default:
1465 break;
1466 }
1467 }
1468 }
1469
1470 switch (objType) {
1471 case XPATH_UNDEFINED:
1472 if (! isCached)
1473 xmlXPathDebugObjTotalUndefined++;
1474 xmlXPathDebugObjCounterUndefined++;
1475 if (xmlXPathDebugObjCounterUndefined >
1476 xmlXPathDebugObjMaxUndefined)
1477 xmlXPathDebugObjMaxUndefined =
1478 xmlXPathDebugObjCounterUndefined;
1479 break;
1480 case XPATH_NODESET:
1481 if (! isCached)
1482 xmlXPathDebugObjTotalNodeset++;
1483 xmlXPathDebugObjCounterNodeset++;
1484 if (xmlXPathDebugObjCounterNodeset >
1485 xmlXPathDebugObjMaxNodeset)
1486 xmlXPathDebugObjMaxNodeset =
1487 xmlXPathDebugObjCounterNodeset;
1488 break;
1489 case XPATH_BOOLEAN:
1490 if (! isCached)
1491 xmlXPathDebugObjTotalBool++;
1492 xmlXPathDebugObjCounterBool++;
1493 if (xmlXPathDebugObjCounterBool >
1494 xmlXPathDebugObjMaxBool)
1495 xmlXPathDebugObjMaxBool =
1496 xmlXPathDebugObjCounterBool;
1497 break;
1498 case XPATH_NUMBER:
1499 if (! isCached)
1500 xmlXPathDebugObjTotalNumber++;
1501 xmlXPathDebugObjCounterNumber++;
1502 if (xmlXPathDebugObjCounterNumber >
1503 xmlXPathDebugObjMaxNumber)
1504 xmlXPathDebugObjMaxNumber =
1505 xmlXPathDebugObjCounterNumber;
1506 break;
1507 case XPATH_STRING:
1508 if (! isCached)
1509 xmlXPathDebugObjTotalString++;
1510 xmlXPathDebugObjCounterString++;
1511 if (xmlXPathDebugObjCounterString >
1512 xmlXPathDebugObjMaxString)
1513 xmlXPathDebugObjMaxString =
1514 xmlXPathDebugObjCounterString;
1515 break;
1516 case XPATH_POINT:
1517 if (! isCached)
1518 xmlXPathDebugObjTotalPoint++;
1519 xmlXPathDebugObjCounterPoint++;
1520 if (xmlXPathDebugObjCounterPoint >
1521 xmlXPathDebugObjMaxPoint)
1522 xmlXPathDebugObjMaxPoint =
1523 xmlXPathDebugObjCounterPoint;
1524 break;
1525 case XPATH_RANGE:
1526 if (! isCached)
1527 xmlXPathDebugObjTotalRange++;
1528 xmlXPathDebugObjCounterRange++;
1529 if (xmlXPathDebugObjCounterRange >
1530 xmlXPathDebugObjMaxRange)
1531 xmlXPathDebugObjMaxRange =
1532 xmlXPathDebugObjCounterRange;
1533 break;
1534 case XPATH_LOCATIONSET:
1535 if (! isCached)
1536 xmlXPathDebugObjTotalLocset++;
1537 xmlXPathDebugObjCounterLocset++;
1538 if (xmlXPathDebugObjCounterLocset >
1539 xmlXPathDebugObjMaxLocset)
1540 xmlXPathDebugObjMaxLocset =
1541 xmlXPathDebugObjCounterLocset;
1542 break;
1543 case XPATH_USERS:
1544 if (! isCached)
1545 xmlXPathDebugObjTotalUsers++;
1546 xmlXPathDebugObjCounterUsers++;
1547 if (xmlXPathDebugObjCounterUsers >
1548 xmlXPathDebugObjMaxUsers)
1549 xmlXPathDebugObjMaxUsers =
1550 xmlXPathDebugObjCounterUsers;
1551 break;
1552 case XPATH_XSLT_TREE:
1553 if (! isCached)
1554 xmlXPathDebugObjTotalXSLTTree++;
1555 xmlXPathDebugObjCounterXSLTTree++;
1556 if (xmlXPathDebugObjCounterXSLTTree >
1557 xmlXPathDebugObjMaxXSLTTree)
1558 xmlXPathDebugObjMaxXSLTTree =
1559 xmlXPathDebugObjCounterXSLTTree;
1560 break;
1561 default:
1562 break;
1563 }
1564 if (! isCached)
1565 xmlXPathDebugObjTotalAll++;
1566 xmlXPathDebugObjCounterAll++;
1567 if (xmlXPathDebugObjCounterAll >
1568 xmlXPathDebugObjMaxAll)
1569 xmlXPathDebugObjMaxAll =
1570 xmlXPathDebugObjCounterAll;
1571}
1572
1573static void
1574xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1575 xmlXPathObjectType objType)
1576{
1577 int isCached = 0;
1578
1579 if (ctxt != NULL) {
1580 if (ctxt->objCache != NULL) {
1581 xmlXPathObjectCachePtr cache =
1582 (xmlXPathObjectCachePtr) ctxt->objCache;
1583
1584 isCached = 1;
1585
1586 cache->dbgCachedAll++;
1587 switch (objType) {
1588 case XPATH_UNDEFINED:
1589 cache->dbgCachedUndefined++;
1590 break;
1591 case XPATH_NODESET:
1592 cache->dbgCachedNodeset++;
1593 break;
1594 case XPATH_BOOLEAN:
1595 cache->dbgCachedBool++;
1596 break;
1597 case XPATH_NUMBER:
1598 cache->dbgCachedNumber++;
1599 break;
1600 case XPATH_STRING:
1601 cache->dbgCachedString++;
1602 break;
1603 case XPATH_POINT:
1604 cache->dbgCachedPoint++;
1605 break;
1606 case XPATH_RANGE:
1607 cache->dbgCachedRange++;
1608 break;
1609 case XPATH_LOCATIONSET:
1610 cache->dbgCachedLocset++;
1611 break;
1612 case XPATH_USERS:
1613 cache->dbgCachedUsers++;
1614 break;
1615 case XPATH_XSLT_TREE:
1616 cache->dbgCachedXSLTTree++;
1617 break;
1618 default:
1619 break;
1620 }
1621
1622 }
1623 }
1624 switch (objType) {
1625 case XPATH_UNDEFINED:
1626 xmlXPathDebugObjCounterUndefined--;
1627 break;
1628 case XPATH_NODESET:
1629 xmlXPathDebugObjCounterNodeset--;
1630 break;
1631 case XPATH_BOOLEAN:
1632 xmlXPathDebugObjCounterBool--;
1633 break;
1634 case XPATH_NUMBER:
1635 xmlXPathDebugObjCounterNumber--;
1636 break;
1637 case XPATH_STRING:
1638 xmlXPathDebugObjCounterString--;
1639 break;
1640 case XPATH_POINT:
1641 xmlXPathDebugObjCounterPoint--;
1642 break;
1643 case XPATH_RANGE:
1644 xmlXPathDebugObjCounterRange--;
1645 break;
1646 case XPATH_LOCATIONSET:
1647 xmlXPathDebugObjCounterLocset--;
1648 break;
1649 case XPATH_USERS:
1650 xmlXPathDebugObjCounterUsers--;
1651 break;
1652 case XPATH_XSLT_TREE:
1653 xmlXPathDebugObjCounterXSLTTree--;
1654 break;
1655 default:
1656 break;
1657 }
1658 xmlXPathDebugObjCounterAll--;
1659}
1660
1661/* REVISIT TODO: Make this static when committing */
1662static void
1663xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1664{
1665 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1666 reqXSLTTree, reqUndefined;
1667 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1668 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1669 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1670 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1671 int leftObjs = xmlXPathDebugObjCounterAll;
1672
1673 reqAll = xmlXPathDebugObjTotalAll;
1674 reqNodeset = xmlXPathDebugObjTotalNodeset;
1675 reqString = xmlXPathDebugObjTotalString;
1676 reqBool = xmlXPathDebugObjTotalBool;
1677 reqNumber = xmlXPathDebugObjTotalNumber;
1678 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1679 reqUndefined = xmlXPathDebugObjTotalUndefined;
1680
1681 printf("# XPath object usage:\n");
1682
1683 if (ctxt != NULL) {
1684 if (ctxt->objCache != NULL) {
1685 xmlXPathObjectCachePtr cache =
1686 (xmlXPathObjectCachePtr) ctxt->objCache;
1687
1688 reAll = cache->dbgReusedAll;
1689 reqAll += reAll;
1690 reNodeset = cache->dbgReusedNodeset;
1691 reqNodeset += reNodeset;
1692 reString = cache->dbgReusedString;
1693 reqString += reString;
1694 reBool = cache->dbgReusedBool;
1695 reqBool += reBool;
1696 reNumber = cache->dbgReusedNumber;
1697 reqNumber += reNumber;
1698 reXSLTTree = cache->dbgReusedXSLTTree;
1699 reqXSLTTree += reXSLTTree;
1700 reUndefined = cache->dbgReusedUndefined;
1701 reqUndefined += reUndefined;
1702
1703 caAll = cache->dbgCachedAll;
1704 caBool = cache->dbgCachedBool;
1705 caNodeset = cache->dbgCachedNodeset;
1706 caString = cache->dbgCachedString;
1707 caNumber = cache->dbgCachedNumber;
1708 caXSLTTree = cache->dbgCachedXSLTTree;
1709 caUndefined = cache->dbgCachedUndefined;
1710
1711 if (cache->nodesetObjs)
1712 leftObjs -= cache->nodesetObjs->number;
1713 if (cache->stringObjs)
1714 leftObjs -= cache->stringObjs->number;
1715 if (cache->booleanObjs)
1716 leftObjs -= cache->booleanObjs->number;
1717 if (cache->numberObjs)
1718 leftObjs -= cache->numberObjs->number;
1719 if (cache->miscObjs)
1720 leftObjs -= cache->miscObjs->number;
1721 }
1722 }
1723
1724 printf("# all\n");
1725 printf("# total : %d\n", reqAll);
1726 printf("# left : %d\n", leftObjs);
1727 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1728 printf("# reused : %d\n", reAll);
1729 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1730
1731 printf("# node-sets\n");
1732 printf("# total : %d\n", reqNodeset);
1733 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1734 printf("# reused : %d\n", reNodeset);
1735 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1736
1737 printf("# strings\n");
1738 printf("# total : %d\n", reqString);
1739 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1740 printf("# reused : %d\n", reString);
1741 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1742
1743 printf("# booleans\n");
1744 printf("# total : %d\n", reqBool);
1745 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1746 printf("# reused : %d\n", reBool);
1747 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1748
1749 printf("# numbers\n");
1750 printf("# total : %d\n", reqNumber);
1751 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1752 printf("# reused : %d\n", reNumber);
1753 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1754
1755 printf("# XSLT result tree fragments\n");
1756 printf("# total : %d\n", reqXSLTTree);
1757 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1758 printf("# reused : %d\n", reXSLTTree);
1759 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1760
1761 printf("# undefined\n");
1762 printf("# total : %d\n", reqUndefined);
1763 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1764 printf("# reused : %d\n", reUndefined);
1765 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1766
1767}
1768
1769#endif /* XP_DEBUG_OBJ_USAGE */
1770
Daniel Veillard017b1082001-06-21 11:20:21 +00001771#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001772
1773/************************************************************************
1774 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001775 * XPath object caching *
1776 * *
1777 ************************************************************************/
1778
1779/**
1780 * xmlXPathNewObjectCache:
1781 *
1782 * Create a new object cache
1783 *
1784 * Returns the xmlXPathObjectCahce just allocated.
1785 */
1786static xmlXPathObjectCachePtr
1787xmlXPathNewObjectCache(void)
1788{
1789 xmlXPathObjectCachePtr ret;
1790
1791 ret = (xmlXPathObjectCachePtr) xmlMalloc(sizeof(xmlXPathObjectCache));
1792 if (ret == NULL) {
1793 xmlXPathErrMemory(NULL, "creating object cache\n");
1794 return(NULL);
1795 }
1796 memset(ret, 0 , (size_t) sizeof(xmlXPathObjectCache));
1797 ret->maxNodeset = 100;
1798 ret->maxString = 100;
1799 ret->maxBoolean = 100;
1800 ret->maxNumber = 100;
1801 ret->maxMisc = 100;
1802 return(ret);
1803}
1804
1805static void
1806xmlXPathFreeObjectCacheList(xmlPointerListPtr list)
1807{
1808 int i;
1809 xmlXPathObjectPtr obj;
1810
1811 if (list == NULL)
1812 return;
1813
1814 for (i = 0; i < list->number; i++) {
1815 obj = list->items[i];
1816 /*
1817 * Note that it is already assured that we don't need to
1818 * look out for namespace nodes in the node-set.
1819 */
1820 if (obj->nodesetval != NULL) {
1821 if (obj->nodesetval->nodeTab != NULL)
1822 xmlFree(obj->nodesetval->nodeTab);
1823 xmlFree(obj->nodesetval);
1824 }
1825 xmlFree(obj);
1826#ifdef XP_DEBUG_OBJ_USAGE
1827 xmlXPathDebugObjCounterAll--;
1828#endif
1829 }
1830 xmlPointerListFree(list);
1831}
1832
1833static void
1834xmlXPathFreeObjectCache(xmlXPathObjectCachePtr cache)
1835{
1836 if (cache == NULL)
1837 return;
1838 if (cache->nodesetObjs)
1839 xmlXPathFreeObjectCacheList(cache->nodesetObjs);
1840 if (cache->stringObjs)
1841 xmlXPathFreeObjectCacheList(cache->stringObjs);
1842 if (cache->booleanObjs)
1843 xmlXPathFreeObjectCacheList(cache->booleanObjs);
1844 if (cache->numberObjs)
1845 xmlXPathFreeObjectCacheList(cache->numberObjs);
1846 if (cache->miscObjs)
1847 xmlXPathFreeObjectCacheList(cache->miscObjs);
1848
1849 xmlFree(cache);
1850}
1851
1852/**
1853 * xmlXPathContextSetObjectCache:
1854 *
1855 * @ctxt: the XPath context
1856 * @active: enables/disables (creates/frees) the cache
1857 * @maxNumberPerSlot: the maximum number of XPath objects to be cached per slot
1858 * @options: currently not used
1859 *
1860 * Creates/frees an object cache on the XPath context.
1861 * If activates XPath objects (xmlXPathObject) will be cached internally
1862 * to be reused.
1863 * @maxNumberPerSlot is the maximum number of XPath objects to be cached per
1864 * slot. There are 5 slots for: node-set, string, number, boolean, and
1865 * misc objects. Use <0 for the default number (100).
1866 *
1867 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1868 */
1869int
1870xmlXPathContextSetObjectCache(xmlXPathContextPtr ctxt,
1871 int active,
1872 int maxNumberPerSlot,
1873 int options ATTRIBUTE_UNUSED)
1874{
1875 if (ctxt == NULL)
1876 return(-1);
1877 if (active) {
1878 xmlXPathObjectCachePtr cache;
1879
1880 if (ctxt->objCache == NULL) {
1881 ctxt->objCache = xmlXPathNewObjectCache();
1882 if (ctxt->objCache == NULL)
1883 return(-1);
1884 }
1885 cache = (xmlXPathObjectCachePtr) ctxt->objCache;
1886 if (maxNumberPerSlot < 0)
1887 maxNumberPerSlot = 100;
1888 cache->maxNodeset = maxNumberPerSlot;
1889 cache->maxString = maxNumberPerSlot;
1890 cache->maxNumber = maxNumberPerSlot;
1891 cache->maxBoolean = maxNumberPerSlot;
1892 cache->maxMisc = maxNumberPerSlot;
1893 } else if (ctxt->objCache != NULL) {
1894 xmlXPathFreeObjectCache((xmlXPathObjectCachePtr) ctxt->objCache);
1895 ctxt->objCache = NULL;
1896 }
1897 return(0);
1898}
1899
1900/**
1901 * xmlXPathCacheWrapNodeSet:
1902 * @ctxt: the XPath context
1903 * @val: the NodePtr value
1904 *
1905 * This is the cached version of xmlXPathWrapNodeSet().
1906 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1907 *
1908 * Returns the created or reused object.
1909 */
1910static xmlXPathObjectPtr
1911xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1912{
1913 if ((ctxt != NULL) && (ctxt->objCache != NULL)) {
1914 xmlXPathObjectCachePtr cache =
1915 (xmlXPathObjectCachePtr) ctxt->objCache;
1916
1917 if ((cache->miscObjs != NULL) &&
1918 (cache->miscObjs->number != 0))
1919 {
1920 xmlXPathObjectPtr ret;
1921
1922 ret = (xmlXPathObjectPtr)
1923 cache->miscObjs->items[--cache->miscObjs->number];
1924 ret->type = XPATH_NODESET;
1925 ret->nodesetval = val;
1926#ifdef XP_DEBUG_OBJ_USAGE
1927 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1928#endif
1929 return(ret);
1930 }
1931 }
1932
1933 return(xmlXPathWrapNodeSet(val));
1934
1935}
1936
1937/**
1938 * xmlXPathCacheWrapString:
1939 * @ctxt: the XPath context
1940 * @val: the xmlChar * value
1941 *
1942 * This is the cached version of xmlXPathWrapString().
1943 * Wraps the @val string into an XPath object.
1944 *
1945 * Returns the created or reused object.
1946 */
1947static xmlXPathObjectPtr
1948xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1949{
1950 if ((ctxt != NULL) && (ctxt->objCache != NULL)) {
1951 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
1952
1953 if ((cache->stringObjs != NULL) &&
1954 (cache->stringObjs->number != 0))
1955 {
1956
1957 xmlXPathObjectPtr ret;
1958
1959 ret = (xmlXPathObjectPtr)
1960 cache->stringObjs->items[--cache->stringObjs->number];
1961 ret->type = XPATH_STRING;
1962 ret->stringval = val;
1963#ifdef XP_DEBUG_OBJ_USAGE
1964 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1965#endif
1966 return(ret);
1967 } else if ((cache->miscObjs != NULL) &&
1968 (cache->miscObjs->number != 0))
1969 {
1970 xmlXPathObjectPtr ret;
1971 /*
1972 * Fallback to misc-cache.
1973 */
1974 ret = (xmlXPathObjectPtr)
1975 cache->miscObjs->items[--cache->miscObjs->number];
1976
1977 ret->type = XPATH_STRING;
1978 ret->stringval = val;
1979#ifdef XP_DEBUG_OBJ_USAGE
1980 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1981#endif
1982 return(ret);
1983 }
1984 }
1985 return(xmlXPathWrapString(val));
1986}
1987
1988/**
1989 * xmlXPathCacheNewNodeSet:
1990 * @ctxt: the XPath context
1991 * @val: the NodePtr value
1992 *
1993 * This is the cached version of xmlXPathNewNodeSet().
1994 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1995 * it with the single Node @val
1996 *
1997 * Returns the created or reused object.
1998 */
1999static xmlXPathObjectPtr
2000xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2001{
2002 if ((ctxt != NULL) && (ctxt->objCache)) {
2003 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2004
2005 if ((cache->nodesetObjs != NULL) &&
2006 (cache->nodesetObjs->number != 0))
2007 {
2008 xmlXPathObjectPtr ret;
2009 /*
2010 * Use the nodset-cache.
2011 */
2012 ret = (xmlXPathObjectPtr)
2013 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2014 ret->type = XPATH_NODESET;
2015 ret->boolval = 0;
2016 if (val) {
2017 if ((ret->nodesetval->nodeMax == 0) ||
2018 (val->type == XML_NAMESPACE_DECL))
2019 {
2020 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2021 } else {
2022 ret->nodesetval->nodeTab[0] = val;
2023 ret->nodesetval->nodeNr = 1;
2024 }
2025 }
2026#ifdef XP_DEBUG_OBJ_USAGE
2027 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2028#endif
2029 return(ret);
2030 } else if ((cache->miscObjs != NULL) &&
2031 (cache->miscObjs->number != 0))
2032 {
2033 xmlXPathObjectPtr ret;
2034 /*
2035 * Fallback to misc-cache.
2036 */
2037
2038 ret = (xmlXPathObjectPtr)
2039 cache->miscObjs->items[--cache->miscObjs->number];
2040
2041 ret->type = XPATH_NODESET;
2042 ret->boolval = 0;
2043 ret->nodesetval = xmlXPathNodeSetCreate(val);
2044#ifdef XP_DEBUG_OBJ_USAGE
2045 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2046#endif
2047 return(ret);
2048 }
2049 }
2050 return(xmlXPathNewNodeSet(val));
2051}
2052
2053/**
2054 * xmlXPathCacheNewCString:
2055 * @ctxt: the XPath context
2056 * @val: the char * value
2057 *
2058 * This is the cached version of xmlXPathNewCString().
2059 * Acquire an xmlXPathObjectPtr of type string and of value @val
2060 *
2061 * Returns the created or reused object.
2062 */
2063static xmlXPathObjectPtr
2064xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2065{
2066 if ((ctxt != NULL) && (ctxt->objCache)) {
2067 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2068
2069 if ((cache->stringObjs != NULL) &&
2070 (cache->stringObjs->number != 0))
2071 {
2072 xmlXPathObjectPtr ret;
2073
2074 ret = (xmlXPathObjectPtr)
2075 cache->stringObjs->items[--cache->stringObjs->number];
2076
2077 ret->type = XPATH_STRING;
2078 ret->stringval = xmlStrdup(BAD_CAST val);
2079#ifdef XP_DEBUG_OBJ_USAGE
2080 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2081#endif
2082 return(ret);
2083 } else if ((cache->miscObjs != NULL) &&
2084 (cache->miscObjs->number != 0))
2085 {
2086 xmlXPathObjectPtr ret;
2087
2088 ret = (xmlXPathObjectPtr)
2089 cache->miscObjs->items[--cache->miscObjs->number];
2090
2091 ret->type = XPATH_STRING;
2092 ret->stringval = xmlStrdup(BAD_CAST val);
2093#ifdef XP_DEBUG_OBJ_USAGE
2094 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2095#endif
2096 return(ret);
2097 }
2098 }
2099 return(xmlXPathNewCString(val));
2100}
2101
2102/**
2103 * xmlXPathCacheNewString:
2104 * @ctxt: the XPath context
2105 * @val: the xmlChar * value
2106 *
2107 * This is the cached version of xmlXPathNewString().
2108 * Acquire an xmlXPathObjectPtr of type string and of value @val
2109 *
2110 * Returns the created or reused object.
2111 */
2112static xmlXPathObjectPtr
2113xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2114{
2115 if ((ctxt != NULL) && (ctxt->objCache)) {
2116 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2117
2118 if ((cache->stringObjs != NULL) &&
2119 (cache->stringObjs->number != 0))
2120 {
2121 xmlXPathObjectPtr ret;
2122
2123 ret = (xmlXPathObjectPtr)
2124 cache->stringObjs->items[--cache->stringObjs->number];
2125 ret->type = XPATH_STRING;
2126 if (val != NULL)
2127 ret->stringval = xmlStrdup(val);
2128 else
2129 ret->stringval = xmlStrdup((const xmlChar *)"");
2130#ifdef XP_DEBUG_OBJ_USAGE
2131 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2132#endif
2133 return(ret);
2134 } else if ((cache->miscObjs != NULL) &&
2135 (cache->miscObjs->number != 0))
2136 {
2137 xmlXPathObjectPtr ret;
2138
2139 ret = (xmlXPathObjectPtr)
2140 cache->miscObjs->items[--cache->miscObjs->number];
2141
2142 ret->type = XPATH_STRING;
2143 if (val != NULL)
2144 ret->stringval = xmlStrdup(val);
2145 else
2146 ret->stringval = xmlStrdup((const xmlChar *)"");
2147#ifdef XP_DEBUG_OBJ_USAGE
2148 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2149#endif
2150 return(ret);
2151 }
2152 }
2153 return(xmlXPathNewString(val));
2154}
2155
2156/**
2157 * xmlXPathCacheNewBoolean:
2158 * @ctxt: the XPath context
2159 * @val: the boolean value
2160 *
2161 * This is the cached version of xmlXPathNewBoolean().
2162 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2163 *
2164 * Returns the created or reused object.
2165 */
2166static xmlXPathObjectPtr
2167xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2168{
2169 if ((ctxt != NULL) && (ctxt->objCache)) {
2170 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2171
2172 if ((cache->booleanObjs != NULL) &&
2173 (cache->booleanObjs->number != 0))
2174 {
2175 xmlXPathObjectPtr ret;
2176
2177 ret = (xmlXPathObjectPtr)
2178 cache->booleanObjs->items[--cache->booleanObjs->number];
2179 ret->type = XPATH_BOOLEAN;
2180 ret->boolval = (val != 0);
2181#ifdef XP_DEBUG_OBJ_USAGE
2182 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2183#endif
2184 return(ret);
2185 } else if ((cache->miscObjs != NULL) &&
2186 (cache->miscObjs->number != 0))
2187 {
2188 xmlXPathObjectPtr ret;
2189
2190 ret = (xmlXPathObjectPtr)
2191 cache->miscObjs->items[--cache->miscObjs->number];
2192
2193 ret->type = XPATH_BOOLEAN;
2194 ret->boolval = (val != 0);
2195#ifdef XP_DEBUG_OBJ_USAGE
2196 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2197#endif
2198 return(ret);
2199 }
2200 }
2201 return(xmlXPathNewBoolean(val));
2202}
2203
2204/**
2205 * xmlXPathCacheNewFloat:
2206 * @ctxt: the XPath context
2207 * @val: the double value
2208 *
2209 * This is the cached version of xmlXPathNewFloat().
2210 * Acquires an xmlXPathObjectPtr of type double and of value @val
2211 *
2212 * Returns the created or reused object.
2213 */
2214static xmlXPathObjectPtr
2215xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2216{
2217 if ((ctxt != NULL) && (ctxt->objCache)) {
2218 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2219
2220 if ((cache->numberObjs != NULL) &&
2221 (cache->numberObjs->number != 0))
2222 {
2223 xmlXPathObjectPtr ret;
2224
2225 ret = (xmlXPathObjectPtr)
2226 cache->numberObjs->items[--cache->numberObjs->number];
2227 ret->type = XPATH_NUMBER;
2228 ret->floatval = val;
2229#ifdef XP_DEBUG_OBJ_USAGE
2230 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2231#endif
2232 return(ret);
2233 } else if ((cache->miscObjs != NULL) &&
2234 (cache->miscObjs->number != 0))
2235 {
2236 xmlXPathObjectPtr ret;
2237
2238 ret = (xmlXPathObjectPtr)
2239 cache->miscObjs->items[--cache->miscObjs->number];
2240
2241 ret->type = XPATH_NUMBER;
2242 ret->floatval = val;
2243#ifdef XP_DEBUG_OBJ_USAGE
2244 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2245#endif
2246 return(ret);
2247 }
2248 }
2249 return(xmlXPathNewFloat(val));
2250}
2251
2252/**
2253 * xmlXPathCacheConvertString:
2254 * @ctxt: the XPath context
2255 * @val: an XPath object
2256 *
2257 * This is the cached version of xmlXPathConvertString().
2258 * Converts an existing object to its string() equivalent
2259 *
2260 * Returns a created or reused object, the old one is freed (cached)
2261 * (or the operation is done directly on @val)
2262 */
2263
2264static xmlXPathObjectPtr
2265xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2266 xmlChar *res = NULL;
2267
2268 if (val == NULL)
2269 return(xmlXPathCacheNewCString(ctxt, ""));
2270
2271 switch (val->type) {
2272 case XPATH_UNDEFINED:
2273#ifdef DEBUG_EXPR
2274 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2275#endif
2276 break;
2277 case XPATH_NODESET:
2278 case XPATH_XSLT_TREE:
2279 res = xmlXPathCastNodeSetToString(val->nodesetval);
2280 break;
2281 case XPATH_STRING:
2282 return(val);
2283 case XPATH_BOOLEAN:
2284 res = xmlXPathCastBooleanToString(val->boolval);
2285 break;
2286 case XPATH_NUMBER:
2287 res = xmlXPathCastNumberToString(val->floatval);
2288 break;
2289 case XPATH_USERS:
2290 case XPATH_POINT:
2291 case XPATH_RANGE:
2292 case XPATH_LOCATIONSET:
2293 TODO;
2294 break;
2295 }
2296 xmlXPathReleaseObject(ctxt, val);
2297 if (res == NULL)
2298 return(xmlXPathCacheNewCString(ctxt, ""));
2299 return(xmlXPathCacheWrapString(ctxt, res));
2300}
2301
2302/**
2303 * xmlXPathCacheObjectCopy:
2304 * @ctxt: the XPath context
2305 * @val: the original object
2306 *
2307 * This is the cached version of xmlXPathObjectCopy().
2308 * Acquire a copy of a given object
2309 *
2310 * Returns a created or reused created object.
2311 */
2312static xmlXPathObjectPtr
2313xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2314{
2315 if (val == NULL)
2316 return(NULL);
2317 return(xmlXPathObjectCopy(val));
2318
2319 switch (val->type) {
2320 case XPATH_NODESET:
2321 if (XP_HAS_CACHE(ctxt))
2322 return(xmlXPathCacheWrapNodeSet(ctxt,
2323 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2324 case XPATH_STRING:
2325 if (XP_HAS_CACHE(ctxt))
2326 return(xmlXPathCacheNewString(ctxt, val->stringval));
2327 case XPATH_BOOLEAN:
2328 if (XP_HAS_CACHE(ctxt))
2329 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2330 case XPATH_NUMBER:
2331 if (XP_HAS_CACHE(ctxt))
2332 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2333 default:
2334 break;
2335 }
2336 return(xmlXPathObjectCopy(val));
2337}
2338
2339/**
2340 * xmlXPathCacheConvertBoolean:
2341 * @ctxt: the XPath context
2342 * @val: an XPath object
2343 *
2344 * This is the cached version of xmlXPathConvertBoolean().
2345 * Converts an existing object to its boolean() equivalent
2346 *
2347 * Returns a created or reused object, the old one is freed (or the operation
2348 * is done directly on @val)
2349 */
2350static xmlXPathObjectPtr
2351xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2352 xmlXPathObjectPtr ret;
2353
2354 if (val == NULL)
2355 return(xmlXPathCacheNewBoolean(ctxt, 0));
2356 if (val->type == XPATH_BOOLEAN)
2357 return(val);
2358 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2359 xmlXPathReleaseObject(ctxt, val);
2360 return(ret);
2361}
2362
2363/**
2364 * xmlXPathCacheConvertNumber:
2365 * @ctxt: the XPath context
2366 * @val: an XPath object
2367 *
2368 * This is the cached version of xmlXPathConvertNumber().
2369 * Converts an existing object to its number() equivalent
2370 *
2371 * Returns a created or reused object, the old one is freed (or the operation
2372 * is done directly on @val)
2373 */
2374static xmlXPathObjectPtr
2375xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2376 xmlXPathObjectPtr ret;
2377
2378 if (val == NULL)
2379 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2380 if (val->type == XPATH_NUMBER)
2381 return(val);
2382 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2383 xmlXPathReleaseObject(ctxt, val);
2384 return(ret);
2385}
2386
2387/************************************************************************
2388 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002389 * Parser stacks related functions and macros *
2390 * *
2391 ************************************************************************/
2392
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002393/**
2394 * valuePop:
2395 * @ctxt: an XPath evaluation context
2396 *
2397 * Pops the top XPath object from the value stack
2398 *
2399 * Returns the XPath object just removed
2400 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002401xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002402valuePop(xmlXPathParserContextPtr ctxt)
2403{
2404 xmlXPathObjectPtr ret;
2405
Daniel Veillarda82b1822004-11-08 16:24:57 +00002406 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002407 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002408 ctxt->valueNr--;
2409 if (ctxt->valueNr > 0)
2410 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2411 else
2412 ctxt->value = NULL;
2413 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002414 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002415 return (ret);
2416}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002417/**
2418 * valuePush:
2419 * @ctxt: an XPath evaluation context
2420 * @value: the XPath object
2421 *
2422 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002423 *
2424 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002425 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002426int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002427valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2428{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002429 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002430 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002431 xmlXPathObjectPtr *tmp;
2432
2433 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2434 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002435 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002436 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002437 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2438 return (0);
2439 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002440 ctxt->valueMax *= 2;
2441 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 }
2443 ctxt->valueTab[ctxt->valueNr] = value;
2444 ctxt->value = value;
2445 return (ctxt->valueNr++);
2446}
Owen Taylor3473f882001-02-23 17:55:21 +00002447
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002448/**
2449 * xmlXPathPopBoolean:
2450 * @ctxt: an XPath parser context
2451 *
2452 * Pops a boolean from the stack, handling conversion if needed.
2453 * Check error with #xmlXPathCheckError.
2454 *
2455 * Returns the boolean
2456 */
2457int
2458xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2459 xmlXPathObjectPtr obj;
2460 int ret;
2461
2462 obj = valuePop(ctxt);
2463 if (obj == NULL) {
2464 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2465 return(0);
2466 }
William M. Brack08171912003-12-29 02:52:11 +00002467 if (obj->type != XPATH_BOOLEAN)
2468 ret = xmlXPathCastToBoolean(obj);
2469 else
2470 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002471 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002472 return(ret);
2473}
2474
2475/**
2476 * xmlXPathPopNumber:
2477 * @ctxt: an XPath parser context
2478 *
2479 * Pops a number from the stack, handling conversion if needed.
2480 * Check error with #xmlXPathCheckError.
2481 *
2482 * Returns the number
2483 */
2484double
2485xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2486 xmlXPathObjectPtr obj;
2487 double ret;
2488
2489 obj = valuePop(ctxt);
2490 if (obj == NULL) {
2491 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2492 return(0);
2493 }
William M. Brack08171912003-12-29 02:52:11 +00002494 if (obj->type != XPATH_NUMBER)
2495 ret = xmlXPathCastToNumber(obj);
2496 else
2497 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002498 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002499 return(ret);
2500}
2501
2502/**
2503 * xmlXPathPopString:
2504 * @ctxt: an XPath parser context
2505 *
2506 * Pops a string from the stack, handling conversion if needed.
2507 * Check error with #xmlXPathCheckError.
2508 *
2509 * Returns the string
2510 */
2511xmlChar *
2512xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2513 xmlXPathObjectPtr obj;
2514 xmlChar * ret;
2515
2516 obj = valuePop(ctxt);
2517 if (obj == NULL) {
2518 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2519 return(NULL);
2520 }
William M. Brack08171912003-12-29 02:52:11 +00002521 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002522 /* TODO: needs refactoring somewhere else */
2523 if (obj->stringval == ret)
2524 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002525 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002526 return(ret);
2527}
2528
2529/**
2530 * xmlXPathPopNodeSet:
2531 * @ctxt: an XPath parser context
2532 *
2533 * Pops a node-set from the stack, handling conversion if needed.
2534 * Check error with #xmlXPathCheckError.
2535 *
2536 * Returns the node-set
2537 */
2538xmlNodeSetPtr
2539xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2540 xmlXPathObjectPtr obj;
2541 xmlNodeSetPtr ret;
2542
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002543 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002544 if (ctxt->value == NULL) {
2545 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2546 return(NULL);
2547 }
2548 if (!xmlXPathStackIsNodeSet(ctxt)) {
2549 xmlXPathSetTypeError(ctxt);
2550 return(NULL);
2551 }
2552 obj = valuePop(ctxt);
2553 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002554#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002555 /* to fix memory leak of not clearing obj->user */
2556 if (obj->boolval && obj->user != NULL)
2557 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002558#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002559 obj->nodesetval = NULL;
2560 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002561 return(ret);
2562}
2563
2564/**
2565 * xmlXPathPopExternal:
2566 * @ctxt: an XPath parser context
2567 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002568 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002569 * Check error with #xmlXPathCheckError.
2570 *
2571 * Returns the object
2572 */
2573void *
2574xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2575 xmlXPathObjectPtr obj;
2576 void * ret;
2577
Daniel Veillarda82b1822004-11-08 16:24:57 +00002578 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002579 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2580 return(NULL);
2581 }
2582 if (ctxt->value->type != XPATH_USERS) {
2583 xmlXPathSetTypeError(ctxt);
2584 return(NULL);
2585 }
2586 obj = valuePop(ctxt);
2587 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002588 obj->user = NULL;
2589 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002590 return(ret);
2591}
2592
Owen Taylor3473f882001-02-23 17:55:21 +00002593/*
2594 * Macros for accessing the content. Those should be used only by the parser,
2595 * and not exported.
2596 *
2597 * Dirty macros, i.e. one need to make assumption on the context to use them
2598 *
2599 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2600 * CUR returns the current xmlChar value, i.e. a 8 bit value
2601 * in ISO-Latin or UTF-8.
2602 * This should be used internally by the parser
2603 * only to compare to ASCII values otherwise it would break when
2604 * running with UTF-8 encoding.
2605 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2606 * to compare on ASCII based substring.
2607 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2608 * strings within the parser.
2609 * CURRENT Returns the current char value, with the full decoding of
2610 * UTF-8 if we are using this mode. It returns an int.
2611 * NEXT Skip to the next character, this does the proper decoding
2612 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2613 * It returns the pointer to the current xmlChar.
2614 */
2615
2616#define CUR (*ctxt->cur)
2617#define SKIP(val) ctxt->cur += (val)
2618#define NXT(val) ctxt->cur[(val)]
2619#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002620#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2621
2622#define COPY_BUF(l,b,i,v) \
2623 if (l == 1) b[i++] = (xmlChar) v; \
2624 else i += xmlCopyChar(l,&b[i],v)
2625
2626#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002627
2628#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002629 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002630
2631#define CURRENT (*ctxt->cur)
2632#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2633
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002634
2635#ifndef DBL_DIG
2636#define DBL_DIG 16
2637#endif
2638#ifndef DBL_EPSILON
2639#define DBL_EPSILON 1E-9
2640#endif
2641
2642#define UPPER_DOUBLE 1E9
2643#define LOWER_DOUBLE 1E-5
2644
2645#define INTEGER_DIGITS DBL_DIG
2646#define FRACTION_DIGITS (DBL_DIG + 1)
2647#define EXPONENT_DIGITS (3 + 2)
2648
2649/**
2650 * xmlXPathFormatNumber:
2651 * @number: number to format
2652 * @buffer: output buffer
2653 * @buffersize: size of output buffer
2654 *
2655 * Convert the number into a string representation.
2656 */
2657static void
2658xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2659{
Daniel Veillardcda96922001-08-21 10:56:31 +00002660 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002661 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002662 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002663 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002664 break;
2665 case -1:
2666 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002667 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002668 break;
2669 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002670 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002671 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002672 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002673 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002674 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002675 } else if (number == ((int) number)) {
2676 char work[30];
2677 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002678 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002679
2680 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002681 if (value == 0) {
2682 *ptr++ = '0';
2683 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002684 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002685 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002686 while ((*cur) && (ptr - buffer < buffersize)) {
2687 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002688 }
2689 }
2690 if (ptr - buffer < buffersize) {
2691 *ptr = 0;
2692 } else if (buffersize > 0) {
2693 ptr--;
2694 *ptr = 0;
2695 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002696 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002697 /* 3 is sign, decimal point, and terminating zero */
2698 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2699 int integer_place, fraction_place;
2700 char *ptr;
2701 char *after_fraction;
2702 double absolute_value;
2703 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002704
Bjorn Reese70a9da52001-04-21 16:57:29 +00002705 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002706
Bjorn Reese70a9da52001-04-21 16:57:29 +00002707 /*
2708 * First choose format - scientific or regular floating point.
2709 * In either case, result is in work, and after_fraction points
2710 * just past the fractional part.
2711 */
2712 if ( ((absolute_value > UPPER_DOUBLE) ||
2713 (absolute_value < LOWER_DOUBLE)) &&
2714 (absolute_value != 0.0) ) {
2715 /* Use scientific notation */
2716 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2717 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002718 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002719 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002720 while ((size > 0) && (work[size] != 'e')) size--;
2721 after_fraction = work + size;
2722
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002723 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002724 else {
2725 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002726 if (absolute_value > 0.0)
2727 integer_place = 1 + (int)log10(absolute_value);
2728 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002729 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002730 fraction_place = (integer_place > 0)
2731 ? DBL_DIG - integer_place
2732 : DBL_DIG;
2733 size = snprintf(work, sizeof(work), "%0.*f",
2734 fraction_place, number);
2735 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002736 }
2737
Bjorn Reese70a9da52001-04-21 16:57:29 +00002738 /* Remove fractional trailing zeroes */
2739 ptr = after_fraction;
2740 while (*(--ptr) == '0')
2741 ;
2742 if (*ptr != '.')
2743 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002744 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002745
2746 /* Finally copy result back to caller */
2747 size = strlen(work) + 1;
2748 if (size > buffersize) {
2749 work[buffersize - 1] = 0;
2750 size = buffersize;
2751 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002752 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002753 }
2754 break;
2755 }
2756}
2757
Owen Taylor3473f882001-02-23 17:55:21 +00002758
2759/************************************************************************
2760 * *
2761 * Routines to handle NodeSets *
2762 * *
2763 ************************************************************************/
2764
2765/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002766 * xmlXPathOrderDocElems:
2767 * @doc: an input document
2768 *
2769 * Call this routine to speed up XPath computation on static documents.
2770 * This stamps all the element nodes with the document order
2771 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002772 * field, the value stored is actually - the node number (starting at -1)
2773 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002774 *
William M. Brack08171912003-12-29 02:52:11 +00002775 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002776 * of error.
2777 */
2778long
2779xmlXPathOrderDocElems(xmlDocPtr doc) {
2780 long count = 0;
2781 xmlNodePtr cur;
2782
2783 if (doc == NULL)
2784 return(-1);
2785 cur = doc->children;
2786 while (cur != NULL) {
2787 if (cur->type == XML_ELEMENT_NODE) {
2788 cur->content = (void *) (-(++count));
2789 if (cur->children != NULL) {
2790 cur = cur->children;
2791 continue;
2792 }
2793 }
2794 if (cur->next != NULL) {
2795 cur = cur->next;
2796 continue;
2797 }
2798 do {
2799 cur = cur->parent;
2800 if (cur == NULL)
2801 break;
2802 if (cur == (xmlNodePtr) doc) {
2803 cur = NULL;
2804 break;
2805 }
2806 if (cur->next != NULL) {
2807 cur = cur->next;
2808 break;
2809 }
2810 } while (cur != NULL);
2811 }
2812 return(count);
2813}
2814
2815/**
Owen Taylor3473f882001-02-23 17:55:21 +00002816 * xmlXPathCmpNodes:
2817 * @node1: the first node
2818 * @node2: the second node
2819 *
2820 * Compare two nodes w.r.t document order
2821 *
2822 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002823 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002824 */
2825int
2826xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2827 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002828 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002829 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002830 xmlNodePtr cur, root;
2831
2832 if ((node1 == NULL) || (node2 == NULL))
2833 return(-2);
2834 /*
2835 * a couple of optimizations which will avoid computations in most cases
2836 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002837 if (node1->type == XML_ATTRIBUTE_NODE) {
2838 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002839 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002840 node1 = node1->parent;
2841 }
2842 if (node2->type == XML_ATTRIBUTE_NODE) {
2843 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002844 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002845 node2 = node2->parent;
2846 }
2847 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002848 if (attr1 == attr2) {
2849 /* not required, but we keep attributes in order */
2850 if (attr1 != 0) {
2851 cur = attrNode2->prev;
2852 while (cur != NULL) {
2853 if (cur == attrNode1)
2854 return (1);
2855 cur = cur->prev;
2856 }
2857 return (-1);
2858 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002859 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002860 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002861 if (attr2 == 1)
2862 return(1);
2863 return(-1);
2864 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002865 if ((node1->type == XML_NAMESPACE_DECL) ||
2866 (node2->type == XML_NAMESPACE_DECL))
2867 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002868 if (node1 == node2->prev)
2869 return(1);
2870 if (node1 == node2->next)
2871 return(-1);
2872
2873 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002874 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002875 */
2876 if ((node1->type == XML_ELEMENT_NODE) &&
2877 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002878 (0 > (long) node1->content) &&
2879 (0 > (long) node2->content) &&
2880 (node1->doc == node2->doc)) {
2881 long l1, l2;
2882
2883 l1 = -((long) node1->content);
2884 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002885 if (l1 < l2)
2886 return(1);
2887 if (l1 > l2)
2888 return(-1);
2889 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002890
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002891 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002892 * compute depth to root
2893 */
2894 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2895 if (cur == node1)
2896 return(1);
2897 depth2++;
2898 }
2899 root = cur;
2900 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2901 if (cur == node2)
2902 return(-1);
2903 depth1++;
2904 }
2905 /*
2906 * Distinct document (or distinct entities :-( ) case.
2907 */
2908 if (root != cur) {
2909 return(-2);
2910 }
2911 /*
2912 * get the nearest common ancestor.
2913 */
2914 while (depth1 > depth2) {
2915 depth1--;
2916 node1 = node1->parent;
2917 }
2918 while (depth2 > depth1) {
2919 depth2--;
2920 node2 = node2->parent;
2921 }
2922 while (node1->parent != node2->parent) {
2923 node1 = node1->parent;
2924 node2 = node2->parent;
2925 /* should not happen but just in case ... */
2926 if ((node1 == NULL) || (node2 == NULL))
2927 return(-2);
2928 }
2929 /*
2930 * Find who's first.
2931 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002932 if (node1 == node2->prev)
2933 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002934 if (node1 == node2->next)
2935 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002936 /*
2937 * Speedup using document order if availble.
2938 */
2939 if ((node1->type == XML_ELEMENT_NODE) &&
2940 (node2->type == XML_ELEMENT_NODE) &&
2941 (0 > (long) node1->content) &&
2942 (0 > (long) node2->content) &&
2943 (node1->doc == node2->doc)) {
2944 long l1, l2;
2945
2946 l1 = -((long) node1->content);
2947 l2 = -((long) node2->content);
2948 if (l1 < l2)
2949 return(1);
2950 if (l1 > l2)
2951 return(-1);
2952 }
2953
Owen Taylor3473f882001-02-23 17:55:21 +00002954 for (cur = node1->next;cur != NULL;cur = cur->next)
2955 if (cur == node2)
2956 return(1);
2957 return(-1); /* assume there is no sibling list corruption */
2958}
2959
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002960#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002961/**
2962 * xmlXPathCmpNodesExt:
2963 * @node1: the first node
2964 * @node2: the second node
2965 *
2966 * Compare two nodes w.r.t document order.
2967 * This one is optimized for handling of non-element nodes.
2968 *
2969 * Returns -2 in case of error 1 if first point < second point, 0 if
2970 * it's the same node, -1 otherwise
2971 */
2972static int
2973xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2974 int depth1, depth2;
2975 int misc = 0, precedence1 = 0, precedence2 = 0;
2976 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2977 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002978 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002979
2980 if ((node1 == NULL) || (node2 == NULL))
2981 return(-2);
2982
2983 if (node1 == node2)
2984 return(0);
2985
2986 /*
2987 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002988 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002989 switch (node1->type) {
2990 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002991 if (node2->type == XML_ELEMENT_NODE) {
2992 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2993 (0 > (long) node2->content) &&
2994 (node1->doc == node2->doc))
2995 {
2996 l1 = -((long) node1->content);
2997 l2 = -((long) node2->content);
2998 if (l1 < l2)
2999 return(1);
3000 if (l1 > l2)
3001 return(-1);
3002 } else
3003 goto turtle_comparison;
3004 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003005 break;
3006 case XML_ATTRIBUTE_NODE:
3007 precedence1 = 1; /* element is owner */
3008 miscNode1 = node1;
3009 node1 = node1->parent;
3010 misc = 1;
3011 break;
3012 case XML_TEXT_NODE:
3013 case XML_CDATA_SECTION_NODE:
3014 case XML_COMMENT_NODE:
3015 case XML_PI_NODE: {
3016 miscNode1 = node1;
3017 /*
3018 * Find nearest element node.
3019 */
3020 if (node1->prev != NULL) {
3021 do {
3022 node1 = node1->prev;
3023 if (node1->type == XML_ELEMENT_NODE) {
3024 precedence1 = 3; /* element in prev-sibl axis */
3025 break;
3026 }
3027 if (node1->prev == NULL) {
3028 precedence1 = 2; /* element is parent */
3029 /*
3030 * URGENT TODO: Are there any cases, where the
3031 * parent of such a node is not an element node?
3032 */
3033 node1 = node1->parent;
3034 break;
3035 }
3036 } while (1);
3037 } else {
3038 precedence1 = 2; /* element is parent */
3039 node1 = node1->parent;
3040 }
3041 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3042 /*
3043 * Fallback for whatever case.
3044 */
3045 node1 = miscNode1;
3046 precedence1 = 0;
3047 } else
3048 misc = 1;
3049 }
3050 break;
3051 case XML_NAMESPACE_DECL:
3052 /*
3053 * TODO: why do we return 1 for namespace nodes?
3054 */
3055 return(1);
3056 default:
3057 break;
3058 }
3059 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003060 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003061 break;
3062 case XML_ATTRIBUTE_NODE:
3063 precedence2 = 1; /* element is owner */
3064 miscNode2 = node2;
3065 node2 = node2->parent;
3066 misc = 1;
3067 break;
3068 case XML_TEXT_NODE:
3069 case XML_CDATA_SECTION_NODE:
3070 case XML_COMMENT_NODE:
3071 case XML_PI_NODE: {
3072 miscNode2 = node2;
3073 if (node2->prev != NULL) {
3074 do {
3075 node2 = node2->prev;
3076 if (node2->type == XML_ELEMENT_NODE) {
3077 precedence2 = 3; /* element in prev-sibl axis */
3078 break;
3079 }
3080 if (node2->prev == NULL) {
3081 precedence2 = 2; /* element is parent */
3082 node2 = node2->parent;
3083 break;
3084 }
3085 } while (1);
3086 } else {
3087 precedence2 = 2; /* element is parent */
3088 node2 = node2->parent;
3089 }
3090 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3091 (0 <= (long) node1->content))
3092 {
3093 node2 = miscNode2;
3094 precedence2 = 0;
3095 } else
3096 misc = 1;
3097 }
3098 break;
3099 case XML_NAMESPACE_DECL:
3100 return(1);
3101 default:
3102 break;
3103 }
3104 if (misc) {
3105 if (node1 == node2) {
3106 if (precedence1 == precedence2) {
3107 /*
3108 * The ugly case; but normally there aren't many
3109 * adjacent non-element nodes around.
3110 */
3111 cur = miscNode2->prev;
3112 while (cur != NULL) {
3113 if (cur == miscNode1)
3114 return(1);
3115 if (cur->type == XML_ELEMENT_NODE)
3116 return(-1);
3117 cur = cur->prev;
3118 }
3119 return (-1);
3120 } else {
3121 /*
3122 * Evaluate based on higher precedence wrt to the element.
3123 * TODO: This assumes attributes are sorted before content.
3124 * Is this 100% correct?
3125 */
3126 if (precedence1 < precedence2)
3127 return(1);
3128 else
3129 return(-1);
3130 }
3131 }
3132 /*
3133 * Special case: One of the helper-elements is contained by the other.
3134 * <foo>
3135 * <node2>
3136 * <node1>Text-1(precedence1 == 2)</node1>
3137 * </node2>
3138 * Text-6(precedence2 == 3)
3139 * </foo>
3140 */
3141 if ((precedence2 == 3) && (precedence1 > 1)) {
3142 cur = node1->parent;
3143 while (cur) {
3144 if (cur == node2)
3145 return(1);
3146 cur = cur->parent;
3147 }
3148 }
3149 if ((precedence1 == 3) && (precedence2 > 1)) {
3150 cur = node2->parent;
3151 while (cur) {
3152 if (cur == node1)
3153 return(-1);
3154 cur = cur->parent;
3155 }
3156 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003157 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003158
3159 /*
3160 * Speedup using document order if availble.
3161 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003162 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003163 (node2->type == XML_ELEMENT_NODE) &&
3164 (0 > (long) node1->content) &&
3165 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003166 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003167
3168 l1 = -((long) node1->content);
3169 l2 = -((long) node2->content);
3170 if (l1 < l2)
3171 return(1);
3172 if (l1 > l2)
3173 return(-1);
3174 }
3175
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003176turtle_comparison:
3177
3178 if (node1 == node2->prev)
3179 return(1);
3180 if (node1 == node2->next)
3181 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003182 /*
3183 * compute depth to root
3184 */
3185 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3186 if (cur == node1)
3187 return(1);
3188 depth2++;
3189 }
3190 root = cur;
3191 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3192 if (cur == node2)
3193 return(-1);
3194 depth1++;
3195 }
3196 /*
3197 * Distinct document (or distinct entities :-( ) case.
3198 */
3199 if (root != cur) {
3200 return(-2);
3201 }
3202 /*
3203 * get the nearest common ancestor.
3204 */
3205 while (depth1 > depth2) {
3206 depth1--;
3207 node1 = node1->parent;
3208 }
3209 while (depth2 > depth1) {
3210 depth2--;
3211 node2 = node2->parent;
3212 }
3213 while (node1->parent != node2->parent) {
3214 node1 = node1->parent;
3215 node2 = node2->parent;
3216 /* should not happen but just in case ... */
3217 if ((node1 == NULL) || (node2 == NULL))
3218 return(-2);
3219 }
3220 /*
3221 * Find who's first.
3222 */
3223 if (node1 == node2->prev)
3224 return(1);
3225 if (node1 == node2->next)
3226 return(-1);
3227 /*
3228 * Speedup using document order if availble.
3229 */
3230 if ((node1->type == XML_ELEMENT_NODE) &&
3231 (node2->type == XML_ELEMENT_NODE) &&
3232 (0 > (long) node1->content) &&
3233 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003234 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003235
3236 l1 = -((long) node1->content);
3237 l2 = -((long) node2->content);
3238 if (l1 < l2)
3239 return(1);
3240 if (l1 > l2)
3241 return(-1);
3242 }
3243
3244 for (cur = node1->next;cur != NULL;cur = cur->next)
3245 if (cur == node2)
3246 return(1);
3247 return(-1); /* assume there is no sibling list corruption */
3248}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003249#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003250
Owen Taylor3473f882001-02-23 17:55:21 +00003251/**
3252 * xmlXPathNodeSetSort:
3253 * @set: the node set
3254 *
3255 * Sort the node set in document order
3256 */
3257void
3258xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003259 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003260 xmlNodePtr tmp;
3261
3262 if (set == NULL)
3263 return;
3264
3265 /* Use Shell's sort to sort the node-set */
3266 len = set->nodeNr;
3267 for (incr = len / 2; incr > 0; incr /= 2) {
3268 for (i = incr; i < len; i++) {
3269 j = i - incr;
3270 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003271#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003272 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3273 set->nodeTab[j + incr]) == -1)
3274#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003275 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003276 set->nodeTab[j + incr]) == -1)
3277#endif
3278 {
Owen Taylor3473f882001-02-23 17:55:21 +00003279 tmp = set->nodeTab[j];
3280 set->nodeTab[j] = set->nodeTab[j + incr];
3281 set->nodeTab[j + incr] = tmp;
3282 j -= incr;
3283 } else
3284 break;
3285 }
3286 }
3287 }
3288}
3289
3290#define XML_NODESET_DEFAULT 10
3291/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003292 * xmlXPathNodeSetDupNs:
3293 * @node: the parent node of the namespace XPath node
3294 * @ns: the libxml namespace declaration node.
3295 *
3296 * Namespace node in libxml don't match the XPath semantic. In a node set
3297 * the namespace nodes are duplicated and the next pointer is set to the
3298 * parent node in the XPath semantic.
3299 *
3300 * Returns the newly created object.
3301 */
3302static xmlNodePtr
3303xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3304 xmlNsPtr cur;
3305
3306 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3307 return(NULL);
3308 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3309 return((xmlNodePtr) ns);
3310
3311 /*
3312 * Allocate a new Namespace and fill the fields.
3313 */
3314 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3315 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003316 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003317 return(NULL);
3318 }
3319 memset(cur, 0, sizeof(xmlNs));
3320 cur->type = XML_NAMESPACE_DECL;
3321 if (ns->href != NULL)
3322 cur->href = xmlStrdup(ns->href);
3323 if (ns->prefix != NULL)
3324 cur->prefix = xmlStrdup(ns->prefix);
3325 cur->next = (xmlNsPtr) node;
3326 return((xmlNodePtr) cur);
3327}
3328
3329/**
3330 * xmlXPathNodeSetFreeNs:
3331 * @ns: the XPath namespace node found in a nodeset.
3332 *
William M. Brack08171912003-12-29 02:52:11 +00003333 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003334 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003335 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003336 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003337void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003338xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3339 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3340 return;
3341
3342 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3343 if (ns->href != NULL)
3344 xmlFree((xmlChar *)ns->href);
3345 if (ns->prefix != NULL)
3346 xmlFree((xmlChar *)ns->prefix);
3347 xmlFree(ns);
3348 }
3349}
3350
3351/**
Owen Taylor3473f882001-02-23 17:55:21 +00003352 * xmlXPathNodeSetCreate:
3353 * @val: an initial xmlNodePtr, or NULL
3354 *
3355 * Create a new xmlNodeSetPtr of type double and of value @val
3356 *
3357 * Returns the newly created object.
3358 */
3359xmlNodeSetPtr
3360xmlXPathNodeSetCreate(xmlNodePtr val) {
3361 xmlNodeSetPtr ret;
3362
3363 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3364 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003365 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003366 return(NULL);
3367 }
3368 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3369 if (val != NULL) {
3370 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3371 sizeof(xmlNodePtr));
3372 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003373 xmlXPathErrMemory(NULL, "creating nodeset\n");
3374 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003375 return(NULL);
3376 }
3377 memset(ret->nodeTab, 0 ,
3378 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3379 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003380 if (val->type == XML_NAMESPACE_DECL) {
3381 xmlNsPtr ns = (xmlNsPtr) val;
3382
3383 ret->nodeTab[ret->nodeNr++] =
3384 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3385 } else
3386 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003387 }
3388 return(ret);
3389}
3390
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003391#if 0 /* Not used yet. */
Owen Taylor3473f882001-02-23 17:55:21 +00003392/**
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003393 * xmlXPathNodeSetCreateSize:
3394 * @val: an initial xmlNodePtr, or NULL
3395 * @size: the initial size of the node-sets
3396 *
3397 * Create a new xmlNodeSetPtr of type double and of value @val
3398 *
3399 * Returns the newly created object.
3400 */
3401static xmlNodeSetPtr
3402xmlXPathNodeSetCreateSize(int size)
3403{
3404 xmlNodeSetPtr ret;
3405
3406 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3407 if (ret == NULL) {
3408 xmlXPathErrMemory(NULL, "creating nodeset\n");
3409 return(NULL);
3410 }
3411 memset(ret, 0, (size_t) sizeof(xmlNodeSet));
3412 if (size > 0) {
3413 if (size < XML_NODESET_DEFAULT)
3414 size = XML_NODESET_DEFAULT;
3415 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3416 if (ret->nodeTab == NULL) {
3417 xmlXPathErrMemory(NULL, "creating nodeset\n");
3418 xmlFree(ret);
3419 return(NULL);
3420 }
3421 memset(ret->nodeTab, 0, size * (size_t) sizeof(xmlNodePtr));
3422 ret->nodeMax = size;
3423 }
3424 return(ret);
3425}
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003426#endif
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003427
3428/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003429 * xmlXPathNodeSetContains:
3430 * @cur: the node-set
3431 * @val: the node
3432 *
3433 * checks whether @cur contains @val
3434 *
3435 * Returns true (1) if @cur contains @val, false (0) otherwise
3436 */
3437int
3438xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3439 int i;
3440
Daniel Veillarda82b1822004-11-08 16:24:57 +00003441 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003442 if (val->type == XML_NAMESPACE_DECL) {
3443 for (i = 0; i < cur->nodeNr; i++) {
3444 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3445 xmlNsPtr ns1, ns2;
3446
3447 ns1 = (xmlNsPtr) val;
3448 ns2 = (xmlNsPtr) cur->nodeTab[i];
3449 if (ns1 == ns2)
3450 return(1);
3451 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3452 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3453 return(1);
3454 }
3455 }
3456 } else {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i] == val)
3459 return(1);
3460 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003461 }
3462 return(0);
3463}
3464
3465/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003466 * xmlXPathNodeSetAddNs:
3467 * @cur: the initial node set
3468 * @node: the hosting node
3469 * @ns: a the namespace node
3470 *
3471 * add a new namespace node to an existing NodeSet
3472 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003473void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003474xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3475 int i;
3476
Daniel Veillarda82b1822004-11-08 16:24:57 +00003477
3478 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3479 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003480 (node->type != XML_ELEMENT_NODE))
3481 return;
3482
William M. Brack08171912003-12-29 02:52:11 +00003483 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 /*
William M. Brack08171912003-12-29 02:52:11 +00003485 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 */
3487 for (i = 0;i < cur->nodeNr;i++) {
3488 if ((cur->nodeTab[i] != NULL) &&
3489 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003490 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003491 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3492 return;
3493 }
3494
3495 /*
3496 * grow the nodeTab if needed
3497 */
3498 if (cur->nodeMax == 0) {
3499 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3500 sizeof(xmlNodePtr));
3501 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003502 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003503 return;
3504 }
3505 memset(cur->nodeTab, 0 ,
3506 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3507 cur->nodeMax = XML_NODESET_DEFAULT;
3508 } else if (cur->nodeNr == cur->nodeMax) {
3509 xmlNodePtr *temp;
3510
3511 cur->nodeMax *= 2;
3512 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3513 sizeof(xmlNodePtr));
3514 if (temp == 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 cur->nodeTab = temp;
3519 }
3520 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3521}
3522
3523/**
Owen Taylor3473f882001-02-23 17:55:21 +00003524 * xmlXPathNodeSetAdd:
3525 * @cur: the initial node set
3526 * @val: a new xmlNodePtr
3527 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003528 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003529 */
3530void
3531xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3532 int i;
3533
Daniel Veillarda82b1822004-11-08 16:24:57 +00003534 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003535
Daniel Veillardef0b4502003-03-24 13:57:34 +00003536#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003537 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3538 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003539#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003540
William M. Brack08171912003-12-29 02:52:11 +00003541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003542 /*
William M. Brack08171912003-12-29 02:52:11 +00003543 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003544 */
3545 for (i = 0;i < cur->nodeNr;i++)
3546 if (cur->nodeTab[i] == val) return;
3547
3548 /*
3549 * grow the nodeTab if needed
3550 */
3551 if (cur->nodeMax == 0) {
3552 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553 sizeof(xmlNodePtr));
3554 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003555 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003556 return;
3557 }
3558 memset(cur->nodeTab, 0 ,
3559 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3560 cur->nodeMax = XML_NODESET_DEFAULT;
3561 } else if (cur->nodeNr == cur->nodeMax) {
3562 xmlNodePtr *temp;
3563
3564 cur->nodeMax *= 2;
3565 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3566 sizeof(xmlNodePtr));
3567 if (temp == 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 cur->nodeTab = temp;
3572 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003573 if (val->type == XML_NAMESPACE_DECL) {
3574 xmlNsPtr ns = (xmlNsPtr) val;
3575
3576 cur->nodeTab[cur->nodeNr++] =
3577 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3578 } else
3579 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003580}
3581
3582/**
3583 * xmlXPathNodeSetAddUnique:
3584 * @cur: the initial node set
3585 * @val: a new xmlNodePtr
3586 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003587 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003588 * when we are sure the node is not already in the set.
3589 */
3590void
3591xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003592 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003593
Daniel Veillardef0b4502003-03-24 13:57:34 +00003594#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003597#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003598
William M. Brack08171912003-12-29 02:52:11 +00003599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003600 /*
3601 * grow the nodeTab if needed
3602 */
3603 if (cur->nodeMax == 0) {
3604 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3605 sizeof(xmlNodePtr));
3606 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003607 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003608 return;
3609 }
3610 memset(cur->nodeTab, 0 ,
3611 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3612 cur->nodeMax = XML_NODESET_DEFAULT;
3613 } else if (cur->nodeNr == cur->nodeMax) {
3614 xmlNodePtr *temp;
3615
3616 cur->nodeMax *= 2;
3617 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3618 sizeof(xmlNodePtr));
3619 if (temp == 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 cur->nodeTab = temp;
3624 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003625 if (val->type == XML_NAMESPACE_DECL) {
3626 xmlNsPtr ns = (xmlNsPtr) val;
3627
3628 cur->nodeTab[cur->nodeNr++] =
3629 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3630 } else
3631 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003632}
3633
3634/**
3635 * xmlXPathNodeSetMerge:
3636 * @val1: the first NodeSet or NULL
3637 * @val2: the second NodeSet
3638 *
3639 * Merges two nodesets, all nodes from @val2 are added to @val1
3640 * if @val1 is NULL, a new set is created and copied from @val2
3641 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003642 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003643 */
3644xmlNodeSetPtr
3645xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003646 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003647 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003648
3649 if (val2 == NULL) return(val1);
3650 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003651 val1 = xmlXPathNodeSetCreate(NULL);
3652#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003653 /*
3654 * TODO: The optimization won't work in every case, since
3655 * those nasty namespace nodes need to be added with
3656 * xmlXPathNodeSetDupNs() to the set; thus a pure
3657 * memcpy is not possible.
3658 */
3659 /*
3660 * Optimization: Create an equally sized node-set
3661 * and memcpy the content.
3662 */
3663 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3664 if (val1 == NULL)
3665 return(NULL);
3666 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003667 if (val2->nodeNr == 1)
3668 *(val1->nodeTab) = *(val2->nodeTab);
3669 else {
3670 memcpy(val1->nodeTab, val2->nodeTab,
3671 val2->nodeNr * sizeof(xmlNodePtr));
3672 }
3673 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003674 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003675 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003676#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003677 }
3678
William M. Brack08171912003-12-29 02:52:11 +00003679 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003680 initNr = val1->nodeNr;
3681
3682 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003683 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003684 /*
William M. Brack08171912003-12-29 02:52:11 +00003685 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003686 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003687 skip = 0;
3688 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003689 n1 = val1->nodeTab[j];
3690 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003691 skip = 1;
3692 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003693 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3694 (n2->type == XML_NAMESPACE_DECL)) {
3695 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3696 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3697 ((xmlNsPtr) n2)->prefix)))
3698 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003699 skip = 1;
3700 break;
3701 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003702 }
3703 }
3704 if (skip)
3705 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003706
3707 /*
3708 * grow the nodeTab if needed
3709 */
3710 if (val1->nodeMax == 0) {
3711 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3712 sizeof(xmlNodePtr));
3713 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003714 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003715 return(NULL);
3716 }
3717 memset(val1->nodeTab, 0 ,
3718 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3719 val1->nodeMax = XML_NODESET_DEFAULT;
3720 } else if (val1->nodeNr == val1->nodeMax) {
3721 xmlNodePtr *temp;
3722
3723 val1->nodeMax *= 2;
3724 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3725 sizeof(xmlNodePtr));
3726 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003727 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003728 return(NULL);
3729 }
3730 val1->nodeTab = temp;
3731 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003732 if (n2->type == XML_NAMESPACE_DECL) {
3733 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003734
3735 val1->nodeTab[val1->nodeNr++] =
3736 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3737 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003738 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003739 }
3740
3741 return(val1);
3742}
3743
3744/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003745 * xmlXPathNodeSetMergeUnique:
3746 * @val1: the first NodeSet or NULL
3747 * @val2: the second NodeSet
3748 *
3749 * Merges two nodesets, all nodes from @val2 are added to @val1
3750 * if @val1 is NULL, a new set is created and copied from @val2
3751 *
3752 * Returns @val1 once extended or NULL in case of error.
3753 */
3754static xmlNodeSetPtr
3755xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003756 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003757
3758 if (val2 == NULL) return(val1);
3759 if (val1 == NULL) {
3760 val1 = xmlXPathNodeSetCreate(NULL);
3761 }
3762
William M. Brack08171912003-12-29 02:52:11 +00003763 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003764
3765 for (i = 0;i < val2->nodeNr;i++) {
3766 /*
3767 * grow the nodeTab if needed
3768 */
3769 if (val1->nodeMax == 0) {
3770 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3771 sizeof(xmlNodePtr));
3772 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003773 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003774 return(NULL);
3775 }
3776 memset(val1->nodeTab, 0 ,
3777 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3778 val1->nodeMax = XML_NODESET_DEFAULT;
3779 } else if (val1->nodeNr == val1->nodeMax) {
3780 xmlNodePtr *temp;
3781
3782 val1->nodeMax *= 2;
3783 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3784 sizeof(xmlNodePtr));
3785 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003786 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003787 return(NULL);
3788 }
3789 val1->nodeTab = temp;
3790 }
3791 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3792 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3793
3794 val1->nodeTab[val1->nodeNr++] =
3795 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3796 } else
3797 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3798 }
3799
3800 return(val1);
3801}
3802
3803/**
Owen Taylor3473f882001-02-23 17:55:21 +00003804 * xmlXPathNodeSetDel:
3805 * @cur: the initial node set
3806 * @val: an xmlNodePtr
3807 *
3808 * Removes an xmlNodePtr from an existing NodeSet
3809 */
3810void
3811xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3812 int i;
3813
3814 if (cur == NULL) return;
3815 if (val == NULL) return;
3816
3817 /*
William M. Brack08171912003-12-29 02:52:11 +00003818 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00003819 */
3820 for (i = 0;i < cur->nodeNr;i++)
3821 if (cur->nodeTab[i] == val) break;
3822
William M. Brack08171912003-12-29 02:52:11 +00003823 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00003824#ifdef DEBUG
3825 xmlGenericError(xmlGenericErrorContext,
3826 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
3827 val->name);
3828#endif
3829 return;
3830 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003831 if ((cur->nodeTab[i] != NULL) &&
3832 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3833 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003834 cur->nodeNr--;
3835 for (;i < cur->nodeNr;i++)
3836 cur->nodeTab[i] = cur->nodeTab[i + 1];
3837 cur->nodeTab[cur->nodeNr] = NULL;
3838}
3839
3840/**
3841 * xmlXPathNodeSetRemove:
3842 * @cur: the initial node set
3843 * @val: the index to remove
3844 *
3845 * Removes an entry from an existing NodeSet list.
3846 */
3847void
3848xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3849 if (cur == NULL) return;
3850 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003851 if ((cur->nodeTab[val] != NULL) &&
3852 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3853 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00003854 cur->nodeNr--;
3855 for (;val < cur->nodeNr;val++)
3856 cur->nodeTab[val] = cur->nodeTab[val + 1];
3857 cur->nodeTab[cur->nodeNr] = NULL;
3858}
3859
3860/**
3861 * xmlXPathFreeNodeSet:
3862 * @obj: the xmlNodeSetPtr to free
3863 *
3864 * Free the NodeSet compound (not the actual nodes !).
3865 */
3866void
3867xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3868 if (obj == NULL) return;
3869 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003870 int i;
3871
William M. Brack08171912003-12-29 02:52:11 +00003872 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003873 for (i = 0;i < obj->nodeNr;i++)
3874 if ((obj->nodeTab[i] != NULL) &&
3875 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3876 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003877 xmlFree(obj->nodeTab);
3878 }
Owen Taylor3473f882001-02-23 17:55:21 +00003879 xmlFree(obj);
3880}
3881
3882/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003883 * xmlXPathNodeSetClear:
3884 * @set: the xmlNodeSetPtr to free
3885 *
3886 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3887 * are feed), but does *not* free the list itself. Sets the length of the
3888 * list to 0.
3889 */
3890static void
3891xmlXPathNodeSetClear(xmlNodeSetPtr set)
3892{
3893 int i;
3894 xmlNodePtr node;
3895
3896 if ((set == NULL) || (set->nodeNr <= 0))
3897 return;
3898
3899 for (i = 0; i < set->nodeNr; i++) {
3900 node = set->nodeTab[i];
3901 if ((node != NULL) &&
3902 (node->type == XML_NAMESPACE_DECL))
3903 {
3904 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3905 }
3906 }
3907 set->nodeNr = 0;
3908}
3909
3910/**
Owen Taylor3473f882001-02-23 17:55:21 +00003911 * xmlXPathFreeValueTree:
3912 * @obj: the xmlNodeSetPtr to free
3913 *
3914 * Free the NodeSet compound and the actual tree, this is different
3915 * from xmlXPathFreeNodeSet()
3916 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003917static void
Owen Taylor3473f882001-02-23 17:55:21 +00003918xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3919 int i;
3920
3921 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003922
3923 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003924 for (i = 0;i < obj->nodeNr;i++) {
3925 if (obj->nodeTab[i] != NULL) {
3926 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3927 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3928 } else {
3929 xmlFreeNodeList(obj->nodeTab[i]);
3930 }
3931 }
3932 }
Owen Taylor3473f882001-02-23 17:55:21 +00003933 xmlFree(obj->nodeTab);
3934 }
Owen Taylor3473f882001-02-23 17:55:21 +00003935 xmlFree(obj);
3936}
3937
3938#if defined(DEBUG) || defined(DEBUG_STEP)
3939/**
3940 * xmlGenericErrorContextNodeSet:
3941 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00003942 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00003943 *
3944 * Quick display of a NodeSet
3945 */
3946void
3947xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
3948 int i;
3949
3950 if (output == NULL) output = xmlGenericErrorContext;
3951 if (obj == NULL) {
3952 fprintf(output, "NodeSet == NULL !\n");
3953 return;
3954 }
3955 if (obj->nodeNr == 0) {
3956 fprintf(output, "NodeSet is empty\n");
3957 return;
3958 }
3959 if (obj->nodeTab == NULL) {
3960 fprintf(output, " nodeTab == NULL !\n");
3961 return;
3962 }
3963 for (i = 0; i < obj->nodeNr; i++) {
3964 if (obj->nodeTab[i] == NULL) {
3965 fprintf(output, " NULL !\n");
3966 return;
3967 }
3968 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
3969 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
3970 fprintf(output, " /");
3971 else if (obj->nodeTab[i]->name == NULL)
3972 fprintf(output, " noname!");
3973 else fprintf(output, " %s", obj->nodeTab[i]->name);
3974 }
3975 fprintf(output, "\n");
3976}
3977#endif
3978
3979/**
3980 * xmlXPathNewNodeSet:
3981 * @val: the NodePtr value
3982 *
3983 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3984 * it with the single Node @val
3985 *
3986 * Returns the newly created object.
3987 */
3988xmlXPathObjectPtr
3989xmlXPathNewNodeSet(xmlNodePtr val) {
3990 xmlXPathObjectPtr ret;
3991
3992 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3993 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003994 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003995 return(NULL);
3996 }
3997 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3998 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00003999 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004000 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00004001 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004002#ifdef XP_DEBUG_OBJ_USAGE
4003 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4004#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004005 return(ret);
4006}
4007
4008/**
4009 * xmlXPathNewValueTree:
4010 * @val: the NodePtr value
4011 *
4012 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4013 * it with the tree root @val
4014 *
4015 * Returns the newly created object.
4016 */
4017xmlXPathObjectPtr
4018xmlXPathNewValueTree(xmlNodePtr val) {
4019 xmlXPathObjectPtr ret;
4020
4021 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4022 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004023 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004024 return(NULL);
4025 }
4026 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4027 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004028 ret->boolval = 1;
4029 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004030 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004031#ifdef XP_DEBUG_OBJ_USAGE
4032 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4033#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004034 return(ret);
4035}
4036
4037/**
4038 * xmlXPathNewNodeSetList:
4039 * @val: an existing NodeSet
4040 *
4041 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4042 * it with the Nodeset @val
4043 *
4044 * Returns the newly created object.
4045 */
4046xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004047xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4048{
Owen Taylor3473f882001-02-23 17:55:21 +00004049 xmlXPathObjectPtr ret;
4050 int i;
4051
4052 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004053 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004054 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004055 ret = xmlXPathNewNodeSet(NULL);
4056 else {
4057 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4058 for (i = 1; i < val->nodeNr; ++i)
4059 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4060 }
Owen Taylor3473f882001-02-23 17:55:21 +00004061
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004062 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004063}
4064
4065/**
4066 * xmlXPathWrapNodeSet:
4067 * @val: the NodePtr value
4068 *
4069 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4070 *
4071 * Returns the newly created object.
4072 */
4073xmlXPathObjectPtr
4074xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4075 xmlXPathObjectPtr ret;
4076
4077 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4078 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004079 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004080 return(NULL);
4081 }
4082 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4083 ret->type = XPATH_NODESET;
4084 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004085#ifdef XP_DEBUG_OBJ_USAGE
4086 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4087#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004088 return(ret);
4089}
4090
4091/**
4092 * xmlXPathFreeNodeSetList:
4093 * @obj: an existing NodeSetList object
4094 *
4095 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4096 * the list contrary to xmlXPathFreeObject().
4097 */
4098void
4099xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4100 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004101#ifdef XP_DEBUG_OBJ_USAGE
4102 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4103#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004104 xmlFree(obj);
4105}
4106
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004107/**
4108 * xmlXPathDifference:
4109 * @nodes1: a node-set
4110 * @nodes2: a node-set
4111 *
4112 * Implements the EXSLT - Sets difference() function:
4113 * node-set set:difference (node-set, node-set)
4114 *
4115 * Returns the difference between the two node sets, or nodes1 if
4116 * nodes2 is empty
4117 */
4118xmlNodeSetPtr
4119xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4120 xmlNodeSetPtr ret;
4121 int i, l1;
4122 xmlNodePtr cur;
4123
4124 if (xmlXPathNodeSetIsEmpty(nodes2))
4125 return(nodes1);
4126
4127 ret = xmlXPathNodeSetCreate(NULL);
4128 if (xmlXPathNodeSetIsEmpty(nodes1))
4129 return(ret);
4130
4131 l1 = xmlXPathNodeSetGetLength(nodes1);
4132
4133 for (i = 0; i < l1; i++) {
4134 cur = xmlXPathNodeSetItem(nodes1, i);
4135 if (!xmlXPathNodeSetContains(nodes2, cur))
4136 xmlXPathNodeSetAddUnique(ret, cur);
4137 }
4138 return(ret);
4139}
4140
4141/**
4142 * xmlXPathIntersection:
4143 * @nodes1: a node-set
4144 * @nodes2: a node-set
4145 *
4146 * Implements the EXSLT - Sets intersection() function:
4147 * node-set set:intersection (node-set, node-set)
4148 *
4149 * Returns a node set comprising the nodes that are within both the
4150 * node sets passed as arguments
4151 */
4152xmlNodeSetPtr
4153xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4154 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4155 int i, l1;
4156 xmlNodePtr cur;
4157
4158 if (xmlXPathNodeSetIsEmpty(nodes1))
4159 return(ret);
4160 if (xmlXPathNodeSetIsEmpty(nodes2))
4161 return(ret);
4162
4163 l1 = xmlXPathNodeSetGetLength(nodes1);
4164
4165 for (i = 0; i < l1; i++) {
4166 cur = xmlXPathNodeSetItem(nodes1, i);
4167 if (xmlXPathNodeSetContains(nodes2, cur))
4168 xmlXPathNodeSetAddUnique(ret, cur);
4169 }
4170 return(ret);
4171}
4172
4173/**
4174 * xmlXPathDistinctSorted:
4175 * @nodes: a node-set, sorted by document order
4176 *
4177 * Implements the EXSLT - Sets distinct() function:
4178 * node-set set:distinct (node-set)
4179 *
4180 * Returns a subset of the nodes contained in @nodes, or @nodes if
4181 * it is empty
4182 */
4183xmlNodeSetPtr
4184xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4185 xmlNodeSetPtr ret;
4186 xmlHashTablePtr hash;
4187 int i, l;
4188 xmlChar * strval;
4189 xmlNodePtr cur;
4190
4191 if (xmlXPathNodeSetIsEmpty(nodes))
4192 return(nodes);
4193
4194 ret = xmlXPathNodeSetCreate(NULL);
4195 l = xmlXPathNodeSetGetLength(nodes);
4196 hash = xmlHashCreate (l);
4197 for (i = 0; i < l; i++) {
4198 cur = xmlXPathNodeSetItem(nodes, i);
4199 strval = xmlXPathCastNodeToString(cur);
4200 if (xmlHashLookup(hash, strval) == NULL) {
4201 xmlHashAddEntry(hash, strval, strval);
4202 xmlXPathNodeSetAddUnique(ret, cur);
4203 } else {
4204 xmlFree(strval);
4205 }
4206 }
4207 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4208 return(ret);
4209}
4210
4211/**
4212 * xmlXPathDistinct:
4213 * @nodes: a node-set
4214 *
4215 * Implements the EXSLT - Sets distinct() function:
4216 * node-set set:distinct (node-set)
4217 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4218 * is called with the sorted node-set
4219 *
4220 * Returns a subset of the nodes contained in @nodes, or @nodes if
4221 * it is empty
4222 */
4223xmlNodeSetPtr
4224xmlXPathDistinct (xmlNodeSetPtr nodes) {
4225 if (xmlXPathNodeSetIsEmpty(nodes))
4226 return(nodes);
4227
4228 xmlXPathNodeSetSort(nodes);
4229 return(xmlXPathDistinctSorted(nodes));
4230}
4231
4232/**
4233 * xmlXPathHasSameNodes:
4234 * @nodes1: a node-set
4235 * @nodes2: a node-set
4236 *
4237 * Implements the EXSLT - Sets has-same-nodes function:
4238 * boolean set:has-same-node(node-set, node-set)
4239 *
4240 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4241 * otherwise
4242 */
4243int
4244xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4245 int i, l;
4246 xmlNodePtr cur;
4247
4248 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4249 xmlXPathNodeSetIsEmpty(nodes2))
4250 return(0);
4251
4252 l = xmlXPathNodeSetGetLength(nodes1);
4253 for (i = 0; i < l; i++) {
4254 cur = xmlXPathNodeSetItem(nodes1, i);
4255 if (xmlXPathNodeSetContains(nodes2, cur))
4256 return(1);
4257 }
4258 return(0);
4259}
4260
4261/**
4262 * xmlXPathNodeLeadingSorted:
4263 * @nodes: a node-set, sorted by document order
4264 * @node: a node
4265 *
4266 * Implements the EXSLT - Sets leading() function:
4267 * node-set set:leading (node-set, node-set)
4268 *
4269 * Returns the nodes in @nodes that precede @node in document order,
4270 * @nodes if @node is NULL or an empty node-set if @nodes
4271 * doesn't contain @node
4272 */
4273xmlNodeSetPtr
4274xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4275 int i, l;
4276 xmlNodePtr cur;
4277 xmlNodeSetPtr ret;
4278
4279 if (node == NULL)
4280 return(nodes);
4281
4282 ret = xmlXPathNodeSetCreate(NULL);
4283 if (xmlXPathNodeSetIsEmpty(nodes) ||
4284 (!xmlXPathNodeSetContains(nodes, node)))
4285 return(ret);
4286
4287 l = xmlXPathNodeSetGetLength(nodes);
4288 for (i = 0; i < l; i++) {
4289 cur = xmlXPathNodeSetItem(nodes, i);
4290 if (cur == node)
4291 break;
4292 xmlXPathNodeSetAddUnique(ret, cur);
4293 }
4294 return(ret);
4295}
4296
4297/**
4298 * xmlXPathNodeLeading:
4299 * @nodes: a node-set
4300 * @node: a node
4301 *
4302 * Implements the EXSLT - Sets leading() function:
4303 * node-set set:leading (node-set, node-set)
4304 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4305 * is called.
4306 *
4307 * Returns the nodes in @nodes that precede @node in document order,
4308 * @nodes if @node is NULL or an empty node-set if @nodes
4309 * doesn't contain @node
4310 */
4311xmlNodeSetPtr
4312xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4313 xmlXPathNodeSetSort(nodes);
4314 return(xmlXPathNodeLeadingSorted(nodes, node));
4315}
4316
4317/**
4318 * xmlXPathLeadingSorted:
4319 * @nodes1: a node-set, sorted by document order
4320 * @nodes2: a node-set, sorted by document order
4321 *
4322 * Implements the EXSLT - Sets leading() function:
4323 * node-set set:leading (node-set, node-set)
4324 *
4325 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4326 * in document order, @nodes1 if @nodes2 is NULL or empty or
4327 * an empty node-set if @nodes1 doesn't contain @nodes2
4328 */
4329xmlNodeSetPtr
4330xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4331 if (xmlXPathNodeSetIsEmpty(nodes2))
4332 return(nodes1);
4333 return(xmlXPathNodeLeadingSorted(nodes1,
4334 xmlXPathNodeSetItem(nodes2, 1)));
4335}
4336
4337/**
4338 * xmlXPathLeading:
4339 * @nodes1: a node-set
4340 * @nodes2: a node-set
4341 *
4342 * Implements the EXSLT - Sets leading() function:
4343 * node-set set:leading (node-set, node-set)
4344 * @nodes1 and @nodes2 are sorted by document order, then
4345 * #exslSetsLeadingSorted is called.
4346 *
4347 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4348 * in document order, @nodes1 if @nodes2 is NULL or empty or
4349 * an empty node-set if @nodes1 doesn't contain @nodes2
4350 */
4351xmlNodeSetPtr
4352xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4353 if (xmlXPathNodeSetIsEmpty(nodes2))
4354 return(nodes1);
4355 if (xmlXPathNodeSetIsEmpty(nodes1))
4356 return(xmlXPathNodeSetCreate(NULL));
4357 xmlXPathNodeSetSort(nodes1);
4358 xmlXPathNodeSetSort(nodes2);
4359 return(xmlXPathNodeLeadingSorted(nodes1,
4360 xmlXPathNodeSetItem(nodes2, 1)));
4361}
4362
4363/**
4364 * xmlXPathNodeTrailingSorted:
4365 * @nodes: a node-set, sorted by document order
4366 * @node: a node
4367 *
4368 * Implements the EXSLT - Sets trailing() function:
4369 * node-set set:trailing (node-set, node-set)
4370 *
4371 * Returns the nodes in @nodes that follow @node in document order,
4372 * @nodes if @node is NULL or an empty node-set if @nodes
4373 * doesn't contain @node
4374 */
4375xmlNodeSetPtr
4376xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4377 int i, l;
4378 xmlNodePtr cur;
4379 xmlNodeSetPtr ret;
4380
4381 if (node == NULL)
4382 return(nodes);
4383
4384 ret = xmlXPathNodeSetCreate(NULL);
4385 if (xmlXPathNodeSetIsEmpty(nodes) ||
4386 (!xmlXPathNodeSetContains(nodes, node)))
4387 return(ret);
4388
4389 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004390 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004391 cur = xmlXPathNodeSetItem(nodes, i);
4392 if (cur == node)
4393 break;
4394 xmlXPathNodeSetAddUnique(ret, cur);
4395 }
4396 return(ret);
4397}
4398
4399/**
4400 * xmlXPathNodeTrailing:
4401 * @nodes: a node-set
4402 * @node: a node
4403 *
4404 * Implements the EXSLT - Sets trailing() function:
4405 * node-set set:trailing (node-set, node-set)
4406 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4407 * is called.
4408 *
4409 * Returns the nodes in @nodes that follow @node in document order,
4410 * @nodes if @node is NULL or an empty node-set if @nodes
4411 * doesn't contain @node
4412 */
4413xmlNodeSetPtr
4414xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4415 xmlXPathNodeSetSort(nodes);
4416 return(xmlXPathNodeTrailingSorted(nodes, node));
4417}
4418
4419/**
4420 * xmlXPathTrailingSorted:
4421 * @nodes1: a node-set, sorted by document order
4422 * @nodes2: a node-set, sorted by document order
4423 *
4424 * Implements the EXSLT - Sets trailing() function:
4425 * node-set set:trailing (node-set, node-set)
4426 *
4427 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4428 * in document order, @nodes1 if @nodes2 is NULL or empty or
4429 * an empty node-set if @nodes1 doesn't contain @nodes2
4430 */
4431xmlNodeSetPtr
4432xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433 if (xmlXPathNodeSetIsEmpty(nodes2))
4434 return(nodes1);
4435 return(xmlXPathNodeTrailingSorted(nodes1,
4436 xmlXPathNodeSetItem(nodes2, 0)));
4437}
4438
4439/**
4440 * xmlXPathTrailing:
4441 * @nodes1: a node-set
4442 * @nodes2: a node-set
4443 *
4444 * Implements the EXSLT - Sets trailing() function:
4445 * node-set set:trailing (node-set, node-set)
4446 * @nodes1 and @nodes2 are sorted by document order, then
4447 * #xmlXPathTrailingSorted is called.
4448 *
4449 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4450 * in document order, @nodes1 if @nodes2 is NULL or empty or
4451 * an empty node-set if @nodes1 doesn't contain @nodes2
4452 */
4453xmlNodeSetPtr
4454xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4455 if (xmlXPathNodeSetIsEmpty(nodes2))
4456 return(nodes1);
4457 if (xmlXPathNodeSetIsEmpty(nodes1))
4458 return(xmlXPathNodeSetCreate(NULL));
4459 xmlXPathNodeSetSort(nodes1);
4460 xmlXPathNodeSetSort(nodes2);
4461 return(xmlXPathNodeTrailingSorted(nodes1,
4462 xmlXPathNodeSetItem(nodes2, 0)));
4463}
4464
Owen Taylor3473f882001-02-23 17:55:21 +00004465/************************************************************************
4466 * *
4467 * Routines to handle extra functions *
4468 * *
4469 ************************************************************************/
4470
4471/**
4472 * xmlXPathRegisterFunc:
4473 * @ctxt: the XPath context
4474 * @name: the function name
4475 * @f: the function implementation or NULL
4476 *
4477 * Register a new function. If @f is NULL it unregisters the function
4478 *
4479 * Returns 0 in case of success, -1 in case of error
4480 */
4481int
4482xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4483 xmlXPathFunction f) {
4484 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4485}
4486
4487/**
4488 * xmlXPathRegisterFuncNS:
4489 * @ctxt: the XPath context
4490 * @name: the function name
4491 * @ns_uri: the function namespace URI
4492 * @f: the function implementation or NULL
4493 *
4494 * Register a new function. If @f is NULL it unregisters the function
4495 *
4496 * Returns 0 in case of success, -1 in case of error
4497 */
4498int
4499xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4500 const xmlChar *ns_uri, xmlXPathFunction f) {
4501 if (ctxt == NULL)
4502 return(-1);
4503 if (name == NULL)
4504 return(-1);
4505
4506 if (ctxt->funcHash == NULL)
4507 ctxt->funcHash = xmlHashCreate(0);
4508 if (ctxt->funcHash == NULL)
4509 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004510 if (f == NULL)
4511 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004512 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004513}
4514
4515/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004516 * xmlXPathRegisterFuncLookup:
4517 * @ctxt: the XPath context
4518 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004519 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004520 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004521 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004522 */
4523void
4524xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4525 xmlXPathFuncLookupFunc f,
4526 void *funcCtxt) {
4527 if (ctxt == NULL)
4528 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004529 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004530 ctxt->funcLookupData = funcCtxt;
4531}
4532
4533/**
Owen Taylor3473f882001-02-23 17:55:21 +00004534 * xmlXPathFunctionLookup:
4535 * @ctxt: the XPath context
4536 * @name: the function name
4537 *
4538 * Search in the Function array of the context for the given
4539 * function.
4540 *
4541 * Returns the xmlXPathFunction or NULL if not found
4542 */
4543xmlXPathFunction
4544xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004545 if (ctxt == NULL)
4546 return (NULL);
4547
4548 if (ctxt->funcLookupFunc != NULL) {
4549 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004550 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004551
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004552 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004553 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004554 if (ret != NULL)
4555 return(ret);
4556 }
Owen Taylor3473f882001-02-23 17:55:21 +00004557 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4558}
4559
4560/**
4561 * xmlXPathFunctionLookupNS:
4562 * @ctxt: the XPath context
4563 * @name: the function name
4564 * @ns_uri: the function namespace URI
4565 *
4566 * Search in the Function array of the context for the given
4567 * function.
4568 *
4569 * Returns the xmlXPathFunction or NULL if not found
4570 */
4571xmlXPathFunction
4572xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4573 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004574 xmlXPathFunction ret;
4575
Owen Taylor3473f882001-02-23 17:55:21 +00004576 if (ctxt == NULL)
4577 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004578 if (name == NULL)
4579 return(NULL);
4580
Thomas Broyerba4ad322001-07-26 16:55:21 +00004581 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004582 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004583
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004584 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004585 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004586 if (ret != NULL)
4587 return(ret);
4588 }
4589
4590 if (ctxt->funcHash == NULL)
4591 return(NULL);
4592
William M. Brackad0e67c2004-12-01 14:35:10 +00004593 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4594 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004595}
4596
4597/**
4598 * xmlXPathRegisteredFuncsCleanup:
4599 * @ctxt: the XPath context
4600 *
4601 * Cleanup the XPath context data associated to registered functions
4602 */
4603void
4604xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4605 if (ctxt == NULL)
4606 return;
4607
4608 xmlHashFree(ctxt->funcHash, NULL);
4609 ctxt->funcHash = NULL;
4610}
4611
4612/************************************************************************
4613 * *
William M. Brack08171912003-12-29 02:52:11 +00004614 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004615 * *
4616 ************************************************************************/
4617
4618/**
4619 * xmlXPathRegisterVariable:
4620 * @ctxt: the XPath context
4621 * @name: the variable name
4622 * @value: the variable value or NULL
4623 *
4624 * Register a new variable value. If @value is NULL it unregisters
4625 * the variable
4626 *
4627 * Returns 0 in case of success, -1 in case of error
4628 */
4629int
4630xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4631 xmlXPathObjectPtr value) {
4632 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4633}
4634
4635/**
4636 * xmlXPathRegisterVariableNS:
4637 * @ctxt: the XPath context
4638 * @name: the variable name
4639 * @ns_uri: the variable namespace URI
4640 * @value: the variable value or NULL
4641 *
4642 * Register a new variable value. If @value is NULL it unregisters
4643 * the variable
4644 *
4645 * Returns 0 in case of success, -1 in case of error
4646 */
4647int
4648xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4649 const xmlChar *ns_uri,
4650 xmlXPathObjectPtr value) {
4651 if (ctxt == NULL)
4652 return(-1);
4653 if (name == NULL)
4654 return(-1);
4655
4656 if (ctxt->varHash == NULL)
4657 ctxt->varHash = xmlHashCreate(0);
4658 if (ctxt->varHash == NULL)
4659 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004660 if (value == NULL)
4661 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4662 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004663 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4664 (void *) value,
4665 (xmlHashDeallocator)xmlXPathFreeObject));
4666}
4667
4668/**
4669 * xmlXPathRegisterVariableLookup:
4670 * @ctxt: the XPath context
4671 * @f: the lookup function
4672 * @data: the lookup data
4673 *
4674 * register an external mechanism to do variable lookup
4675 */
4676void
4677xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4678 xmlXPathVariableLookupFunc f, void *data) {
4679 if (ctxt == NULL)
4680 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004681 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004682 ctxt->varLookupData = data;
4683}
4684
4685/**
4686 * xmlXPathVariableLookup:
4687 * @ctxt: the XPath context
4688 * @name: the variable name
4689 *
4690 * Search in the Variable array of the context for the given
4691 * variable value.
4692 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004693 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004694 */
4695xmlXPathObjectPtr
4696xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4697 if (ctxt == NULL)
4698 return(NULL);
4699
4700 if (ctxt->varLookupFunc != NULL) {
4701 xmlXPathObjectPtr ret;
4702
4703 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4704 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004705 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004706 }
4707 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4708}
4709
4710/**
4711 * xmlXPathVariableLookupNS:
4712 * @ctxt: the XPath context
4713 * @name: the variable name
4714 * @ns_uri: the variable namespace URI
4715 *
4716 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004717 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004718 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004719 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004720 */
4721xmlXPathObjectPtr
4722xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4723 const xmlChar *ns_uri) {
4724 if (ctxt == NULL)
4725 return(NULL);
4726
4727 if (ctxt->varLookupFunc != NULL) {
4728 xmlXPathObjectPtr ret;
4729
4730 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4731 (ctxt->varLookupData, name, ns_uri);
4732 if (ret != NULL) return(ret);
4733 }
4734
4735 if (ctxt->varHash == NULL)
4736 return(NULL);
4737 if (name == NULL)
4738 return(NULL);
4739
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004740 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004741 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004742}
4743
4744/**
4745 * xmlXPathRegisteredVariablesCleanup:
4746 * @ctxt: the XPath context
4747 *
4748 * Cleanup the XPath context data associated to registered variables
4749 */
4750void
4751xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4752 if (ctxt == NULL)
4753 return;
4754
Daniel Veillard76d66f42001-05-16 21:05:17 +00004755 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004756 ctxt->varHash = NULL;
4757}
4758
4759/**
4760 * xmlXPathRegisterNs:
4761 * @ctxt: the XPath context
4762 * @prefix: the namespace prefix
4763 * @ns_uri: the namespace name
4764 *
4765 * Register a new namespace. If @ns_uri is NULL it unregisters
4766 * the namespace
4767 *
4768 * Returns 0 in case of success, -1 in case of error
4769 */
4770int
4771xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4772 const xmlChar *ns_uri) {
4773 if (ctxt == NULL)
4774 return(-1);
4775 if (prefix == NULL)
4776 return(-1);
4777
4778 if (ctxt->nsHash == NULL)
4779 ctxt->nsHash = xmlHashCreate(10);
4780 if (ctxt->nsHash == NULL)
4781 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004782 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004783 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004784 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004785 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004786 (xmlHashDeallocator)xmlFree));
4787}
4788
4789/**
4790 * xmlXPathNsLookup:
4791 * @ctxt: the XPath context
4792 * @prefix: the namespace prefix value
4793 *
4794 * Search in the namespace declaration array of the context for the given
4795 * namespace name associated to the given prefix
4796 *
4797 * Returns the value or NULL if not found
4798 */
4799const xmlChar *
4800xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4801 if (ctxt == NULL)
4802 return(NULL);
4803 if (prefix == NULL)
4804 return(NULL);
4805
4806#ifdef XML_XML_NAMESPACE
4807 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4808 return(XML_XML_NAMESPACE);
4809#endif
4810
Daniel Veillardc8f620b2001-04-30 20:31:33 +00004811 if (ctxt->namespaces != NULL) {
4812 int i;
4813
4814 for (i = 0;i < ctxt->nsNr;i++) {
4815 if ((ctxt->namespaces[i] != NULL) &&
4816 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4817 return(ctxt->namespaces[i]->href);
4818 }
4819 }
Owen Taylor3473f882001-02-23 17:55:21 +00004820
4821 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4822}
4823
4824/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004825 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00004826 * @ctxt: the XPath context
4827 *
4828 * Cleanup the XPath context data associated to registered variables
4829 */
4830void
4831xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4832 if (ctxt == NULL)
4833 return;
4834
Daniel Veillard42766c02002-08-22 20:52:17 +00004835 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00004836 ctxt->nsHash = NULL;
4837}
4838
4839/************************************************************************
4840 * *
4841 * Routines to handle Values *
4842 * *
4843 ************************************************************************/
4844
William M. Brack08171912003-12-29 02:52:11 +00004845/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00004846
4847/**
4848 * xmlXPathNewFloat:
4849 * @val: the double value
4850 *
4851 * Create a new xmlXPathObjectPtr of type double and of value @val
4852 *
4853 * Returns the newly created object.
4854 */
4855xmlXPathObjectPtr
4856xmlXPathNewFloat(double val) {
4857 xmlXPathObjectPtr ret;
4858
4859 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4860 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004861 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004862 return(NULL);
4863 }
4864 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4865 ret->type = XPATH_NUMBER;
4866 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004867#ifdef XP_DEBUG_OBJ_USAGE
4868 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
4869#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004870 return(ret);
4871}
4872
4873/**
4874 * xmlXPathNewBoolean:
4875 * @val: the boolean value
4876 *
4877 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4878 *
4879 * Returns the newly created object.
4880 */
4881xmlXPathObjectPtr
4882xmlXPathNewBoolean(int val) {
4883 xmlXPathObjectPtr ret;
4884
4885 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4886 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004887 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004888 return(NULL);
4889 }
4890 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4891 ret->type = XPATH_BOOLEAN;
4892 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004893#ifdef XP_DEBUG_OBJ_USAGE
4894 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
4895#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004896 return(ret);
4897}
4898
4899/**
4900 * xmlXPathNewString:
4901 * @val: the xmlChar * value
4902 *
4903 * Create a new xmlXPathObjectPtr of type string and of value @val
4904 *
4905 * Returns the newly created object.
4906 */
4907xmlXPathObjectPtr
4908xmlXPathNewString(const xmlChar *val) {
4909 xmlXPathObjectPtr ret;
4910
4911 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4912 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004913 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004914 return(NULL);
4915 }
4916 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4917 ret->type = XPATH_STRING;
4918 if (val != NULL)
4919 ret->stringval = xmlStrdup(val);
4920 else
4921 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004922#ifdef XP_DEBUG_OBJ_USAGE
4923 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4924#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004925 return(ret);
4926}
4927
4928/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004929 * xmlXPathWrapString:
4930 * @val: the xmlChar * value
4931 *
4932 * Wraps the @val string into an XPath object.
4933 *
4934 * Returns the newly created object.
4935 */
4936xmlXPathObjectPtr
4937xmlXPathWrapString (xmlChar *val) {
4938 xmlXPathObjectPtr ret;
4939
4940 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4941 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004942 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004943 return(NULL);
4944 }
4945 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4946 ret->type = XPATH_STRING;
4947 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004948#ifdef XP_DEBUG_OBJ_USAGE
4949 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4950#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004951 return(ret);
4952}
4953
4954/**
Owen Taylor3473f882001-02-23 17:55:21 +00004955 * xmlXPathNewCString:
4956 * @val: the char * value
4957 *
4958 * Create a new xmlXPathObjectPtr of type string and of value @val
4959 *
4960 * Returns the newly created object.
4961 */
4962xmlXPathObjectPtr
4963xmlXPathNewCString(const char *val) {
4964 xmlXPathObjectPtr ret;
4965
4966 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4967 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004968 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004969 return(NULL);
4970 }
4971 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4972 ret->type = XPATH_STRING;
4973 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004974#ifdef XP_DEBUG_OBJ_USAGE
4975 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4976#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004977 return(ret);
4978}
4979
4980/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004981 * xmlXPathWrapCString:
4982 * @val: the char * value
4983 *
4984 * Wraps a string into an XPath object.
4985 *
4986 * Returns the newly created object.
4987 */
4988xmlXPathObjectPtr
4989xmlXPathWrapCString (char * val) {
4990 return(xmlXPathWrapString((xmlChar *)(val)));
4991}
4992
4993/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004994 * xmlXPathWrapExternal:
4995 * @val: the user data
4996 *
4997 * Wraps the @val data into an XPath object.
4998 *
4999 * Returns the newly created object.
5000 */
5001xmlXPathObjectPtr
5002xmlXPathWrapExternal (void *val) {
5003 xmlXPathObjectPtr ret;
5004
5005 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5006 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005007 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005008 return(NULL);
5009 }
5010 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5011 ret->type = XPATH_USERS;
5012 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005013#ifdef XP_DEBUG_OBJ_USAGE
5014 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5015#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005016 return(ret);
5017}
5018
5019/**
Owen Taylor3473f882001-02-23 17:55:21 +00005020 * xmlXPathObjectCopy:
5021 * @val: the original object
5022 *
5023 * allocate a new copy of a given object
5024 *
5025 * Returns the newly created object.
5026 */
5027xmlXPathObjectPtr
5028xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5029 xmlXPathObjectPtr ret;
5030
5031 if (val == NULL)
5032 return(NULL);
5033
5034 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5035 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005036 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005037 return(NULL);
5038 }
5039 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005040#ifdef XP_DEBUG_OBJ_USAGE
5041 xmlXPathDebugObjUsageRequested(NULL, val->type);
5042#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005043 switch (val->type) {
5044 case XPATH_BOOLEAN:
5045 case XPATH_NUMBER:
5046 case XPATH_POINT:
5047 case XPATH_RANGE:
5048 break;
5049 case XPATH_STRING:
5050 ret->stringval = xmlStrdup(val->stringval);
5051 break;
5052 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005053#if 0
5054/*
5055 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5056 this previous handling is no longer correct, and can cause some serious
5057 problems (ref. bug 145547)
5058*/
Owen Taylor3473f882001-02-23 17:55:21 +00005059 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005060 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005061 xmlNodePtr cur, tmp;
5062 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005063
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005064 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005065 top = xmlNewDoc(NULL);
5066 top->name = (char *)
5067 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005068 ret->user = top;
5069 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005070 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005071 cur = val->nodesetval->nodeTab[0]->children;
5072 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005073 tmp = xmlDocCopyNode(cur, top, 1);
5074 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005075 cur = cur->next;
5076 }
5077 }
William M. Bracke9449c52004-07-11 14:41:20 +00005078
Daniel Veillard9adc0462003-03-24 18:39:54 +00005079 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005080 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005081 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005082 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005083 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005084#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005085 case XPATH_NODESET:
5086 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005087 /* Do not deallocate the copied tree value */
5088 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005089 break;
5090 case XPATH_LOCATIONSET:
5091#ifdef LIBXML_XPTR_ENABLED
5092 {
5093 xmlLocationSetPtr loc = val->user;
5094 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5095 break;
5096 }
5097#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005098 case XPATH_USERS:
5099 ret->user = val->user;
5100 break;
5101 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005102 xmlGenericError(xmlGenericErrorContext,
5103 "xmlXPathObjectCopy: unsupported type %d\n",
5104 val->type);
5105 break;
5106 }
5107 return(ret);
5108}
5109
5110/**
5111 * xmlXPathFreeObject:
5112 * @obj: the object to free
5113 *
5114 * Free up an xmlXPathObjectPtr object.
5115 */
5116void
5117xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5118 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005119 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005120 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005121#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005122 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005123 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005124 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005125 } else
5126#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005127 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005128 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005129 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005130 } else {
5131 if (obj->nodesetval != NULL)
5132 xmlXPathFreeNodeSet(obj->nodesetval);
5133 }
Owen Taylor3473f882001-02-23 17:55:21 +00005134#ifdef LIBXML_XPTR_ENABLED
5135 } else if (obj->type == XPATH_LOCATIONSET) {
5136 if (obj->user != NULL)
5137 xmlXPtrFreeLocationSet(obj->user);
5138#endif
5139 } else if (obj->type == XPATH_STRING) {
5140 if (obj->stringval != NULL)
5141 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005142 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005143#ifdef XP_DEBUG_OBJ_USAGE
5144 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5145#endif
5146 xmlFree(obj);
5147}
Owen Taylor3473f882001-02-23 17:55:21 +00005148
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005149/**
5150 * xmlXPathReleaseObject:
5151 * @obj: the xmlXPathObjectPtr to free or to cache
5152 *
5153 * Depending on the state of the cache this frees the given
5154 * XPath object or stores it in the cache.
5155 */
5156static void
5157xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5158{
5159#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5160 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5161 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5162
5163#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5164
5165 if (obj == NULL)
5166 return;
5167 if ((ctxt == NULL) || (ctxt->objCache == NULL)) {
5168 xmlXPathFreeObject(obj);
5169 } else {
5170 xmlXPathObjectCachePtr cache =
5171 (xmlXPathObjectCachePtr) ctxt->objCache;
5172
5173 switch (obj->type) {
5174 case XPATH_NODESET:
5175 case XPATH_XSLT_TREE:
5176 if (obj->nodesetval != NULL) {
5177 if (obj->boolval) {
5178 /*
5179 * It looks like the @boolval is used for
5180 * evaluation if this an XSLT Result Tree Fragment.
5181 * TODO: Check if this assumption is correct.
5182 */
5183 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5184 xmlXPathFreeValueTree(obj->nodesetval);
5185 obj->nodesetval = NULL;
5186 } else if ((obj->nodesetval->nodeMax <= 40) &&
5187 (XP_CACHE_WANTS(cache->nodesetObjs,
5188 cache->maxNodeset)))
5189 {
5190 XP_CACHE_ADD(cache->nodesetObjs, obj);
5191 goto obj_cached;
5192 } else {
5193 xmlXPathFreeNodeSet(obj->nodesetval);
5194 obj->nodesetval = NULL;
5195 }
5196 }
5197 break;
5198 case XPATH_STRING:
5199 if (obj->stringval != NULL)
5200 xmlFree(obj->stringval);
5201
5202 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5203 XP_CACHE_ADD(cache->stringObjs, obj);
5204 goto obj_cached;
5205 }
5206 break;
5207 case XPATH_BOOLEAN:
5208 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5209 XP_CACHE_ADD(cache->booleanObjs, obj);
5210 goto obj_cached;
5211 }
5212 break;
5213 case XPATH_NUMBER:
5214 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5215 XP_CACHE_ADD(cache->numberObjs, obj);
5216 goto obj_cached;
5217 }
5218 break;
5219#ifdef LIBXML_XPTR_ENABLED
5220 case XPATH_LOCATIONSET:
5221 if (obj->user != NULL) {
5222 xmlXPtrFreeLocationSet(obj->user);
5223 }
5224 goto free_obj;
5225#endif
5226 default:
5227 goto free_obj;
5228 }
5229
5230 /*
5231 * Fallback to adding to the misc-objects slot.
5232 */
5233 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5234 XP_CACHE_ADD(cache->miscObjs, obj);
5235 } else
5236 goto free_obj;
5237
5238obj_cached:
5239
5240#ifdef XP_DEBUG_OBJ_USAGE
5241 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5242#endif
5243
5244 if (obj->nodesetval != NULL) {
5245 xmlNodeSetPtr tmpset = obj->nodesetval;
5246
5247 /*
5248 * TODO: Due to those nasty ns-nodes, we need to traverse
5249 * the list and free the ns-nodes.
5250 * URGENT TODO: Check if it's actually slowing things down.
5251 * Maybe we shouldn't try to preserve the list.
5252 */
5253 if (tmpset->nodeNr > 1) {
5254 int i;
5255 xmlNodePtr node;
5256
5257 for (i = 0; i < tmpset->nodeNr; i++) {
5258 node = tmpset->nodeTab[i];
5259 if ((node != NULL) &&
5260 (node->type == XML_NAMESPACE_DECL))
5261 {
5262 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5263 }
5264 }
5265 } else if (tmpset->nodeNr == 1) {
5266 if ((tmpset->nodeTab[0] != NULL) &&
5267 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5268 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5269 }
5270 tmpset->nodeNr = 0;
5271 memset(obj, 0, sizeof(xmlXPathObject));
5272 obj->nodesetval = tmpset;
5273 } else
5274 memset(obj, 0, sizeof(xmlXPathObject));
5275
5276 return;
5277
5278free_obj:
5279 /*
5280 * Cache is full; free the object.
5281 */
5282 if (obj->nodesetval != NULL)
5283 xmlXPathFreeNodeSet(obj->nodesetval);
5284#ifdef XP_DEBUG_OBJ_USAGE
5285 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5286#endif
5287 xmlFree(obj);
5288 }
5289 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005290}
5291
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005292
5293/************************************************************************
5294 * *
5295 * Type Casting Routines *
5296 * *
5297 ************************************************************************/
5298
5299/**
5300 * xmlXPathCastBooleanToString:
5301 * @val: a boolean
5302 *
5303 * Converts a boolean to its string value.
5304 *
5305 * Returns a newly allocated string.
5306 */
5307xmlChar *
5308xmlXPathCastBooleanToString (int val) {
5309 xmlChar *ret;
5310 if (val)
5311 ret = xmlStrdup((const xmlChar *) "true");
5312 else
5313 ret = xmlStrdup((const xmlChar *) "false");
5314 return(ret);
5315}
5316
5317/**
5318 * xmlXPathCastNumberToString:
5319 * @val: a number
5320 *
5321 * Converts a number to its string value.
5322 *
5323 * Returns a newly allocated string.
5324 */
5325xmlChar *
5326xmlXPathCastNumberToString (double val) {
5327 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005328 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005329 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005330 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005331 break;
5332 case -1:
5333 ret = xmlStrdup((const xmlChar *) "-Infinity");
5334 break;
5335 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005336 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005337 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005338 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5339 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005340 } else {
5341 /* could be improved */
5342 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005343 xmlXPathFormatNumber(val, buf, 99);
5344 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005345 ret = xmlStrdup((const xmlChar *) buf);
5346 }
5347 }
5348 return(ret);
5349}
5350
5351/**
5352 * xmlXPathCastNodeToString:
5353 * @node: a node
5354 *
5355 * Converts a node to its string value.
5356 *
5357 * Returns a newly allocated string.
5358 */
5359xmlChar *
5360xmlXPathCastNodeToString (xmlNodePtr node) {
5361 return(xmlNodeGetContent(node));
5362}
5363
5364/**
5365 * xmlXPathCastNodeSetToString:
5366 * @ns: a node-set
5367 *
5368 * Converts a node-set to its string value.
5369 *
5370 * Returns a newly allocated string.
5371 */
5372xmlChar *
5373xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5374 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5375 return(xmlStrdup((const xmlChar *) ""));
5376
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005377 if (ns->nodeNr > 1)
5378 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005379 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5380}
5381
5382/**
5383 * xmlXPathCastToString:
5384 * @val: an XPath object
5385 *
5386 * Converts an existing object to its string() equivalent
5387 *
5388 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005389 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005390 * string object).
5391 */
5392xmlChar *
5393xmlXPathCastToString(xmlXPathObjectPtr val) {
5394 xmlChar *ret = NULL;
5395
5396 if (val == NULL)
5397 return(xmlStrdup((const xmlChar *) ""));
5398 switch (val->type) {
5399 case XPATH_UNDEFINED:
5400#ifdef DEBUG_EXPR
5401 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5402#endif
5403 ret = xmlStrdup((const xmlChar *) "");
5404 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005405 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005406 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005407 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5408 break;
5409 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005410 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005411 case XPATH_BOOLEAN:
5412 ret = xmlXPathCastBooleanToString(val->boolval);
5413 break;
5414 case XPATH_NUMBER: {
5415 ret = xmlXPathCastNumberToString(val->floatval);
5416 break;
5417 }
5418 case XPATH_USERS:
5419 case XPATH_POINT:
5420 case XPATH_RANGE:
5421 case XPATH_LOCATIONSET:
5422 TODO
5423 ret = xmlStrdup((const xmlChar *) "");
5424 break;
5425 }
5426 return(ret);
5427}
5428
5429/**
5430 * xmlXPathConvertString:
5431 * @val: an XPath object
5432 *
5433 * Converts an existing object to its string() equivalent
5434 *
5435 * Returns the new object, the old one is freed (or the operation
5436 * is done directly on @val)
5437 */
5438xmlXPathObjectPtr
5439xmlXPathConvertString(xmlXPathObjectPtr val) {
5440 xmlChar *res = NULL;
5441
5442 if (val == NULL)
5443 return(xmlXPathNewCString(""));
5444
5445 switch (val->type) {
5446 case XPATH_UNDEFINED:
5447#ifdef DEBUG_EXPR
5448 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5449#endif
5450 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005451 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005452 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005453 res = xmlXPathCastNodeSetToString(val->nodesetval);
5454 break;
5455 case XPATH_STRING:
5456 return(val);
5457 case XPATH_BOOLEAN:
5458 res = xmlXPathCastBooleanToString(val->boolval);
5459 break;
5460 case XPATH_NUMBER:
5461 res = xmlXPathCastNumberToString(val->floatval);
5462 break;
5463 case XPATH_USERS:
5464 case XPATH_POINT:
5465 case XPATH_RANGE:
5466 case XPATH_LOCATIONSET:
5467 TODO;
5468 break;
5469 }
5470 xmlXPathFreeObject(val);
5471 if (res == NULL)
5472 return(xmlXPathNewCString(""));
5473 return(xmlXPathWrapString(res));
5474}
5475
5476/**
5477 * xmlXPathCastBooleanToNumber:
5478 * @val: a boolean
5479 *
5480 * Converts a boolean to its number value
5481 *
5482 * Returns the number value
5483 */
5484double
5485xmlXPathCastBooleanToNumber(int val) {
5486 if (val)
5487 return(1.0);
5488 return(0.0);
5489}
5490
5491/**
5492 * xmlXPathCastStringToNumber:
5493 * @val: a string
5494 *
5495 * Converts a string to its number value
5496 *
5497 * Returns the number value
5498 */
5499double
5500xmlXPathCastStringToNumber(const xmlChar * val) {
5501 return(xmlXPathStringEvalNumber(val));
5502}
5503
5504/**
5505 * xmlXPathCastNodeToNumber:
5506 * @node: a node
5507 *
5508 * Converts a node to its number value
5509 *
5510 * Returns the number value
5511 */
5512double
5513xmlXPathCastNodeToNumber (xmlNodePtr node) {
5514 xmlChar *strval;
5515 double ret;
5516
5517 if (node == NULL)
5518 return(xmlXPathNAN);
5519 strval = xmlXPathCastNodeToString(node);
5520 if (strval == NULL)
5521 return(xmlXPathNAN);
5522 ret = xmlXPathCastStringToNumber(strval);
5523 xmlFree(strval);
5524
5525 return(ret);
5526}
5527
5528/**
5529 * xmlXPathCastNodeSetToNumber:
5530 * @ns: a node-set
5531 *
5532 * Converts a node-set to its number value
5533 *
5534 * Returns the number value
5535 */
5536double
5537xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5538 xmlChar *str;
5539 double ret;
5540
5541 if (ns == NULL)
5542 return(xmlXPathNAN);
5543 str = xmlXPathCastNodeSetToString(ns);
5544 ret = xmlXPathCastStringToNumber(str);
5545 xmlFree(str);
5546 return(ret);
5547}
5548
5549/**
5550 * xmlXPathCastToNumber:
5551 * @val: an XPath object
5552 *
5553 * Converts an XPath object to its number value
5554 *
5555 * Returns the number value
5556 */
5557double
5558xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5559 double ret = 0.0;
5560
5561 if (val == NULL)
5562 return(xmlXPathNAN);
5563 switch (val->type) {
5564 case XPATH_UNDEFINED:
5565#ifdef DEGUB_EXPR
5566 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5567#endif
5568 ret = xmlXPathNAN;
5569 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005570 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005571 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005572 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5573 break;
5574 case XPATH_STRING:
5575 ret = xmlXPathCastStringToNumber(val->stringval);
5576 break;
5577 case XPATH_NUMBER:
5578 ret = val->floatval;
5579 break;
5580 case XPATH_BOOLEAN:
5581 ret = xmlXPathCastBooleanToNumber(val->boolval);
5582 break;
5583 case XPATH_USERS:
5584 case XPATH_POINT:
5585 case XPATH_RANGE:
5586 case XPATH_LOCATIONSET:
5587 TODO;
5588 ret = xmlXPathNAN;
5589 break;
5590 }
5591 return(ret);
5592}
5593
5594/**
5595 * xmlXPathConvertNumber:
5596 * @val: an XPath object
5597 *
5598 * Converts an existing object to its number() equivalent
5599 *
5600 * Returns the new object, the old one is freed (or the operation
5601 * is done directly on @val)
5602 */
5603xmlXPathObjectPtr
5604xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5605 xmlXPathObjectPtr ret;
5606
5607 if (val == NULL)
5608 return(xmlXPathNewFloat(0.0));
5609 if (val->type == XPATH_NUMBER)
5610 return(val);
5611 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5612 xmlXPathFreeObject(val);
5613 return(ret);
5614}
5615
5616/**
5617 * xmlXPathCastNumberToBoolean:
5618 * @val: a number
5619 *
5620 * Converts a number to its boolean value
5621 *
5622 * Returns the boolean value
5623 */
5624int
5625xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005626 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005627 return(0);
5628 return(1);
5629}
5630
5631/**
5632 * xmlXPathCastStringToBoolean:
5633 * @val: a string
5634 *
5635 * Converts a string to its boolean value
5636 *
5637 * Returns the boolean value
5638 */
5639int
5640xmlXPathCastStringToBoolean (const xmlChar *val) {
5641 if ((val == NULL) || (xmlStrlen(val) == 0))
5642 return(0);
5643 return(1);
5644}
5645
5646/**
5647 * xmlXPathCastNodeSetToBoolean:
5648 * @ns: a node-set
5649 *
5650 * Converts a node-set to its boolean value
5651 *
5652 * Returns the boolean value
5653 */
5654int
5655xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5656 if ((ns == NULL) || (ns->nodeNr == 0))
5657 return(0);
5658 return(1);
5659}
5660
5661/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005662 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005663 * @val: an XPath object
5664 *
5665 * Converts an XPath object to its boolean value
5666 *
5667 * Returns the boolean value
5668 */
5669int
5670xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5671 int ret = 0;
5672
5673 if (val == NULL)
5674 return(0);
5675 switch (val->type) {
5676 case XPATH_UNDEFINED:
5677#ifdef DEBUG_EXPR
5678 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5679#endif
5680 ret = 0;
5681 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005682 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005683 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005684 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5685 break;
5686 case XPATH_STRING:
5687 ret = xmlXPathCastStringToBoolean(val->stringval);
5688 break;
5689 case XPATH_NUMBER:
5690 ret = xmlXPathCastNumberToBoolean(val->floatval);
5691 break;
5692 case XPATH_BOOLEAN:
5693 ret = val->boolval;
5694 break;
5695 case XPATH_USERS:
5696 case XPATH_POINT:
5697 case XPATH_RANGE:
5698 case XPATH_LOCATIONSET:
5699 TODO;
5700 ret = 0;
5701 break;
5702 }
5703 return(ret);
5704}
5705
5706
5707/**
5708 * xmlXPathConvertBoolean:
5709 * @val: an XPath object
5710 *
5711 * Converts an existing object to its boolean() equivalent
5712 *
5713 * Returns the new object, the old one is freed (or the operation
5714 * is done directly on @val)
5715 */
5716xmlXPathObjectPtr
5717xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5718 xmlXPathObjectPtr ret;
5719
5720 if (val == NULL)
5721 return(xmlXPathNewBoolean(0));
5722 if (val->type == XPATH_BOOLEAN)
5723 return(val);
5724 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5725 xmlXPathFreeObject(val);
5726 return(ret);
5727}
5728
Owen Taylor3473f882001-02-23 17:55:21 +00005729/************************************************************************
5730 * *
5731 * Routines to handle XPath contexts *
5732 * *
5733 ************************************************************************/
5734
5735/**
5736 * xmlXPathNewContext:
5737 * @doc: the XML document
5738 *
5739 * Create a new xmlXPathContext
5740 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005741 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005742 */
5743xmlXPathContextPtr
5744xmlXPathNewContext(xmlDocPtr doc) {
5745 xmlXPathContextPtr ret;
5746
5747 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5748 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005749 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005750 return(NULL);
5751 }
5752 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5753 ret->doc = doc;
5754 ret->node = NULL;
5755
5756 ret->varHash = NULL;
5757
5758 ret->nb_types = 0;
5759 ret->max_types = 0;
5760 ret->types = NULL;
5761
5762 ret->funcHash = xmlHashCreate(0);
5763
5764 ret->nb_axis = 0;
5765 ret->max_axis = 0;
5766 ret->axis = NULL;
5767
5768 ret->nsHash = NULL;
5769 ret->user = NULL;
5770
5771 ret->contextSize = -1;
5772 ret->proximityPosition = -1;
5773
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005774#ifdef XP_DEFAULT_CACHE_ON
5775 if (xmlXPathContextSetObjectCache(ret, 1, -1, 0) == -1) {
5776 xmlXPathFreeContext(ret);
5777 return(NULL);
5778 }
5779#endif
5780
5781 xmlXPathRegisterAllFunctions(ret);
5782
Owen Taylor3473f882001-02-23 17:55:21 +00005783 return(ret);
5784}
5785
5786/**
5787 * xmlXPathFreeContext:
5788 * @ctxt: the context to free
5789 *
5790 * Free up an xmlXPathContext
5791 */
5792void
5793xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005794 if (ctxt == NULL) return;
5795
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005796 if (ctxt->objCache != NULL)
5797 xmlXPathFreeObjectCache((xmlXPathObjectCachePtr) ctxt->objCache);
Owen Taylor3473f882001-02-23 17:55:21 +00005798 xmlXPathRegisteredNsCleanup(ctxt);
5799 xmlXPathRegisteredFuncsCleanup(ctxt);
5800 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005801 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00005802 xmlFree(ctxt);
5803}
5804
5805/************************************************************************
5806 * *
5807 * Routines to handle XPath parser contexts *
5808 * *
5809 ************************************************************************/
5810
5811#define CHECK_CTXT(ctxt) \
5812 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00005813 __xmlRaiseError(NULL, NULL, NULL, \
5814 NULL, NULL, XML_FROM_XPATH, \
5815 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5816 __FILE__, __LINE__, \
5817 NULL, NULL, NULL, 0, 0, \
5818 "NULL context pointer\n"); \
5819 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00005820 } \
5821
5822
5823#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00005824 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
5825 (ctxt->doc->children == NULL)) { \
5826 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00005827 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00005828 }
Owen Taylor3473f882001-02-23 17:55:21 +00005829
5830
5831/**
5832 * xmlXPathNewParserContext:
5833 * @str: the XPath expression
5834 * @ctxt: the XPath context
5835 *
5836 * Create a new xmlXPathParserContext
5837 *
5838 * Returns the xmlXPathParserContext just allocated.
5839 */
5840xmlXPathParserContextPtr
5841xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5842 xmlXPathParserContextPtr ret;
5843
5844 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5845 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005846 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005847 return(NULL);
5848 }
5849 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5850 ret->cur = ret->base = str;
5851 ret->context = ctxt;
5852
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005853 ret->comp = xmlXPathNewCompExpr();
5854 if (ret->comp == NULL) {
5855 xmlFree(ret->valueTab);
5856 xmlFree(ret);
5857 return(NULL);
5858 }
Daniel Veillard4773df22004-01-23 13:15:13 +00005859 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5860 ret->comp->dict = ctxt->dict;
5861 xmlDictReference(ret->comp->dict);
5862 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005863
5864 return(ret);
5865}
5866
5867/**
5868 * xmlXPathCompParserContext:
5869 * @comp: the XPath compiled expression
5870 * @ctxt: the XPath context
5871 *
5872 * Create a new xmlXPathParserContext when processing a compiled expression
5873 *
5874 * Returns the xmlXPathParserContext just allocated.
5875 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005876static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005877xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5878 xmlXPathParserContextPtr ret;
5879
5880 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5881 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005882 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005883 return(NULL);
5884 }
5885 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5886
Owen Taylor3473f882001-02-23 17:55:21 +00005887 /* Allocate the value stack */
5888 ret->valueTab = (xmlXPathObjectPtr *)
5889 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005890 if (ret->valueTab == NULL) {
5891 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005892 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005893 return(NULL);
5894 }
Owen Taylor3473f882001-02-23 17:55:21 +00005895 ret->valueNr = 0;
5896 ret->valueMax = 10;
5897 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005898
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005899 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005900 ret->comp = comp;
5901
Owen Taylor3473f882001-02-23 17:55:21 +00005902 return(ret);
5903}
5904
5905/**
5906 * xmlXPathFreeParserContext:
5907 * @ctxt: the context to free
5908 *
5909 * Free up an xmlXPathParserContext
5910 */
5911void
5912xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5913 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005914 xmlFree(ctxt->valueTab);
5915 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00005916 if (ctxt->comp != NULL) {
5917#ifdef XPATH_STREAMING
5918 if (ctxt->comp->stream != NULL) {
5919 xmlFreePatternList(ctxt->comp->stream);
5920 ctxt->comp->stream = NULL;
5921 }
5922#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005923 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00005924 }
Owen Taylor3473f882001-02-23 17:55:21 +00005925 xmlFree(ctxt);
5926}
5927
5928/************************************************************************
5929 * *
5930 * The implicit core function library *
5931 * *
5932 ************************************************************************/
5933
Owen Taylor3473f882001-02-23 17:55:21 +00005934/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005935 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00005936 * @node: a node pointer
5937 *
5938 * Function computing the beginning of the string value of the node,
5939 * used to speed up comparisons
5940 *
5941 * Returns an int usable as a hash
5942 */
5943static unsigned int
5944xmlXPathNodeValHash(xmlNodePtr node) {
5945 int len = 2;
5946 const xmlChar * string = NULL;
5947 xmlNodePtr tmp = NULL;
5948 unsigned int ret = 0;
5949
5950 if (node == NULL)
5951 return(0);
5952
Daniel Veillard9adc0462003-03-24 18:39:54 +00005953 if (node->type == XML_DOCUMENT_NODE) {
5954 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5955 if (tmp == NULL)
5956 node = node->children;
5957 else
5958 node = tmp;
5959
5960 if (node == NULL)
5961 return(0);
5962 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005963
5964 switch (node->type) {
5965 case XML_COMMENT_NODE:
5966 case XML_PI_NODE:
5967 case XML_CDATA_SECTION_NODE:
5968 case XML_TEXT_NODE:
5969 string = node->content;
5970 if (string == NULL)
5971 return(0);
5972 if (string[0] == 0)
5973 return(0);
5974 return(((unsigned int) string[0]) +
5975 (((unsigned int) string[1]) << 8));
5976 case XML_NAMESPACE_DECL:
5977 string = ((xmlNsPtr)node)->href;
5978 if (string == NULL)
5979 return(0);
5980 if (string[0] == 0)
5981 return(0);
5982 return(((unsigned int) string[0]) +
5983 (((unsigned int) string[1]) << 8));
5984 case XML_ATTRIBUTE_NODE:
5985 tmp = ((xmlAttrPtr) node)->children;
5986 break;
5987 case XML_ELEMENT_NODE:
5988 tmp = node->children;
5989 break;
5990 default:
5991 return(0);
5992 }
5993 while (tmp != NULL) {
5994 switch (tmp->type) {
5995 case XML_COMMENT_NODE:
5996 case XML_PI_NODE:
5997 case XML_CDATA_SECTION_NODE:
5998 case XML_TEXT_NODE:
5999 string = tmp->content;
6000 break;
6001 case XML_NAMESPACE_DECL:
6002 string = ((xmlNsPtr)tmp)->href;
6003 break;
6004 default:
6005 break;
6006 }
6007 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006008 if (len == 1) {
6009 return(ret + (((unsigned int) string[0]) << 8));
6010 }
6011 if (string[1] == 0) {
6012 len = 1;
6013 ret = (unsigned int) string[0];
6014 } else {
6015 return(((unsigned int) string[0]) +
6016 (((unsigned int) string[1]) << 8));
6017 }
6018 }
6019 /*
6020 * Skip to next node
6021 */
6022 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6023 if (tmp->children->type != XML_ENTITY_DECL) {
6024 tmp = tmp->children;
6025 continue;
6026 }
6027 }
6028 if (tmp == node)
6029 break;
6030
6031 if (tmp->next != NULL) {
6032 tmp = tmp->next;
6033 continue;
6034 }
6035
6036 do {
6037 tmp = tmp->parent;
6038 if (tmp == NULL)
6039 break;
6040 if (tmp == node) {
6041 tmp = NULL;
6042 break;
6043 }
6044 if (tmp->next != NULL) {
6045 tmp = tmp->next;
6046 break;
6047 }
6048 } while (tmp != NULL);
6049 }
6050 return(ret);
6051}
6052
6053/**
6054 * xmlXPathStringHash:
6055 * @string: a string
6056 *
6057 * Function computing the beginning of the string value of the node,
6058 * used to speed up comparisons
6059 *
6060 * Returns an int usable as a hash
6061 */
6062static unsigned int
6063xmlXPathStringHash(const xmlChar * string) {
6064 if (string == NULL)
6065 return((unsigned int) 0);
6066 if (string[0] == 0)
6067 return(0);
6068 return(((unsigned int) string[0]) +
6069 (((unsigned int) string[1]) << 8));
6070}
6071
6072/**
Owen Taylor3473f882001-02-23 17:55:21 +00006073 * xmlXPathCompareNodeSetFloat:
6074 * @ctxt: the XPath Parser context
6075 * @inf: less than (1) or greater than (0)
6076 * @strict: is the comparison strict
6077 * @arg: the node set
6078 * @f: the value
6079 *
6080 * Implement the compare operation between a nodeset and a number
6081 * @ns < @val (1, 1, ...
6082 * @ns <= @val (1, 0, ...
6083 * @ns > @val (0, 1, ...
6084 * @ns >= @val (0, 0, ...
6085 *
6086 * If one object to be compared is a node-set and the other is a number,
6087 * then the comparison will be true if and only if there is a node in the
6088 * node-set such that the result of performing the comparison on the number
6089 * to be compared and on the result of converting the string-value of that
6090 * node to a number using the number function is true.
6091 *
6092 * Returns 0 or 1 depending on the results of the test.
6093 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006094static int
Owen Taylor3473f882001-02-23 17:55:21 +00006095xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6096 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6097 int i, ret = 0;
6098 xmlNodeSetPtr ns;
6099 xmlChar *str2;
6100
6101 if ((f == NULL) || (arg == NULL) ||
6102 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006103 xmlXPathReleaseObject(ctxt->context, arg);
6104 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006105 return(0);
6106 }
6107 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006108 if (ns != NULL) {
6109 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006110 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006111 if (str2 != NULL) {
6112 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006113 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006114 xmlFree(str2);
6115 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006116 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006117 ret = xmlXPathCompareValues(ctxt, inf, strict);
6118 if (ret)
6119 break;
6120 }
6121 }
Owen Taylor3473f882001-02-23 17:55:21 +00006122 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006123 xmlXPathReleaseObject(ctxt->context, arg);
6124 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006125 return(ret);
6126}
6127
6128/**
6129 * xmlXPathCompareNodeSetString:
6130 * @ctxt: the XPath Parser context
6131 * @inf: less than (1) or greater than (0)
6132 * @strict: is the comparison strict
6133 * @arg: the node set
6134 * @s: the value
6135 *
6136 * Implement the compare operation between a nodeset and a string
6137 * @ns < @val (1, 1, ...
6138 * @ns <= @val (1, 0, ...
6139 * @ns > @val (0, 1, ...
6140 * @ns >= @val (0, 0, ...
6141 *
6142 * If one object to be compared is a node-set and the other is a string,
6143 * then the comparison will be true if and only if there is a node in
6144 * the node-set such that the result of performing the comparison on the
6145 * string-value of the node and the other string is true.
6146 *
6147 * Returns 0 or 1 depending on the results of the test.
6148 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006149static int
Owen Taylor3473f882001-02-23 17:55:21 +00006150xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6151 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6152 int i, ret = 0;
6153 xmlNodeSetPtr ns;
6154 xmlChar *str2;
6155
6156 if ((s == NULL) || (arg == NULL) ||
6157 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006158 xmlXPathReleaseObject(ctxt->context, arg);
6159 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006160 return(0);
6161 }
6162 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006163 if (ns != NULL) {
6164 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006165 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006166 if (str2 != NULL) {
6167 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006168 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006169 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006170 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006171 ret = xmlXPathCompareValues(ctxt, inf, strict);
6172 if (ret)
6173 break;
6174 }
6175 }
Owen Taylor3473f882001-02-23 17:55:21 +00006176 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006177 xmlXPathReleaseObject(ctxt->context, arg);
6178 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006179 return(ret);
6180}
6181
6182/**
6183 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006184 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006185 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006186 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006187 * @arg2: the second node set object
6188 *
6189 * Implement the compare operation on nodesets:
6190 *
6191 * If both objects to be compared are node-sets, then the comparison
6192 * will be true if and only if there is a node in the first node-set
6193 * and a node in the second node-set such that the result of performing
6194 * the comparison on the string-values of the two nodes is true.
6195 * ....
6196 * When neither object to be compared is a node-set and the operator
6197 * is <=, <, >= or >, then the objects are compared by converting both
6198 * objects to numbers and comparing the numbers according to IEEE 754.
6199 * ....
6200 * The number function converts its argument to a number as follows:
6201 * - a string that consists of optional whitespace followed by an
6202 * optional minus sign followed by a Number followed by whitespace
6203 * is converted to the IEEE 754 number that is nearest (according
6204 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6205 * represented by the string; any other string is converted to NaN
6206 *
6207 * Conclusion all nodes need to be converted first to their string value
6208 * and then the comparison must be done when possible
6209 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006210static int
6211xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006212 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6213 int i, j, init = 0;
6214 double val1;
6215 double *values2;
6216 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006217 xmlNodeSetPtr ns1;
6218 xmlNodeSetPtr ns2;
6219
6220 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006221 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6222 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006223 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006224 }
Owen Taylor3473f882001-02-23 17:55:21 +00006225 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006226 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6227 xmlXPathFreeObject(arg1);
6228 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006229 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006230 }
Owen Taylor3473f882001-02-23 17:55:21 +00006231
6232 ns1 = arg1->nodesetval;
6233 ns2 = arg2->nodesetval;
6234
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006235 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006236 xmlXPathFreeObject(arg1);
6237 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006238 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006239 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006240 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006241 xmlXPathFreeObject(arg1);
6242 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006243 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006244 }
Owen Taylor3473f882001-02-23 17:55:21 +00006245
6246 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6247 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006248 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006249 xmlXPathFreeObject(arg1);
6250 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006251 return(0);
6252 }
6253 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006254 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006255 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006256 continue;
6257 for (j = 0;j < ns2->nodeNr;j++) {
6258 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006259 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006260 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006261 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006262 continue;
6263 if (inf && strict)
6264 ret = (val1 < values2[j]);
6265 else if (inf && !strict)
6266 ret = (val1 <= values2[j]);
6267 else if (!inf && strict)
6268 ret = (val1 > values2[j]);
6269 else if (!inf && !strict)
6270 ret = (val1 >= values2[j]);
6271 if (ret)
6272 break;
6273 }
6274 if (ret)
6275 break;
6276 init = 1;
6277 }
6278 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006279 xmlXPathFreeObject(arg1);
6280 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006281 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006282}
6283
6284/**
6285 * xmlXPathCompareNodeSetValue:
6286 * @ctxt: the XPath Parser context
6287 * @inf: less than (1) or greater than (0)
6288 * @strict: is the comparison strict
6289 * @arg: the node set
6290 * @val: the value
6291 *
6292 * Implement the compare operation between a nodeset and a value
6293 * @ns < @val (1, 1, ...
6294 * @ns <= @val (1, 0, ...
6295 * @ns > @val (0, 1, ...
6296 * @ns >= @val (0, 0, ...
6297 *
6298 * If one object to be compared is a node-set and the other is a boolean,
6299 * then the comparison will be true if and only if the result of performing
6300 * the comparison on the boolean and on the result of converting
6301 * the node-set to a boolean using the boolean function is true.
6302 *
6303 * Returns 0 or 1 depending on the results of the test.
6304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006305static int
Owen Taylor3473f882001-02-23 17:55:21 +00006306xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6307 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6308 if ((val == NULL) || (arg == NULL) ||
6309 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6310 return(0);
6311
6312 switch(val->type) {
6313 case XPATH_NUMBER:
6314 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6315 case XPATH_NODESET:
6316 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006317 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006318 case XPATH_STRING:
6319 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6320 case XPATH_BOOLEAN:
6321 valuePush(ctxt, arg);
6322 xmlXPathBooleanFunction(ctxt, 1);
6323 valuePush(ctxt, val);
6324 return(xmlXPathCompareValues(ctxt, inf, strict));
6325 default:
6326 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006327 }
6328 return(0);
6329}
6330
6331/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006332 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006333 * @arg: the nodeset object argument
6334 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006335 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006336 *
6337 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6338 * If one object to be compared is a node-set and the other is a string,
6339 * then the comparison will be true if and only if there is a node in
6340 * the node-set such that the result of performing the comparison on the
6341 * string-value of the node and the other string is true.
6342 *
6343 * Returns 0 or 1 depending on the results of the test.
6344 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006345static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006346xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006347{
Owen Taylor3473f882001-02-23 17:55:21 +00006348 int i;
6349 xmlNodeSetPtr ns;
6350 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006351 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006352
6353 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006354 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6355 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006356 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006357 /*
6358 * A NULL nodeset compared with a string is always false
6359 * (since there is no node equal, and no node not equal)
6360 */
6361 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006362 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006363 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006364 for (i = 0; i < ns->nodeNr; i++) {
6365 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6366 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6367 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6368 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006369 if (neq)
6370 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006371 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006372 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6373 if (neq)
6374 continue;
6375 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006376 } else if (neq) {
6377 if (str2 != NULL)
6378 xmlFree(str2);
6379 return (1);
6380 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006381 if (str2 != NULL)
6382 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006383 } else if (neq)
6384 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006385 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006386 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006387}
6388
6389/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006390 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006391 * @arg: the nodeset object argument
6392 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006393 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006394 *
6395 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6396 * If one object to be compared is a node-set and the other is a number,
6397 * then the comparison will be true if and only if there is a node in
6398 * the node-set such that the result of performing the comparison on the
6399 * number to be compared and on the result of converting the string-value
6400 * of that node to a number using the number function is true.
6401 *
6402 * Returns 0 or 1 depending on the results of the test.
6403 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006404static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006405xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6406 xmlXPathObjectPtr arg, double f, int neq) {
6407 int i, ret=0;
6408 xmlNodeSetPtr ns;
6409 xmlChar *str2;
6410 xmlXPathObjectPtr val;
6411 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006412
6413 if ((arg == NULL) ||
6414 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6415 return(0);
6416
William M. Brack0c022ad2002-07-12 00:56:01 +00006417 ns = arg->nodesetval;
6418 if (ns != NULL) {
6419 for (i=0;i<ns->nodeNr;i++) {
6420 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6421 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006422 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006423 xmlFree(str2);
6424 xmlXPathNumberFunction(ctxt, 1);
6425 val = valuePop(ctxt);
6426 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006427 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006428 if (!xmlXPathIsNaN(v)) {
6429 if ((!neq) && (v==f)) {
6430 ret = 1;
6431 break;
6432 } else if ((neq) && (v!=f)) {
6433 ret = 1;
6434 break;
6435 }
William M. Brack32f0f712005-07-14 07:00:33 +00006436 } else { /* NaN is unequal to any value */
6437 if (neq)
6438 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006439 }
6440 }
6441 }
6442 }
6443
6444 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006445}
6446
6447
6448/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006449 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006450 * @arg1: first nodeset object argument
6451 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006452 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006453 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006454 * Implement the equal / not equal operation on XPath nodesets:
6455 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006456 * If both objects to be compared are node-sets, then the comparison
6457 * will be true if and only if there is a node in the first node-set and
6458 * a node in the second node-set such that the result of performing the
6459 * comparison on the string-values of the two nodes is true.
6460 *
6461 * (needless to say, this is a costly operation)
6462 *
6463 * Returns 0 or 1 depending on the results of the test.
6464 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006465static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006466xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006467 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006468 unsigned int *hashs1;
6469 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006470 xmlChar **values1;
6471 xmlChar **values2;
6472 int ret = 0;
6473 xmlNodeSetPtr ns1;
6474 xmlNodeSetPtr ns2;
6475
6476 if ((arg1 == NULL) ||
6477 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6478 return(0);
6479 if ((arg2 == NULL) ||
6480 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6481 return(0);
6482
6483 ns1 = arg1->nodesetval;
6484 ns2 = arg2->nodesetval;
6485
Daniel Veillard911f49a2001-04-07 15:39:35 +00006486 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006487 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006488 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006489 return(0);
6490
6491 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006492 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006493 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006494 if (neq == 0)
6495 for (i = 0;i < ns1->nodeNr;i++)
6496 for (j = 0;j < ns2->nodeNr;j++)
6497 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6498 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006499
6500 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006501 if (values1 == NULL) {
6502 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006503 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006504 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006505 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6506 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006507 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006508 xmlFree(values1);
6509 return(0);
6510 }
Owen Taylor3473f882001-02-23 17:55:21 +00006511 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6512 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6513 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006514 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006515 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006516 xmlFree(values1);
6517 return(0);
6518 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006519 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6520 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006521 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006522 xmlFree(hashs1);
6523 xmlFree(values1);
6524 xmlFree(values2);
6525 return(0);
6526 }
Owen Taylor3473f882001-02-23 17:55:21 +00006527 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6528 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006529 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006530 for (j = 0;j < ns2->nodeNr;j++) {
6531 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006532 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006533 if (hashs1[i] != hashs2[j]) {
6534 if (neq) {
6535 ret = 1;
6536 break;
6537 }
6538 }
6539 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006540 if (values1[i] == NULL)
6541 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6542 if (values2[j] == NULL)
6543 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006544 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006545 if (ret)
6546 break;
6547 }
Owen Taylor3473f882001-02-23 17:55:21 +00006548 }
6549 if (ret)
6550 break;
6551 }
6552 for (i = 0;i < ns1->nodeNr;i++)
6553 if (values1[i] != NULL)
6554 xmlFree(values1[i]);
6555 for (j = 0;j < ns2->nodeNr;j++)
6556 if (values2[j] != NULL)
6557 xmlFree(values2[j]);
6558 xmlFree(values1);
6559 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006560 xmlFree(hashs1);
6561 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006562 return(ret);
6563}
6564
William M. Brack0c022ad2002-07-12 00:56:01 +00006565static int
6566xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6567 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006568 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006569 /*
6570 *At this point we are assured neither arg1 nor arg2
6571 *is a nodeset, so we can just pick the appropriate routine.
6572 */
Owen Taylor3473f882001-02-23 17:55:21 +00006573 switch (arg1->type) {
6574 case XPATH_UNDEFINED:
6575#ifdef DEBUG_EXPR
6576 xmlGenericError(xmlGenericErrorContext,
6577 "Equal: undefined\n");
6578#endif
6579 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006580 case XPATH_BOOLEAN:
6581 switch (arg2->type) {
6582 case XPATH_UNDEFINED:
6583#ifdef DEBUG_EXPR
6584 xmlGenericError(xmlGenericErrorContext,
6585 "Equal: undefined\n");
6586#endif
6587 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006588 case XPATH_BOOLEAN:
6589#ifdef DEBUG_EXPR
6590 xmlGenericError(xmlGenericErrorContext,
6591 "Equal: %d boolean %d \n",
6592 arg1->boolval, arg2->boolval);
6593#endif
6594 ret = (arg1->boolval == arg2->boolval);
6595 break;
6596 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006597 ret = (arg1->boolval ==
6598 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006599 break;
6600 case XPATH_STRING:
6601 if ((arg2->stringval == NULL) ||
6602 (arg2->stringval[0] == 0)) ret = 0;
6603 else
6604 ret = 1;
6605 ret = (arg1->boolval == ret);
6606 break;
6607 case XPATH_USERS:
6608 case XPATH_POINT:
6609 case XPATH_RANGE:
6610 case XPATH_LOCATIONSET:
6611 TODO
6612 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006613 case XPATH_NODESET:
6614 case XPATH_XSLT_TREE:
6615 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006616 }
6617 break;
6618 case XPATH_NUMBER:
6619 switch (arg2->type) {
6620 case XPATH_UNDEFINED:
6621#ifdef DEBUG_EXPR
6622 xmlGenericError(xmlGenericErrorContext,
6623 "Equal: undefined\n");
6624#endif
6625 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006626 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006627 ret = (arg2->boolval==
6628 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006629 break;
6630 case XPATH_STRING:
6631 valuePush(ctxt, arg2);
6632 xmlXPathNumberFunction(ctxt, 1);
6633 arg2 = valuePop(ctxt);
6634 /* no break on purpose */
6635 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006636 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006637 if (xmlXPathIsNaN(arg1->floatval) ||
6638 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006639 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006640 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6641 if (xmlXPathIsInf(arg2->floatval) == 1)
6642 ret = 1;
6643 else
6644 ret = 0;
6645 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6646 if (xmlXPathIsInf(arg2->floatval) == -1)
6647 ret = 1;
6648 else
6649 ret = 0;
6650 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6651 if (xmlXPathIsInf(arg1->floatval) == 1)
6652 ret = 1;
6653 else
6654 ret = 0;
6655 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6656 if (xmlXPathIsInf(arg1->floatval) == -1)
6657 ret = 1;
6658 else
6659 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006660 } else {
6661 ret = (arg1->floatval == arg2->floatval);
6662 }
Owen Taylor3473f882001-02-23 17:55:21 +00006663 break;
6664 case XPATH_USERS:
6665 case XPATH_POINT:
6666 case XPATH_RANGE:
6667 case XPATH_LOCATIONSET:
6668 TODO
6669 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006670 case XPATH_NODESET:
6671 case XPATH_XSLT_TREE:
6672 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006673 }
6674 break;
6675 case XPATH_STRING:
6676 switch (arg2->type) {
6677 case XPATH_UNDEFINED:
6678#ifdef DEBUG_EXPR
6679 xmlGenericError(xmlGenericErrorContext,
6680 "Equal: undefined\n");
6681#endif
6682 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006683 case XPATH_BOOLEAN:
6684 if ((arg1->stringval == NULL) ||
6685 (arg1->stringval[0] == 0)) ret = 0;
6686 else
6687 ret = 1;
6688 ret = (arg2->boolval == ret);
6689 break;
6690 case XPATH_STRING:
6691 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6692 break;
6693 case XPATH_NUMBER:
6694 valuePush(ctxt, arg1);
6695 xmlXPathNumberFunction(ctxt, 1);
6696 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006697 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006698 if (xmlXPathIsNaN(arg1->floatval) ||
6699 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006700 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006701 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6702 if (xmlXPathIsInf(arg2->floatval) == 1)
6703 ret = 1;
6704 else
6705 ret = 0;
6706 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6707 if (xmlXPathIsInf(arg2->floatval) == -1)
6708 ret = 1;
6709 else
6710 ret = 0;
6711 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6712 if (xmlXPathIsInf(arg1->floatval) == 1)
6713 ret = 1;
6714 else
6715 ret = 0;
6716 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6717 if (xmlXPathIsInf(arg1->floatval) == -1)
6718 ret = 1;
6719 else
6720 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006721 } else {
6722 ret = (arg1->floatval == arg2->floatval);
6723 }
Owen Taylor3473f882001-02-23 17:55:21 +00006724 break;
6725 case XPATH_USERS:
6726 case XPATH_POINT:
6727 case XPATH_RANGE:
6728 case XPATH_LOCATIONSET:
6729 TODO
6730 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006731 case XPATH_NODESET:
6732 case XPATH_XSLT_TREE:
6733 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006734 }
6735 break;
6736 case XPATH_USERS:
6737 case XPATH_POINT:
6738 case XPATH_RANGE:
6739 case XPATH_LOCATIONSET:
6740 TODO
6741 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006742 case XPATH_NODESET:
6743 case XPATH_XSLT_TREE:
6744 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006745 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006746 xmlXPathReleaseObject(ctxt->context, arg1);
6747 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006748 return(ret);
6749}
6750
William M. Brack0c022ad2002-07-12 00:56:01 +00006751/**
6752 * xmlXPathEqualValues:
6753 * @ctxt: the XPath Parser context
6754 *
6755 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6756 *
6757 * Returns 0 or 1 depending on the results of the test.
6758 */
6759int
6760xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6761 xmlXPathObjectPtr arg1, arg2, argtmp;
6762 int ret = 0;
6763
Daniel Veillard6128c012004-11-08 17:16:15 +00006764 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006765 arg2 = valuePop(ctxt);
6766 arg1 = valuePop(ctxt);
6767 if ((arg1 == NULL) || (arg2 == NULL)) {
6768 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006769 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006770 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006771 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006772 XP_ERROR0(XPATH_INVALID_OPERAND);
6773 }
6774
6775 if (arg1 == arg2) {
6776#ifdef DEBUG_EXPR
6777 xmlGenericError(xmlGenericErrorContext,
6778 "Equal: by pointer\n");
6779#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00006780 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006781 return(1);
6782 }
6783
6784 /*
6785 *If either argument is a nodeset, it's a 'special case'
6786 */
6787 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6788 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6789 /*
6790 *Hack it to assure arg1 is the nodeset
6791 */
6792 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6793 argtmp = arg2;
6794 arg2 = arg1;
6795 arg1 = argtmp;
6796 }
6797 switch (arg2->type) {
6798 case XPATH_UNDEFINED:
6799#ifdef DEBUG_EXPR
6800 xmlGenericError(xmlGenericErrorContext,
6801 "Equal: undefined\n");
6802#endif
6803 break;
6804 case XPATH_NODESET:
6805 case XPATH_XSLT_TREE:
6806 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6807 break;
6808 case XPATH_BOOLEAN:
6809 if ((arg1->nodesetval == NULL) ||
6810 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6811 else
6812 ret = 1;
6813 ret = (ret == arg2->boolval);
6814 break;
6815 case XPATH_NUMBER:
6816 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6817 break;
6818 case XPATH_STRING:
6819 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6820 break;
6821 case XPATH_USERS:
6822 case XPATH_POINT:
6823 case XPATH_RANGE:
6824 case XPATH_LOCATIONSET:
6825 TODO
6826 break;
6827 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006828 xmlXPathReleaseObject(ctxt->context, arg1);
6829 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006830 return(ret);
6831 }
6832
6833 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6834}
6835
6836/**
6837 * xmlXPathNotEqualValues:
6838 * @ctxt: the XPath Parser context
6839 *
6840 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6841 *
6842 * Returns 0 or 1 depending on the results of the test.
6843 */
6844int
6845xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6846 xmlXPathObjectPtr arg1, arg2, argtmp;
6847 int ret = 0;
6848
Daniel Veillard6128c012004-11-08 17:16:15 +00006849 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006850 arg2 = valuePop(ctxt);
6851 arg1 = valuePop(ctxt);
6852 if ((arg1 == NULL) || (arg2 == NULL)) {
6853 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006854 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006855 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006856 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006857 XP_ERROR0(XPATH_INVALID_OPERAND);
6858 }
6859
6860 if (arg1 == arg2) {
6861#ifdef DEBUG_EXPR
6862 xmlGenericError(xmlGenericErrorContext,
6863 "NotEqual: by pointer\n");
6864#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006865 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006866 return(0);
6867 }
6868
6869 /*
6870 *If either argument is a nodeset, it's a 'special case'
6871 */
6872 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6873 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6874 /*
6875 *Hack it to assure arg1 is the nodeset
6876 */
6877 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6878 argtmp = arg2;
6879 arg2 = arg1;
6880 arg1 = argtmp;
6881 }
6882 switch (arg2->type) {
6883 case XPATH_UNDEFINED:
6884#ifdef DEBUG_EXPR
6885 xmlGenericError(xmlGenericErrorContext,
6886 "NotEqual: undefined\n");
6887#endif
6888 break;
6889 case XPATH_NODESET:
6890 case XPATH_XSLT_TREE:
6891 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6892 break;
6893 case XPATH_BOOLEAN:
6894 if ((arg1->nodesetval == NULL) ||
6895 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6896 else
6897 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00006898 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00006899 break;
6900 case XPATH_NUMBER:
6901 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6902 break;
6903 case XPATH_STRING:
6904 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6905 break;
6906 case XPATH_USERS:
6907 case XPATH_POINT:
6908 case XPATH_RANGE:
6909 case XPATH_LOCATIONSET:
6910 TODO
6911 break;
6912 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006913 xmlXPathReleaseObject(ctxt->context, arg1);
6914 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006915 return(ret);
6916 }
6917
6918 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6919}
Owen Taylor3473f882001-02-23 17:55:21 +00006920
6921/**
6922 * xmlXPathCompareValues:
6923 * @ctxt: the XPath Parser context
6924 * @inf: less than (1) or greater than (0)
6925 * @strict: is the comparison strict
6926 *
6927 * Implement the compare operation on XPath objects:
6928 * @arg1 < @arg2 (1, 1, ...
6929 * @arg1 <= @arg2 (1, 0, ...
6930 * @arg1 > @arg2 (0, 1, ...
6931 * @arg1 >= @arg2 (0, 0, ...
6932 *
6933 * When neither object to be compared is a node-set and the operator is
6934 * <=, <, >=, >, then the objects are compared by converted both objects
6935 * to numbers and comparing the numbers according to IEEE 754. The <
6936 * comparison will be true if and only if the first number is less than the
6937 * second number. The <= comparison will be true if and only if the first
6938 * number is less than or equal to the second number. The > comparison
6939 * will be true if and only if the first number is greater than the second
6940 * number. The >= comparison will be true if and only if the first number
6941 * is greater than or equal to the second number.
6942 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006943 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00006944 */
6945int
6946xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006947 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006948 xmlXPathObjectPtr arg1, arg2;
6949
Daniel Veillard6128c012004-11-08 17:16:15 +00006950 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006951 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006952 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00006953 if ((arg1 == NULL) || (arg2 == NULL)) {
6954 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006955 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006956 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006957 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006958 XP_ERROR0(XPATH_INVALID_OPERAND);
6959 }
6960
William M. Brack0c022ad2002-07-12 00:56:01 +00006961 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6962 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00006963 /*
6964 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6965 * are not freed from within this routine; they will be freed from the
6966 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6967 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006968 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6969 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006970 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006971 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00006972 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006973 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6974 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006975 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006976 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6977 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00006978 }
6979 }
6980 return(ret);
6981 }
6982
6983 if (arg1->type != XPATH_NUMBER) {
6984 valuePush(ctxt, arg1);
6985 xmlXPathNumberFunction(ctxt, 1);
6986 arg1 = valuePop(ctxt);
6987 }
6988 if (arg1->type != XPATH_NUMBER) {
6989 xmlXPathFreeObject(arg1);
6990 xmlXPathFreeObject(arg2);
6991 XP_ERROR0(XPATH_INVALID_OPERAND);
6992 }
6993 if (arg2->type != XPATH_NUMBER) {
6994 valuePush(ctxt, arg2);
6995 xmlXPathNumberFunction(ctxt, 1);
6996 arg2 = valuePop(ctxt);
6997 }
6998 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006999 xmlXPathReleaseObject(ctxt->context, arg1);
7000 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007001 XP_ERROR0(XPATH_INVALID_OPERAND);
7002 }
7003 /*
7004 * Add tests for infinity and nan
7005 * => feedback on 3.4 for Inf and NaN
7006 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007007 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007008 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007009 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007010 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007011 arg1i=xmlXPathIsInf(arg1->floatval);
7012 arg2i=xmlXPathIsInf(arg2->floatval);
7013 if (inf && strict) {
7014 if ((arg1i == -1 && arg2i != -1) ||
7015 (arg2i == 1 && arg1i != 1)) {
7016 ret = 1;
7017 } else if (arg1i == 0 && arg2i == 0) {
7018 ret = (arg1->floatval < arg2->floatval);
7019 } else {
7020 ret = 0;
7021 }
7022 }
7023 else if (inf && !strict) {
7024 if (arg1i == -1 || arg2i == 1) {
7025 ret = 1;
7026 } else if (arg1i == 0 && arg2i == 0) {
7027 ret = (arg1->floatval <= arg2->floatval);
7028 } else {
7029 ret = 0;
7030 }
7031 }
7032 else if (!inf && strict) {
7033 if ((arg1i == 1 && arg2i != 1) ||
7034 (arg2i == -1 && arg1i != -1)) {
7035 ret = 1;
7036 } else if (arg1i == 0 && arg2i == 0) {
7037 ret = (arg1->floatval > arg2->floatval);
7038 } else {
7039 ret = 0;
7040 }
7041 }
7042 else if (!inf && !strict) {
7043 if (arg1i == 1 || arg2i == -1) {
7044 ret = 1;
7045 } else if (arg1i == 0 && arg2i == 0) {
7046 ret = (arg1->floatval >= arg2->floatval);
7047 } else {
7048 ret = 0;
7049 }
7050 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007051 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007052 xmlXPathReleaseObject(ctxt->context, arg1);
7053 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007054 return(ret);
7055}
7056
7057/**
7058 * xmlXPathValueFlipSign:
7059 * @ctxt: the XPath Parser context
7060 *
7061 * Implement the unary - operation on an XPath object
7062 * The numeric operators convert their operands to numbers as if
7063 * by calling the number function.
7064 */
7065void
7066xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007067 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007068 CAST_TO_NUMBER;
7069 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007070 if (xmlXPathIsNaN(ctxt->value->floatval))
7071 ctxt->value->floatval=xmlXPathNAN;
7072 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7073 ctxt->value->floatval=xmlXPathNINF;
7074 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7075 ctxt->value->floatval=xmlXPathPINF;
7076 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007077 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7078 ctxt->value->floatval = xmlXPathNZERO;
7079 else
7080 ctxt->value->floatval = 0;
7081 }
7082 else
7083 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007084}
7085
7086/**
7087 * xmlXPathAddValues:
7088 * @ctxt: the XPath Parser context
7089 *
7090 * Implement the add operation on XPath objects:
7091 * The numeric operators convert their operands to numbers as if
7092 * by calling the number function.
7093 */
7094void
7095xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7096 xmlXPathObjectPtr arg;
7097 double val;
7098
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007099 arg = valuePop(ctxt);
7100 if (arg == NULL)
7101 XP_ERROR(XPATH_INVALID_OPERAND);
7102 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007103 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007104 CAST_TO_NUMBER;
7105 CHECK_TYPE(XPATH_NUMBER);
7106 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007107}
7108
7109/**
7110 * xmlXPathSubValues:
7111 * @ctxt: the XPath Parser context
7112 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007113 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007114 * The numeric operators convert their operands to numbers as if
7115 * by calling the number function.
7116 */
7117void
7118xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7119 xmlXPathObjectPtr arg;
7120 double val;
7121
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007122 arg = valuePop(ctxt);
7123 if (arg == NULL)
7124 XP_ERROR(XPATH_INVALID_OPERAND);
7125 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007126 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007127 CAST_TO_NUMBER;
7128 CHECK_TYPE(XPATH_NUMBER);
7129 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007130}
7131
7132/**
7133 * xmlXPathMultValues:
7134 * @ctxt: the XPath Parser context
7135 *
7136 * Implement the multiply operation on XPath objects:
7137 * The numeric operators convert their operands to numbers as if
7138 * by calling the number function.
7139 */
7140void
7141xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7142 xmlXPathObjectPtr arg;
7143 double val;
7144
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007145 arg = valuePop(ctxt);
7146 if (arg == NULL)
7147 XP_ERROR(XPATH_INVALID_OPERAND);
7148 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007149 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007150 CAST_TO_NUMBER;
7151 CHECK_TYPE(XPATH_NUMBER);
7152 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007153}
7154
7155/**
7156 * xmlXPathDivValues:
7157 * @ctxt: the XPath Parser context
7158 *
7159 * Implement the div operation on XPath objects @arg1 / @arg2:
7160 * The numeric operators convert their operands to numbers as if
7161 * by calling the number function.
7162 */
7163void
7164xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7165 xmlXPathObjectPtr arg;
7166 double val;
7167
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007168 arg = valuePop(ctxt);
7169 if (arg == NULL)
7170 XP_ERROR(XPATH_INVALID_OPERAND);
7171 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007172 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007173 CAST_TO_NUMBER;
7174 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007175 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7176 ctxt->value->floatval = xmlXPathNAN;
7177 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007178 if (ctxt->value->floatval == 0)
7179 ctxt->value->floatval = xmlXPathNAN;
7180 else if (ctxt->value->floatval > 0)
7181 ctxt->value->floatval = xmlXPathNINF;
7182 else if (ctxt->value->floatval < 0)
7183 ctxt->value->floatval = xmlXPathPINF;
7184 }
7185 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007186 if (ctxt->value->floatval == 0)
7187 ctxt->value->floatval = xmlXPathNAN;
7188 else if (ctxt->value->floatval > 0)
7189 ctxt->value->floatval = xmlXPathPINF;
7190 else if (ctxt->value->floatval < 0)
7191 ctxt->value->floatval = xmlXPathNINF;
7192 } else
7193 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007194}
7195
7196/**
7197 * xmlXPathModValues:
7198 * @ctxt: the XPath Parser context
7199 *
7200 * Implement the mod operation on XPath objects: @arg1 / @arg2
7201 * The numeric operators convert their operands to numbers as if
7202 * by calling the number function.
7203 */
7204void
7205xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7206 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007207 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007208
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007209 arg = valuePop(ctxt);
7210 if (arg == NULL)
7211 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007212 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007213 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007214 CAST_TO_NUMBER;
7215 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007216 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007217 if (arg2 == 0)
7218 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007219 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007220 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007221 }
Owen Taylor3473f882001-02-23 17:55:21 +00007222}
7223
7224/************************************************************************
7225 * *
7226 * The traversal functions *
7227 * *
7228 ************************************************************************/
7229
Owen Taylor3473f882001-02-23 17:55:21 +00007230/*
7231 * A traversal function enumerates nodes along an axis.
7232 * Initially it must be called with NULL, and it indicates
7233 * termination on the axis by returning NULL.
7234 */
7235typedef xmlNodePtr (*xmlXPathTraversalFunction)
7236 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7237
7238/**
7239 * xmlXPathNextSelf:
7240 * @ctxt: the XPath Parser context
7241 * @cur: the current node in the traversal
7242 *
7243 * Traversal function for the "self" direction
7244 * The self axis contains just the context node itself
7245 *
7246 * Returns the next element following that axis
7247 */
7248xmlNodePtr
7249xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007250 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007251 if (cur == NULL)
7252 return(ctxt->context->node);
7253 return(NULL);
7254}
7255
7256/**
7257 * xmlXPathNextChild:
7258 * @ctxt: the XPath Parser context
7259 * @cur: the current node in the traversal
7260 *
7261 * Traversal function for the "child" direction
7262 * The child axis contains the children of the context node in document order.
7263 *
7264 * Returns the next element following that axis
7265 */
7266xmlNodePtr
7267xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007268 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007269 if (cur == NULL) {
7270 if (ctxt->context->node == NULL) return(NULL);
7271 switch (ctxt->context->node->type) {
7272 case XML_ELEMENT_NODE:
7273 case XML_TEXT_NODE:
7274 case XML_CDATA_SECTION_NODE:
7275 case XML_ENTITY_REF_NODE:
7276 case XML_ENTITY_NODE:
7277 case XML_PI_NODE:
7278 case XML_COMMENT_NODE:
7279 case XML_NOTATION_NODE:
7280 case XML_DTD_NODE:
7281 return(ctxt->context->node->children);
7282 case XML_DOCUMENT_NODE:
7283 case XML_DOCUMENT_TYPE_NODE:
7284 case XML_DOCUMENT_FRAG_NODE:
7285 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007286#ifdef LIBXML_DOCB_ENABLED
7287 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007288#endif
7289 return(((xmlDocPtr) ctxt->context->node)->children);
7290 case XML_ELEMENT_DECL:
7291 case XML_ATTRIBUTE_DECL:
7292 case XML_ENTITY_DECL:
7293 case XML_ATTRIBUTE_NODE:
7294 case XML_NAMESPACE_DECL:
7295 case XML_XINCLUDE_START:
7296 case XML_XINCLUDE_END:
7297 return(NULL);
7298 }
7299 return(NULL);
7300 }
7301 if ((cur->type == XML_DOCUMENT_NODE) ||
7302 (cur->type == XML_HTML_DOCUMENT_NODE))
7303 return(NULL);
7304 return(cur->next);
7305}
7306
7307/**
7308 * xmlXPathNextDescendant:
7309 * @ctxt: the XPath Parser context
7310 * @cur: the current node in the traversal
7311 *
7312 * Traversal function for the "descendant" direction
7313 * the descendant axis contains the descendants of the context node in document
7314 * order; a descendant is a child or a child of a child and so on.
7315 *
7316 * Returns the next element following that axis
7317 */
7318xmlNodePtr
7319xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007320 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007321 if (cur == NULL) {
7322 if (ctxt->context->node == NULL)
7323 return(NULL);
7324 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7325 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7326 return(NULL);
7327
7328 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7329 return(ctxt->context->doc->children);
7330 return(ctxt->context->node->children);
7331 }
7332
Daniel Veillard567e1b42001-08-01 15:53:47 +00007333 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007334 /*
7335 * Do not descend on entities declarations
7336 */
7337 if (cur->children->type != XML_ENTITY_DECL) {
7338 cur = cur->children;
7339 /*
7340 * Skip DTDs
7341 */
7342 if (cur->type != XML_DTD_NODE)
7343 return(cur);
7344 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007345 }
7346
7347 if (cur == ctxt->context->node) return(NULL);
7348
Daniel Veillard68e9e742002-11-16 15:35:11 +00007349 while (cur->next != NULL) {
7350 cur = cur->next;
7351 if ((cur->type != XML_ENTITY_DECL) &&
7352 (cur->type != XML_DTD_NODE))
7353 return(cur);
7354 }
Owen Taylor3473f882001-02-23 17:55:21 +00007355
7356 do {
7357 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007358 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007359 if (cur == ctxt->context->node) return(NULL);
7360 if (cur->next != NULL) {
7361 cur = cur->next;
7362 return(cur);
7363 }
7364 } while (cur != NULL);
7365 return(cur);
7366}
7367
7368/**
7369 * xmlXPathNextDescendantOrSelf:
7370 * @ctxt: the XPath Parser context
7371 * @cur: the current node in the traversal
7372 *
7373 * Traversal function for the "descendant-or-self" direction
7374 * the descendant-or-self axis contains the context node and the descendants
7375 * of the context node in document order; thus the context node is the first
7376 * node on the axis, and the first child of the context node is the second node
7377 * on the axis
7378 *
7379 * Returns the next element following that axis
7380 */
7381xmlNodePtr
7382xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007383 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007384 if (cur == NULL) {
7385 if (ctxt->context->node == NULL)
7386 return(NULL);
7387 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7388 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7389 return(NULL);
7390 return(ctxt->context->node);
7391 }
7392
7393 return(xmlXPathNextDescendant(ctxt, cur));
7394}
7395
7396/**
7397 * xmlXPathNextParent:
7398 * @ctxt: the XPath Parser context
7399 * @cur: the current node in the traversal
7400 *
7401 * Traversal function for the "parent" direction
7402 * The parent axis contains the parent of the context node, if there is one.
7403 *
7404 * Returns the next element following that axis
7405 */
7406xmlNodePtr
7407xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007408 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007409 /*
7410 * the parent of an attribute or namespace node is the element
7411 * to which the attribute or namespace node is attached
7412 * Namespace handling !!!
7413 */
7414 if (cur == NULL) {
7415 if (ctxt->context->node == NULL) return(NULL);
7416 switch (ctxt->context->node->type) {
7417 case XML_ELEMENT_NODE:
7418 case XML_TEXT_NODE:
7419 case XML_CDATA_SECTION_NODE:
7420 case XML_ENTITY_REF_NODE:
7421 case XML_ENTITY_NODE:
7422 case XML_PI_NODE:
7423 case XML_COMMENT_NODE:
7424 case XML_NOTATION_NODE:
7425 case XML_DTD_NODE:
7426 case XML_ELEMENT_DECL:
7427 case XML_ATTRIBUTE_DECL:
7428 case XML_XINCLUDE_START:
7429 case XML_XINCLUDE_END:
7430 case XML_ENTITY_DECL:
7431 if (ctxt->context->node->parent == NULL)
7432 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007433 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007434 ((ctxt->context->node->parent->name[0] == ' ') ||
7435 (xmlStrEqual(ctxt->context->node->parent->name,
7436 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007437 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007438 return(ctxt->context->node->parent);
7439 case XML_ATTRIBUTE_NODE: {
7440 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7441
7442 return(att->parent);
7443 }
7444 case XML_DOCUMENT_NODE:
7445 case XML_DOCUMENT_TYPE_NODE:
7446 case XML_DOCUMENT_FRAG_NODE:
7447 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007448#ifdef LIBXML_DOCB_ENABLED
7449 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007450#endif
7451 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007452 case XML_NAMESPACE_DECL: {
7453 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7454
7455 if ((ns->next != NULL) &&
7456 (ns->next->type != XML_NAMESPACE_DECL))
7457 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007458 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007459 }
Owen Taylor3473f882001-02-23 17:55:21 +00007460 }
7461 }
7462 return(NULL);
7463}
7464
7465/**
7466 * xmlXPathNextAncestor:
7467 * @ctxt: the XPath Parser context
7468 * @cur: the current node in the traversal
7469 *
7470 * Traversal function for the "ancestor" direction
7471 * the ancestor axis contains the ancestors of the context node; the ancestors
7472 * of the context node consist of the parent of context node and the parent's
7473 * parent and so on; the nodes are ordered in reverse document order; thus the
7474 * parent is the first node on the axis, and the parent's parent is the second
7475 * node on the axis
7476 *
7477 * Returns the next element following that axis
7478 */
7479xmlNodePtr
7480xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007481 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007482 /*
7483 * the parent of an attribute or namespace node is the element
7484 * to which the attribute or namespace node is attached
7485 * !!!!!!!!!!!!!
7486 */
7487 if (cur == NULL) {
7488 if (ctxt->context->node == NULL) return(NULL);
7489 switch (ctxt->context->node->type) {
7490 case XML_ELEMENT_NODE:
7491 case XML_TEXT_NODE:
7492 case XML_CDATA_SECTION_NODE:
7493 case XML_ENTITY_REF_NODE:
7494 case XML_ENTITY_NODE:
7495 case XML_PI_NODE:
7496 case XML_COMMENT_NODE:
7497 case XML_DTD_NODE:
7498 case XML_ELEMENT_DECL:
7499 case XML_ATTRIBUTE_DECL:
7500 case XML_ENTITY_DECL:
7501 case XML_NOTATION_NODE:
7502 case XML_XINCLUDE_START:
7503 case XML_XINCLUDE_END:
7504 if (ctxt->context->node->parent == NULL)
7505 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007506 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007507 ((ctxt->context->node->parent->name[0] == ' ') ||
7508 (xmlStrEqual(ctxt->context->node->parent->name,
7509 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007510 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007511 return(ctxt->context->node->parent);
7512 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007513 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007514
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007515 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007516 }
7517 case XML_DOCUMENT_NODE:
7518 case XML_DOCUMENT_TYPE_NODE:
7519 case XML_DOCUMENT_FRAG_NODE:
7520 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007521#ifdef LIBXML_DOCB_ENABLED
7522 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007523#endif
7524 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007525 case XML_NAMESPACE_DECL: {
7526 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7527
7528 if ((ns->next != NULL) &&
7529 (ns->next->type != XML_NAMESPACE_DECL))
7530 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007531 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007532 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007533 }
Owen Taylor3473f882001-02-23 17:55:21 +00007534 }
7535 return(NULL);
7536 }
7537 if (cur == ctxt->context->doc->children)
7538 return((xmlNodePtr) ctxt->context->doc);
7539 if (cur == (xmlNodePtr) ctxt->context->doc)
7540 return(NULL);
7541 switch (cur->type) {
7542 case XML_ELEMENT_NODE:
7543 case XML_TEXT_NODE:
7544 case XML_CDATA_SECTION_NODE:
7545 case XML_ENTITY_REF_NODE:
7546 case XML_ENTITY_NODE:
7547 case XML_PI_NODE:
7548 case XML_COMMENT_NODE:
7549 case XML_NOTATION_NODE:
7550 case XML_DTD_NODE:
7551 case XML_ELEMENT_DECL:
7552 case XML_ATTRIBUTE_DECL:
7553 case XML_ENTITY_DECL:
7554 case XML_XINCLUDE_START:
7555 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007556 if (cur->parent == NULL)
7557 return(NULL);
7558 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007559 ((cur->parent->name[0] == ' ') ||
7560 (xmlStrEqual(cur->parent->name,
7561 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007562 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007563 return(cur->parent);
7564 case XML_ATTRIBUTE_NODE: {
7565 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7566
7567 return(att->parent);
7568 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007569 case XML_NAMESPACE_DECL: {
7570 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7571
7572 if ((ns->next != NULL) &&
7573 (ns->next->type != XML_NAMESPACE_DECL))
7574 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007575 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007576 return(NULL);
7577 }
Owen Taylor3473f882001-02-23 17:55:21 +00007578 case XML_DOCUMENT_NODE:
7579 case XML_DOCUMENT_TYPE_NODE:
7580 case XML_DOCUMENT_FRAG_NODE:
7581 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007582#ifdef LIBXML_DOCB_ENABLED
7583 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007584#endif
7585 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007586 }
7587 return(NULL);
7588}
7589
7590/**
7591 * xmlXPathNextAncestorOrSelf:
7592 * @ctxt: the XPath Parser context
7593 * @cur: the current node in the traversal
7594 *
7595 * Traversal function for the "ancestor-or-self" direction
7596 * he ancestor-or-self axis contains the context node and ancestors of
7597 * the context node in reverse document order; thus the context node is
7598 * the first node on the axis, and the context node's parent the second;
7599 * parent here is defined the same as with the parent axis.
7600 *
7601 * Returns the next element following that axis
7602 */
7603xmlNodePtr
7604xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007605 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007606 if (cur == NULL)
7607 return(ctxt->context->node);
7608 return(xmlXPathNextAncestor(ctxt, cur));
7609}
7610
7611/**
7612 * xmlXPathNextFollowingSibling:
7613 * @ctxt: the XPath Parser context
7614 * @cur: the current node in the traversal
7615 *
7616 * Traversal function for the "following-sibling" direction
7617 * The following-sibling axis contains the following siblings of the context
7618 * node in document order.
7619 *
7620 * Returns the next element following that axis
7621 */
7622xmlNodePtr
7623xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007624 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007625 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7626 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7627 return(NULL);
7628 if (cur == (xmlNodePtr) ctxt->context->doc)
7629 return(NULL);
7630 if (cur == NULL)
7631 return(ctxt->context->node->next);
7632 return(cur->next);
7633}
7634
7635/**
7636 * xmlXPathNextPrecedingSibling:
7637 * @ctxt: the XPath Parser context
7638 * @cur: the current node in the traversal
7639 *
7640 * Traversal function for the "preceding-sibling" direction
7641 * The preceding-sibling axis contains the preceding siblings of the context
7642 * node in reverse document order; the first preceding sibling is first on the
7643 * axis; the sibling preceding that node is the second on the axis and so on.
7644 *
7645 * Returns the next element following that axis
7646 */
7647xmlNodePtr
7648xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007649 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007650 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7651 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7652 return(NULL);
7653 if (cur == (xmlNodePtr) ctxt->context->doc)
7654 return(NULL);
7655 if (cur == NULL)
7656 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007657 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7658 cur = cur->prev;
7659 if (cur == NULL)
7660 return(ctxt->context->node->prev);
7661 }
Owen Taylor3473f882001-02-23 17:55:21 +00007662 return(cur->prev);
7663}
7664
7665/**
7666 * xmlXPathNextFollowing:
7667 * @ctxt: the XPath Parser context
7668 * @cur: the current node in the traversal
7669 *
7670 * Traversal function for the "following" direction
7671 * The following axis contains all nodes in the same document as the context
7672 * node that are after the context node in document order, excluding any
7673 * descendants and excluding attribute nodes and namespace nodes; the nodes
7674 * are ordered in document order
7675 *
7676 * Returns the next element following that axis
7677 */
7678xmlNodePtr
7679xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007680 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007681 if (cur != NULL && cur->children != NULL)
7682 return cur->children ;
7683 if (cur == NULL) cur = ctxt->context->node;
7684 if (cur == NULL) return(NULL) ; /* ERROR */
7685 if (cur->next != NULL) return(cur->next) ;
7686 do {
7687 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007688 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007689 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7690 if (cur->next != NULL) return(cur->next);
7691 } while (cur != NULL);
7692 return(cur);
7693}
7694
7695/*
7696 * xmlXPathIsAncestor:
7697 * @ancestor: the ancestor node
7698 * @node: the current node
7699 *
7700 * Check that @ancestor is a @node's ancestor
7701 *
7702 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7703 */
7704static int
7705xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7706 if ((ancestor == NULL) || (node == NULL)) return(0);
7707 /* nodes need to be in the same document */
7708 if (ancestor->doc != node->doc) return(0);
7709 /* avoid searching if ancestor or node is the root node */
7710 if (ancestor == (xmlNodePtr) node->doc) return(1);
7711 if (node == (xmlNodePtr) ancestor->doc) return(0);
7712 while (node->parent != NULL) {
7713 if (node->parent == ancestor)
7714 return(1);
7715 node = node->parent;
7716 }
7717 return(0);
7718}
7719
7720/**
7721 * xmlXPathNextPreceding:
7722 * @ctxt: the XPath Parser context
7723 * @cur: the current node in the traversal
7724 *
7725 * Traversal function for the "preceding" direction
7726 * the preceding axis contains all nodes in the same document as the context
7727 * node that are before the context node in document order, excluding any
7728 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7729 * ordered in reverse document order
7730 *
7731 * Returns the next element following that axis
7732 */
7733xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00007734xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7735{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007736 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007737 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007738 cur = ctxt->context->node;
7739 if (cur == NULL)
7740 return (NULL);
7741 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7742 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00007743 do {
7744 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007745 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7746 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007747 }
7748
7749 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007750 if (cur == NULL)
7751 return (NULL);
7752 if (cur == ctxt->context->doc->children)
7753 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007754 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007755 return (cur);
7756}
7757
7758/**
7759 * xmlXPathNextPrecedingInternal:
7760 * @ctxt: the XPath Parser context
7761 * @cur: the current node in the traversal
7762 *
7763 * Traversal function for the "preceding" direction
7764 * the preceding axis contains all nodes in the same document as the context
7765 * node that are before the context node in document order, excluding any
7766 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7767 * ordered in reverse document order
7768 * This is a faster implementation but internal only since it requires a
7769 * state kept in the parser context: ctxt->ancestor.
7770 *
7771 * Returns the next element following that axis
7772 */
7773static xmlNodePtr
7774xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7775 xmlNodePtr cur)
7776{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007777 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007778 if (cur == NULL) {
7779 cur = ctxt->context->node;
7780 if (cur == NULL)
7781 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00007782 if (cur->type == XML_NAMESPACE_DECL)
7783 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007784 ctxt->ancestor = cur->parent;
7785 }
7786 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7787 cur = cur->prev;
7788 while (cur->prev == NULL) {
7789 cur = cur->parent;
7790 if (cur == NULL)
7791 return (NULL);
7792 if (cur == ctxt->context->doc->children)
7793 return (NULL);
7794 if (cur != ctxt->ancestor)
7795 return (cur);
7796 ctxt->ancestor = cur->parent;
7797 }
7798 cur = cur->prev;
7799 while (cur->last != NULL)
7800 cur = cur->last;
7801 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007802}
7803
7804/**
7805 * xmlXPathNextNamespace:
7806 * @ctxt: the XPath Parser context
7807 * @cur: the current attribute in the traversal
7808 *
7809 * Traversal function for the "namespace" direction
7810 * the namespace axis contains the namespace nodes of the context node;
7811 * the order of nodes on this axis is implementation-defined; the axis will
7812 * be empty unless the context node is an element
7813 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007814 * We keep the XML namespace node at the end of the list.
7815 *
Owen Taylor3473f882001-02-23 17:55:21 +00007816 * Returns the next element following that axis
7817 */
7818xmlNodePtr
7819xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007820 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007821 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00007822 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007823 if (ctxt->context->tmpNsList != NULL)
7824 xmlFree(ctxt->context->tmpNsList);
7825 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00007826 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007827 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007828 if (ctxt->context->tmpNsList != NULL) {
7829 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7830 ctxt->context->tmpNsNr++;
7831 }
7832 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007833 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007834 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00007835 if (ctxt->context->tmpNsNr > 0) {
7836 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7837 } else {
7838 if (ctxt->context->tmpNsList != NULL)
7839 xmlFree(ctxt->context->tmpNsList);
7840 ctxt->context->tmpNsList = NULL;
7841 return(NULL);
7842 }
Owen Taylor3473f882001-02-23 17:55:21 +00007843}
7844
7845/**
7846 * xmlXPathNextAttribute:
7847 * @ctxt: the XPath Parser context
7848 * @cur: the current attribute in the traversal
7849 *
7850 * Traversal function for the "attribute" direction
7851 * TODO: support DTD inherited default attributes
7852 *
7853 * Returns the next element following that axis
7854 */
7855xmlNodePtr
7856xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007857 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00007858 if (ctxt->context->node == NULL)
7859 return(NULL);
7860 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7861 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007862 if (cur == NULL) {
7863 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7864 return(NULL);
7865 return((xmlNodePtr)ctxt->context->node->properties);
7866 }
7867 return((xmlNodePtr)cur->next);
7868}
7869
7870/************************************************************************
7871 * *
7872 * NodeTest Functions *
7873 * *
7874 ************************************************************************/
7875
Owen Taylor3473f882001-02-23 17:55:21 +00007876#define IS_FUNCTION 200
7877
Owen Taylor3473f882001-02-23 17:55:21 +00007878
7879/************************************************************************
7880 * *
7881 * Implicit tree core function library *
7882 * *
7883 ************************************************************************/
7884
7885/**
7886 * xmlXPathRoot:
7887 * @ctxt: the XPath Parser context
7888 *
7889 * Initialize the context to the root of the document
7890 */
7891void
7892xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007893 if ((ctxt == NULL) || (ctxt->context == NULL))
7894 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007895 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007896 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7897 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00007898}
7899
7900/************************************************************************
7901 * *
7902 * The explicit core function library *
7903 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7904 * *
7905 ************************************************************************/
7906
7907
7908/**
7909 * xmlXPathLastFunction:
7910 * @ctxt: the XPath Parser context
7911 * @nargs: the number of arguments
7912 *
7913 * Implement the last() XPath function
7914 * number last()
7915 * The last function returns the number of nodes in the context node list.
7916 */
7917void
7918xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7919 CHECK_ARITY(0);
7920 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007921 valuePush(ctxt,
7922 xmlXPathCacheNewFloat(ctxt->context,
7923 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00007924#ifdef DEBUG_EXPR
7925 xmlGenericError(xmlGenericErrorContext,
7926 "last() : %d\n", ctxt->context->contextSize);
7927#endif
7928 } else {
7929 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7930 }
7931}
7932
7933/**
7934 * xmlXPathPositionFunction:
7935 * @ctxt: the XPath Parser context
7936 * @nargs: the number of arguments
7937 *
7938 * Implement the position() XPath function
7939 * number position()
7940 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007941 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00007942 * will be equal to last().
7943 */
7944void
7945xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7946 CHECK_ARITY(0);
7947 if (ctxt->context->proximityPosition >= 0) {
7948 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007949 xmlXPathCacheNewFloat(ctxt->context,
7950 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00007951#ifdef DEBUG_EXPR
7952 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
7953 ctxt->context->proximityPosition);
7954#endif
7955 } else {
7956 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7957 }
7958}
7959
7960/**
7961 * xmlXPathCountFunction:
7962 * @ctxt: the XPath Parser context
7963 * @nargs: the number of arguments
7964 *
7965 * Implement the count() XPath function
7966 * number count(node-set)
7967 */
7968void
7969xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7970 xmlXPathObjectPtr cur;
7971
7972 CHECK_ARITY(1);
7973 if ((ctxt->value == NULL) ||
7974 ((ctxt->value->type != XPATH_NODESET) &&
7975 (ctxt->value->type != XPATH_XSLT_TREE)))
7976 XP_ERROR(XPATH_INVALID_TYPE);
7977 cur = valuePop(ctxt);
7978
Daniel Veillard911f49a2001-04-07 15:39:35 +00007979 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007980 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00007981 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007982 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
7983 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00007984 } else {
7985 if ((cur->nodesetval->nodeNr != 1) ||
7986 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007987 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00007988 } else {
7989 xmlNodePtr tmp;
7990 int i = 0;
7991
7992 tmp = cur->nodesetval->nodeTab[0];
7993 if (tmp != NULL) {
7994 tmp = tmp->children;
7995 while (tmp != NULL) {
7996 tmp = tmp->next;
7997 i++;
7998 }
7999 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008000 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008001 }
8002 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008003 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008004}
8005
8006/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008007 * xmlXPathGetElementsByIds:
8008 * @doc: the document
8009 * @ids: a whitespace separated list of IDs
8010 *
8011 * Selects elements by their unique ID.
8012 *
8013 * Returns a node-set of selected elements.
8014 */
8015static xmlNodeSetPtr
8016xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8017 xmlNodeSetPtr ret;
8018 const xmlChar *cur = ids;
8019 xmlChar *ID;
8020 xmlAttrPtr attr;
8021 xmlNodePtr elem = NULL;
8022
Daniel Veillard7a985a12003-07-06 17:57:42 +00008023 if (ids == NULL) return(NULL);
8024
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008025 ret = xmlXPathNodeSetCreate(NULL);
8026
William M. Brack76e95df2003-10-18 16:20:14 +00008027 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008028 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008029 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008030 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008031
8032 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008033 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008034 /*
8035 * We used to check the fact that the value passed
8036 * was an NCName, but this generated much troubles for
8037 * me and Aleksey Sanin, people blatantly violated that
8038 * constaint, like Visa3D spec.
8039 * if (xmlValidateNCName(ID, 1) == 0)
8040 */
8041 attr = xmlGetID(doc, ID);
8042 if (attr != NULL) {
8043 if (attr->type == XML_ATTRIBUTE_NODE)
8044 elem = attr->parent;
8045 else if (attr->type == XML_ELEMENT_NODE)
8046 elem = (xmlNodePtr) attr;
8047 else
8048 elem = NULL;
8049 if (elem != NULL)
8050 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008051 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008052 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008053 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008054
William M. Brack76e95df2003-10-18 16:20:14 +00008055 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008056 ids = cur;
8057 }
8058 return(ret);
8059}
8060
8061/**
Owen Taylor3473f882001-02-23 17:55:21 +00008062 * xmlXPathIdFunction:
8063 * @ctxt: the XPath Parser context
8064 * @nargs: the number of arguments
8065 *
8066 * Implement the id() XPath function
8067 * node-set id(object)
8068 * The id function selects elements by their unique ID
8069 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8070 * then the result is the union of the result of applying id to the
8071 * string value of each of the nodes in the argument node-set. When the
8072 * argument to id is of any other type, the argument is converted to a
8073 * string as if by a call to the string function; the string is split
8074 * into a whitespace-separated list of tokens (whitespace is any sequence
8075 * of characters matching the production S); the result is a node-set
8076 * containing the elements in the same document as the context node that
8077 * have a unique ID equal to any of the tokens in the list.
8078 */
8079void
8080xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008081 xmlChar *tokens;
8082 xmlNodeSetPtr ret;
8083 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008084
8085 CHECK_ARITY(1);
8086 obj = valuePop(ctxt);
8087 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008088 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008089 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008090 int i;
8091
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008092 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008093
Daniel Veillard911f49a2001-04-07 15:39:35 +00008094 if (obj->nodesetval != NULL) {
8095 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008096 tokens =
8097 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8098 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8099 ret = xmlXPathNodeSetMerge(ret, ns);
8100 xmlXPathFreeNodeSet(ns);
8101 if (tokens != NULL)
8102 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008103 }
Owen Taylor3473f882001-02-23 17:55:21 +00008104 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008105 xmlXPathReleaseObject(ctxt->context, obj);
8106 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008107 return;
8108 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008109 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008110 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008111 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8112 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008113 return;
8114}
8115
8116/**
8117 * xmlXPathLocalNameFunction:
8118 * @ctxt: the XPath Parser context
8119 * @nargs: the number of arguments
8120 *
8121 * Implement the local-name() XPath function
8122 * string local-name(node-set?)
8123 * The local-name function returns a string containing the local part
8124 * of the name of the node in the argument node-set that is first in
8125 * document order. If the node-set is empty or the first node has no
8126 * name, an empty string is returned. If the argument is omitted it
8127 * defaults to the context node.
8128 */
8129void
8130xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8131 xmlXPathObjectPtr cur;
8132
Daniel Veillarda82b1822004-11-08 16:24:57 +00008133 if (ctxt == NULL) return;
8134
Owen Taylor3473f882001-02-23 17:55:21 +00008135 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008136 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8137 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008138 nargs = 1;
8139 }
8140
8141 CHECK_ARITY(1);
8142 if ((ctxt->value == NULL) ||
8143 ((ctxt->value->type != XPATH_NODESET) &&
8144 (ctxt->value->type != XPATH_XSLT_TREE)))
8145 XP_ERROR(XPATH_INVALID_TYPE);
8146 cur = valuePop(ctxt);
8147
Daniel Veillard911f49a2001-04-07 15:39:35 +00008148 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008149 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008150 } else {
8151 int i = 0; /* Should be first in document order !!!!! */
8152 switch (cur->nodesetval->nodeTab[i]->type) {
8153 case XML_ELEMENT_NODE:
8154 case XML_ATTRIBUTE_NODE:
8155 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008156 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008157 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008158 else
8159 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008160 xmlXPathCacheNewString(ctxt->context,
8161 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008162 break;
8163 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008164 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008165 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8166 break;
8167 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008168 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008169 }
8170 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008171 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008172}
8173
8174/**
8175 * xmlXPathNamespaceURIFunction:
8176 * @ctxt: the XPath Parser context
8177 * @nargs: the number of arguments
8178 *
8179 * Implement the namespace-uri() XPath function
8180 * string namespace-uri(node-set?)
8181 * The namespace-uri function returns a string containing the
8182 * namespace URI of the expanded name of the node in the argument
8183 * node-set that is first in document order. If the node-set is empty,
8184 * the first node has no name, or the expanded name has no namespace
8185 * URI, an empty string is returned. If the argument is omitted it
8186 * defaults to the context node.
8187 */
8188void
8189xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8190 xmlXPathObjectPtr cur;
8191
Daniel Veillarda82b1822004-11-08 16:24:57 +00008192 if (ctxt == NULL) return;
8193
Owen Taylor3473f882001-02-23 17:55:21 +00008194 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008195 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8196 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008197 nargs = 1;
8198 }
8199 CHECK_ARITY(1);
8200 if ((ctxt->value == NULL) ||
8201 ((ctxt->value->type != XPATH_NODESET) &&
8202 (ctxt->value->type != XPATH_XSLT_TREE)))
8203 XP_ERROR(XPATH_INVALID_TYPE);
8204 cur = valuePop(ctxt);
8205
Daniel Veillard911f49a2001-04-07 15:39:35 +00008206 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008207 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008208 } else {
8209 int i = 0; /* Should be first in document order !!!!! */
8210 switch (cur->nodesetval->nodeTab[i]->type) {
8211 case XML_ELEMENT_NODE:
8212 case XML_ATTRIBUTE_NODE:
8213 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008214 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008215 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008216 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008217 cur->nodesetval->nodeTab[i]->ns->href));
8218 break;
8219 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008220 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008221 }
8222 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008223 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008224}
8225
8226/**
8227 * xmlXPathNameFunction:
8228 * @ctxt: the XPath Parser context
8229 * @nargs: the number of arguments
8230 *
8231 * Implement the name() XPath function
8232 * string name(node-set?)
8233 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008234 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008235 * order. The QName must represent the name with respect to the namespace
8236 * declarations in effect on the node whose name is being represented.
8237 * Typically, this will be the form in which the name occurred in the XML
8238 * source. This need not be the case if there are namespace declarations
8239 * in effect on the node that associate multiple prefixes with the same
8240 * namespace. However, an implementation may include information about
8241 * the original prefix in its representation of nodes; in this case, an
8242 * implementation can ensure that the returned string is always the same
8243 * as the QName used in the XML source. If the argument it omitted it
8244 * defaults to the context node.
8245 * Libxml keep the original prefix so the "real qualified name" used is
8246 * returned.
8247 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008248static void
Daniel Veillard04383752001-07-08 14:27:15 +00008249xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8250{
Owen Taylor3473f882001-02-23 17:55:21 +00008251 xmlXPathObjectPtr cur;
8252
8253 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008254 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8255 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008256 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008257 }
8258
8259 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008260 if ((ctxt->value == NULL) ||
8261 ((ctxt->value->type != XPATH_NODESET) &&
8262 (ctxt->value->type != XPATH_XSLT_TREE)))
8263 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008264 cur = valuePop(ctxt);
8265
Daniel Veillard911f49a2001-04-07 15:39:35 +00008266 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008267 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008268 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008269 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008270
Daniel Veillard04383752001-07-08 14:27:15 +00008271 switch (cur->nodesetval->nodeTab[i]->type) {
8272 case XML_ELEMENT_NODE:
8273 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008274 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008275 valuePush(ctxt,
8276 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008277 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8278 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008279 valuePush(ctxt,
8280 xmlXPathCacheNewString(ctxt->context,
8281 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008282 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008283 xmlChar *fullname;
8284
8285 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8286 cur->nodesetval->nodeTab[i]->ns->prefix,
8287 NULL, 0);
8288 if (fullname == cur->nodesetval->nodeTab[i]->name)
8289 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8290 if (fullname == NULL) {
8291 XP_ERROR(XPATH_MEMORY_ERROR);
8292 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008293 valuePush(ctxt, xmlXPathCacheWrapString(
8294 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008295 }
8296 break;
8297 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008298 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8299 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008300 xmlXPathLocalNameFunction(ctxt, 1);
8301 }
Owen Taylor3473f882001-02-23 17:55:21 +00008302 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008303 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008304}
8305
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008306
8307/**
Owen Taylor3473f882001-02-23 17:55:21 +00008308 * xmlXPathStringFunction:
8309 * @ctxt: the XPath Parser context
8310 * @nargs: the number of arguments
8311 *
8312 * Implement the string() XPath function
8313 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008314 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008315 * - A node-set is converted to a string by returning the value of
8316 * the node in the node-set that is first in document order.
8317 * If the node-set is empty, an empty string is returned.
8318 * - A number is converted to a string as follows
8319 * + NaN is converted to the string NaN
8320 * + positive zero is converted to the string 0
8321 * + negative zero is converted to the string 0
8322 * + positive infinity is converted to the string Infinity
8323 * + negative infinity is converted to the string -Infinity
8324 * + if the number is an integer, the number is represented in
8325 * decimal form as a Number with no decimal point and no leading
8326 * zeros, preceded by a minus sign (-) if the number is negative
8327 * + otherwise, the number is represented in decimal form as a
8328 * Number including a decimal point with at least one digit
8329 * before the decimal point and at least one digit after the
8330 * decimal point, preceded by a minus sign (-) if the number
8331 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008332 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * before the decimal point; beyond the one required digit
8334 * after the decimal point there must be as many, but only as
8335 * many, more digits as are needed to uniquely distinguish the
8336 * number from all other IEEE 754 numeric values.
8337 * - The boolean false value is converted to the string false.
8338 * The boolean true value is converted to the string true.
8339 *
8340 * If the argument is omitted, it defaults to a node-set with the
8341 * context node as its only member.
8342 */
8343void
8344xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8345 xmlXPathObjectPtr cur;
8346
Daniel Veillarda82b1822004-11-08 16:24:57 +00008347 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008348 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008349 valuePush(ctxt,
8350 xmlXPathCacheWrapString(ctxt->context,
8351 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008352 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008353 }
8354
8355 CHECK_ARITY(1);
8356 cur = valuePop(ctxt);
8357 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008358 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008359}
8360
8361/**
8362 * xmlXPathStringLengthFunction:
8363 * @ctxt: the XPath Parser context
8364 * @nargs: the number of arguments
8365 *
8366 * Implement the string-length() XPath function
8367 * number string-length(string?)
8368 * The string-length returns the number of characters in the string
8369 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8370 * the context node converted to a string, in other words the value
8371 * of the context node.
8372 */
8373void
8374xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8375 xmlXPathObjectPtr cur;
8376
8377 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008378 if ((ctxt == NULL) || (ctxt->context == NULL))
8379 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008380 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008381 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008382 } else {
8383 xmlChar *content;
8384
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008385 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008386 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8387 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008388 xmlFree(content);
8389 }
8390 return;
8391 }
8392 CHECK_ARITY(1);
8393 CAST_TO_STRING;
8394 CHECK_TYPE(XPATH_STRING);
8395 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008396 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8397 xmlUTF8Strlen(cur->stringval)));
8398 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008399}
8400
8401/**
8402 * xmlXPathConcatFunction:
8403 * @ctxt: the XPath Parser context
8404 * @nargs: the number of arguments
8405 *
8406 * Implement the concat() XPath function
8407 * string concat(string, string, string*)
8408 * The concat function returns the concatenation of its arguments.
8409 */
8410void
8411xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8412 xmlXPathObjectPtr cur, newobj;
8413 xmlChar *tmp;
8414
Daniel Veillarda82b1822004-11-08 16:24:57 +00008415 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008416 if (nargs < 2) {
8417 CHECK_ARITY(2);
8418 }
8419
8420 CAST_TO_STRING;
8421 cur = valuePop(ctxt);
8422 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008423 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008424 return;
8425 }
8426 nargs--;
8427
8428 while (nargs > 0) {
8429 CAST_TO_STRING;
8430 newobj = valuePop(ctxt);
8431 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008432 xmlXPathReleaseObject(ctxt->context, newobj);
8433 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008434 XP_ERROR(XPATH_INVALID_TYPE);
8435 }
8436 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8437 newobj->stringval = cur->stringval;
8438 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008439 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008440 nargs--;
8441 }
8442 valuePush(ctxt, cur);
8443}
8444
8445/**
8446 * xmlXPathContainsFunction:
8447 * @ctxt: the XPath Parser context
8448 * @nargs: the number of arguments
8449 *
8450 * Implement the contains() XPath function
8451 * boolean contains(string, string)
8452 * The contains function returns true if the first argument string
8453 * contains the second argument string, and otherwise returns false.
8454 */
8455void
8456xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8457 xmlXPathObjectPtr hay, needle;
8458
8459 CHECK_ARITY(2);
8460 CAST_TO_STRING;
8461 CHECK_TYPE(XPATH_STRING);
8462 needle = valuePop(ctxt);
8463 CAST_TO_STRING;
8464 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008465
Owen Taylor3473f882001-02-23 17:55:21 +00008466 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008467 xmlXPathReleaseObject(ctxt->context, hay);
8468 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008469 XP_ERROR(XPATH_INVALID_TYPE);
8470 }
8471 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008472 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008473 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008474 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8475 xmlXPathReleaseObject(ctxt->context, hay);
8476 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008477}
8478
8479/**
8480 * xmlXPathStartsWithFunction:
8481 * @ctxt: the XPath Parser context
8482 * @nargs: the number of arguments
8483 *
8484 * Implement the starts-with() XPath function
8485 * boolean starts-with(string, string)
8486 * The starts-with function returns true if the first argument string
8487 * starts with the second argument string, and otherwise returns false.
8488 */
8489void
8490xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8491 xmlXPathObjectPtr hay, needle;
8492 int n;
8493
8494 CHECK_ARITY(2);
8495 CAST_TO_STRING;
8496 CHECK_TYPE(XPATH_STRING);
8497 needle = valuePop(ctxt);
8498 CAST_TO_STRING;
8499 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008500
Owen Taylor3473f882001-02-23 17:55:21 +00008501 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008502 xmlXPathReleaseObject(ctxt->context, hay);
8503 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008504 XP_ERROR(XPATH_INVALID_TYPE);
8505 }
8506 n = xmlStrlen(needle->stringval);
8507 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008508 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008509 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008510 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8511 xmlXPathReleaseObject(ctxt->context, hay);
8512 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008513}
8514
8515/**
8516 * xmlXPathSubstringFunction:
8517 * @ctxt: the XPath Parser context
8518 * @nargs: the number of arguments
8519 *
8520 * Implement the substring() XPath function
8521 * string substring(string, number, number?)
8522 * The substring function returns the substring of the first argument
8523 * starting at the position specified in the second argument with
8524 * length specified in the third argument. For example,
8525 * substring("12345",2,3) returns "234". If the third argument is not
8526 * specified, it returns the substring starting at the position specified
8527 * in the second argument and continuing to the end of the string. For
8528 * example, substring("12345",2) returns "2345". More precisely, each
8529 * character in the string (see [3.6 Strings]) is considered to have a
8530 * numeric position: the position of the first character is 1, the position
8531 * of the second character is 2 and so on. The returned substring contains
8532 * those characters for which the position of the character is greater than
8533 * or equal to the second argument and, if the third argument is specified,
8534 * less than the sum of the second and third arguments; the comparisons
8535 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8536 * - substring("12345", 1.5, 2.6) returns "234"
8537 * - substring("12345", 0, 3) returns "12"
8538 * - substring("12345", 0 div 0, 3) returns ""
8539 * - substring("12345", 1, 0 div 0) returns ""
8540 * - substring("12345", -42, 1 div 0) returns "12345"
8541 * - substring("12345", -1 div 0, 1 div 0) returns ""
8542 */
8543void
8544xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8545 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008546 double le=0, in;
8547 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008548 xmlChar *ret;
8549
Owen Taylor3473f882001-02-23 17:55:21 +00008550 if (nargs < 2) {
8551 CHECK_ARITY(2);
8552 }
8553 if (nargs > 3) {
8554 CHECK_ARITY(3);
8555 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008556 /*
8557 * take care of possible last (position) argument
8558 */
Owen Taylor3473f882001-02-23 17:55:21 +00008559 if (nargs == 3) {
8560 CAST_TO_NUMBER;
8561 CHECK_TYPE(XPATH_NUMBER);
8562 len = valuePop(ctxt);
8563 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008564 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008565 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008566
Owen Taylor3473f882001-02-23 17:55:21 +00008567 CAST_TO_NUMBER;
8568 CHECK_TYPE(XPATH_NUMBER);
8569 start = valuePop(ctxt);
8570 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008571 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008572 CAST_TO_STRING;
8573 CHECK_TYPE(XPATH_STRING);
8574 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008575 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008576
Daniel Veillard97ac1312001-05-30 19:14:17 +00008577 /*
8578 * If last pos not present, calculate last position
8579 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008580 if (nargs != 3) {
8581 le = (double)m;
8582 if (in < 1.0)
8583 in = 1.0;
8584 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008585
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008586 /* Need to check for the special cases where either
8587 * the index is NaN, the length is NaN, or both
8588 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008589 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008590 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008591 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008592 * To meet the requirements of the spec, the arguments
8593 * must be converted to integer format before
8594 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008595 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008596 * First we go to integer form, rounding up
8597 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008598 */
8599 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008600 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008601
Daniel Veillard9e412302002-06-10 15:59:44 +00008602 if (xmlXPathIsInf(le) == 1) {
8603 l = m;
8604 if (i < 1)
8605 i = 1;
8606 }
8607 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8608 l = 0;
8609 else {
8610 l = (int) le;
8611 if (((double)l)+0.5 <= le) l++;
8612 }
8613
8614 /* Now we normalize inidices */
8615 i -= 1;
8616 l += i;
8617 if (i < 0)
8618 i = 0;
8619 if (l > m)
8620 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00008621
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008622 /* number of chars to copy */
8623 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00008624
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008625 ret = xmlUTF8Strsub(str->stringval, i, l);
8626 }
8627 else {
8628 ret = NULL;
8629 }
Owen Taylor3473f882001-02-23 17:55:21 +00008630 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008631 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008632 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008633 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008634 xmlFree(ret);
8635 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008636 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00008637}
8638
8639/**
8640 * xmlXPathSubstringBeforeFunction:
8641 * @ctxt: the XPath Parser context
8642 * @nargs: the number of arguments
8643 *
8644 * Implement the substring-before() XPath function
8645 * string substring-before(string, string)
8646 * The substring-before function returns the substring of the first
8647 * argument string that precedes the first occurrence of the second
8648 * argument string in the first argument string, or the empty string
8649 * if the first argument string does not contain the second argument
8650 * string. For example, substring-before("1999/04/01","/") returns 1999.
8651 */
8652void
8653xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8654 xmlXPathObjectPtr str;
8655 xmlXPathObjectPtr find;
8656 xmlBufferPtr target;
8657 const xmlChar *point;
8658 int offset;
8659
8660 CHECK_ARITY(2);
8661 CAST_TO_STRING;
8662 find = valuePop(ctxt);
8663 CAST_TO_STRING;
8664 str = valuePop(ctxt);
8665
8666 target = xmlBufferCreate();
8667 if (target) {
8668 point = xmlStrstr(str->stringval, find->stringval);
8669 if (point) {
8670 offset = (int)(point - str->stringval);
8671 xmlBufferAdd(target, str->stringval, offset);
8672 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008673 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8674 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008675 xmlBufferFree(target);
8676 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008677 xmlXPathReleaseObject(ctxt->context, str);
8678 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008679}
8680
8681/**
8682 * xmlXPathSubstringAfterFunction:
8683 * @ctxt: the XPath Parser context
8684 * @nargs: the number of arguments
8685 *
8686 * Implement the substring-after() XPath function
8687 * string substring-after(string, string)
8688 * The substring-after function returns the substring of the first
8689 * argument string that follows the first occurrence of the second
8690 * argument string in the first argument string, or the empty stringi
8691 * if the first argument string does not contain the second argument
8692 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8693 * and substring-after("1999/04/01","19") returns 99/04/01.
8694 */
8695void
8696xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8697 xmlXPathObjectPtr str;
8698 xmlXPathObjectPtr find;
8699 xmlBufferPtr target;
8700 const xmlChar *point;
8701 int offset;
8702
8703 CHECK_ARITY(2);
8704 CAST_TO_STRING;
8705 find = valuePop(ctxt);
8706 CAST_TO_STRING;
8707 str = valuePop(ctxt);
8708
8709 target = xmlBufferCreate();
8710 if (target) {
8711 point = xmlStrstr(str->stringval, find->stringval);
8712 if (point) {
8713 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
8714 xmlBufferAdd(target, &str->stringval[offset],
8715 xmlStrlen(str->stringval) - offset);
8716 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008717 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8718 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008719 xmlBufferFree(target);
8720 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008721 xmlXPathReleaseObject(ctxt->context, str);
8722 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008723}
8724
8725/**
8726 * xmlXPathNormalizeFunction:
8727 * @ctxt: the XPath Parser context
8728 * @nargs: the number of arguments
8729 *
8730 * Implement the normalize-space() XPath function
8731 * string normalize-space(string?)
8732 * The normalize-space function returns the argument string with white
8733 * space normalized by stripping leading and trailing whitespace
8734 * and replacing sequences of whitespace characters by a single
8735 * space. Whitespace characters are the same allowed by the S production
8736 * in XML. If the argument is omitted, it defaults to the context
8737 * node converted to a string, in other words the value of the context node.
8738 */
8739void
8740xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8741 xmlXPathObjectPtr obj = NULL;
8742 xmlChar *source = NULL;
8743 xmlBufferPtr target;
8744 xmlChar blank;
8745
Daniel Veillarda82b1822004-11-08 16:24:57 +00008746 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008747 if (nargs == 0) {
8748 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008749 valuePush(ctxt,
8750 xmlXPathCacheWrapString(ctxt->context,
8751 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00008752 nargs = 1;
8753 }
8754
8755 CHECK_ARITY(1);
8756 CAST_TO_STRING;
8757 CHECK_TYPE(XPATH_STRING);
8758 obj = valuePop(ctxt);
8759 source = obj->stringval;
8760
8761 target = xmlBufferCreate();
8762 if (target && source) {
8763
8764 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00008765 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00008766 source++;
8767
8768 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8769 blank = 0;
8770 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00008771 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008772 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00008773 } else {
8774 if (blank) {
8775 xmlBufferAdd(target, &blank, 1);
8776 blank = 0;
8777 }
8778 xmlBufferAdd(target, source, 1);
8779 }
8780 source++;
8781 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008782 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8783 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008784 xmlBufferFree(target);
8785 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008786 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008787}
8788
8789/**
8790 * xmlXPathTranslateFunction:
8791 * @ctxt: the XPath Parser context
8792 * @nargs: the number of arguments
8793 *
8794 * Implement the translate() XPath function
8795 * string translate(string, string, string)
8796 * The translate function returns the first argument string with
8797 * occurrences of characters in the second argument string replaced
8798 * by the character at the corresponding position in the third argument
8799 * string. For example, translate("bar","abc","ABC") returns the string
8800 * BAr. If there is a character in the second argument string with no
8801 * character at a corresponding position in the third argument string
8802 * (because the second argument string is longer than the third argument
8803 * string), then occurrences of that character in the first argument
8804 * string are removed. For example, translate("--aaa--","abc-","ABC")
8805 * returns "AAA". If a character occurs more than once in second
8806 * argument string, then the first occurrence determines the replacement
8807 * character. If the third argument string is longer than the second
8808 * argument string, then excess characters are ignored.
8809 */
8810void
8811xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00008812 xmlXPathObjectPtr str;
8813 xmlXPathObjectPtr from;
8814 xmlXPathObjectPtr to;
8815 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008816 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008817 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00008818 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008819 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00008820
Daniel Veillarde043ee12001-04-16 14:08:07 +00008821 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00008822
Daniel Veillarde043ee12001-04-16 14:08:07 +00008823 CAST_TO_STRING;
8824 to = valuePop(ctxt);
8825 CAST_TO_STRING;
8826 from = valuePop(ctxt);
8827 CAST_TO_STRING;
8828 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008829
Daniel Veillarde043ee12001-04-16 14:08:07 +00008830 target = xmlBufferCreate();
8831 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008832 max = xmlUTF8Strlen(to->stringval);
8833 for (cptr = str->stringval; (ch=*cptr); ) {
8834 offset = xmlUTF8Strloc(from->stringval, cptr);
8835 if (offset >= 0) {
8836 if (offset < max) {
8837 point = xmlUTF8Strpos(to->stringval, offset);
8838 if (point)
8839 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
8840 }
8841 } else
8842 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8843
8844 /* Step to next character in input */
8845 cptr++;
8846 if ( ch & 0x80 ) {
8847 /* if not simple ascii, verify proper format */
8848 if ( (ch & 0xc0) != 0xc0 ) {
8849 xmlGenericError(xmlGenericErrorContext,
8850 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8851 break;
8852 }
8853 /* then skip over remaining bytes for this char */
8854 while ( (ch <<= 1) & 0x80 )
8855 if ( (*cptr++ & 0xc0) != 0x80 ) {
8856 xmlGenericError(xmlGenericErrorContext,
8857 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8858 break;
8859 }
8860 if (ch & 0x80) /* must have had error encountered */
8861 break;
8862 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00008863 }
Owen Taylor3473f882001-02-23 17:55:21 +00008864 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008865 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8866 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00008867 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008868 xmlXPathReleaseObject(ctxt->context, str);
8869 xmlXPathReleaseObject(ctxt->context, from);
8870 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00008871}
8872
8873/**
8874 * xmlXPathBooleanFunction:
8875 * @ctxt: the XPath Parser context
8876 * @nargs: the number of arguments
8877 *
8878 * Implement the boolean() XPath function
8879 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00008880 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008881 * - a number is true if and only if it is neither positive or
8882 * negative zero nor NaN
8883 * - a node-set is true if and only if it is non-empty
8884 * - a string is true if and only if its length is non-zero
8885 */
8886void
8887xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8888 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008889
8890 CHECK_ARITY(1);
8891 cur = valuePop(ctxt);
8892 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008893 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008894 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008895}
8896
8897/**
8898 * xmlXPathNotFunction:
8899 * @ctxt: the XPath Parser context
8900 * @nargs: the number of arguments
8901 *
8902 * Implement the not() XPath function
8903 * boolean not(boolean)
8904 * The not function returns true if its argument is false,
8905 * and false otherwise.
8906 */
8907void
8908xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8909 CHECK_ARITY(1);
8910 CAST_TO_BOOLEAN;
8911 CHECK_TYPE(XPATH_BOOLEAN);
8912 ctxt->value->boolval = ! ctxt->value->boolval;
8913}
8914
8915/**
8916 * xmlXPathTrueFunction:
8917 * @ctxt: the XPath Parser context
8918 * @nargs: the number of arguments
8919 *
8920 * Implement the true() XPath function
8921 * boolean true()
8922 */
8923void
8924xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8925 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008926 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008927}
8928
8929/**
8930 * xmlXPathFalseFunction:
8931 * @ctxt: the XPath Parser context
8932 * @nargs: the number of arguments
8933 *
8934 * Implement the false() XPath function
8935 * boolean false()
8936 */
8937void
8938xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008940 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008941}
8942
8943/**
8944 * xmlXPathLangFunction:
8945 * @ctxt: the XPath Parser context
8946 * @nargs: the number of arguments
8947 *
8948 * Implement the lang() XPath function
8949 * boolean lang(string)
8950 * The lang function returns true or false depending on whether the
8951 * language of the context node as specified by xml:lang attributes
8952 * is the same as or is a sublanguage of the language specified by
8953 * the argument string. The language of the context node is determined
8954 * by the value of the xml:lang attribute on the context node, or, if
8955 * the context node has no xml:lang attribute, by the value of the
8956 * xml:lang attribute on the nearest ancestor of the context node that
8957 * has an xml:lang attribute. If there is no such attribute, then lang
8958 * returns false. If there is such an attribute, then lang returns
8959 * true if the attribute value is equal to the argument ignoring case,
8960 * or if there is some suffix starting with - such that the attribute
8961 * value is equal to the argument ignoring that suffix of the attribute
8962 * value and ignoring case.
8963 */
8964void
8965xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00008966 xmlXPathObjectPtr val = NULL;
8967 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008968 const xmlChar *lang;
8969 int ret = 0;
8970 int i;
8971
8972 CHECK_ARITY(1);
8973 CAST_TO_STRING;
8974 CHECK_TYPE(XPATH_STRING);
8975 val = valuePop(ctxt);
8976 lang = val->stringval;
8977 theLang = xmlNodeGetLang(ctxt->context->node);
8978 if ((theLang != NULL) && (lang != NULL)) {
8979 for (i = 0;lang[i] != 0;i++)
8980 if (toupper(lang[i]) != toupper(theLang[i]))
8981 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00008982 if ((theLang[i] == 0) || (theLang[i] == '-'))
8983 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008984 }
8985not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00008986 if (theLang != NULL)
8987 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008988
8989 xmlXPathReleaseObject(ctxt->context, val);
8990 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008991}
8992
8993/**
8994 * xmlXPathNumberFunction:
8995 * @ctxt: the XPath Parser context
8996 * @nargs: the number of arguments
8997 *
8998 * Implement the number() XPath function
8999 * number number(object?)
9000 */
9001void
9002xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9003 xmlXPathObjectPtr cur;
9004 double res;
9005
Daniel Veillarda82b1822004-11-08 16:24:57 +00009006 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009007 if (nargs == 0) {
9008 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009009 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009010 } else {
9011 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9012
9013 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009014 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009015 xmlFree(content);
9016 }
9017 return;
9018 }
9019
9020 CHECK_ARITY(1);
9021 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009022 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009023}
9024
9025/**
9026 * xmlXPathSumFunction:
9027 * @ctxt: the XPath Parser context
9028 * @nargs: the number of arguments
9029 *
9030 * Implement the sum() XPath function
9031 * number sum(node-set)
9032 * The sum function returns the sum of the values of the nodes in
9033 * the argument node-set.
9034 */
9035void
9036xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9037 xmlXPathObjectPtr cur;
9038 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009039 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009040
9041 CHECK_ARITY(1);
9042 if ((ctxt->value == NULL) ||
9043 ((ctxt->value->type != XPATH_NODESET) &&
9044 (ctxt->value->type != XPATH_XSLT_TREE)))
9045 XP_ERROR(XPATH_INVALID_TYPE);
9046 cur = valuePop(ctxt);
9047
William M. Brack08171912003-12-29 02:52:11 +00009048 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009049 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9050 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009051 }
9052 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009053 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9054 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009055}
9056
William M. Brack3d426662005-04-19 14:40:28 +00009057/*
9058 * To assure working code on multiple platforms, we want to only depend
9059 * upon the characteristic truncation of converting a floating point value
9060 * to an integer. Unfortunately, because of the different storage sizes
9061 * of our internal floating point value (double) and integer (int), we
9062 * can't directly convert (see bug 301162). This macro is a messy
9063 * 'workaround'
9064 */
9065#define XTRUNC(f, v) \
9066 f = fmod((v), INT_MAX); \
9067 f = (v) - (f) + (double)((int)(f));
9068
Owen Taylor3473f882001-02-23 17:55:21 +00009069/**
9070 * xmlXPathFloorFunction:
9071 * @ctxt: the XPath Parser context
9072 * @nargs: the number of arguments
9073 *
9074 * Implement the floor() XPath function
9075 * number floor(number)
9076 * The floor function returns the largest (closest to positive infinity)
9077 * number that is not greater than the argument and that is an integer.
9078 */
9079void
9080xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009081 double f;
9082
Owen Taylor3473f882001-02-23 17:55:21 +00009083 CHECK_ARITY(1);
9084 CAST_TO_NUMBER;
9085 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009086
William M. Brack3d426662005-04-19 14:40:28 +00009087 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009088 if (f != ctxt->value->floatval) {
9089 if (ctxt->value->floatval > 0)
9090 ctxt->value->floatval = f;
9091 else
9092 ctxt->value->floatval = f - 1;
9093 }
Owen Taylor3473f882001-02-23 17:55:21 +00009094}
9095
9096/**
9097 * xmlXPathCeilingFunction:
9098 * @ctxt: the XPath Parser context
9099 * @nargs: the number of arguments
9100 *
9101 * Implement the ceiling() XPath function
9102 * number ceiling(number)
9103 * The ceiling function returns the smallest (closest to negative infinity)
9104 * number that is not less than the argument and that is an integer.
9105 */
9106void
9107xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9108 double f;
9109
9110 CHECK_ARITY(1);
9111 CAST_TO_NUMBER;
9112 CHECK_TYPE(XPATH_NUMBER);
9113
9114#if 0
9115 ctxt->value->floatval = ceil(ctxt->value->floatval);
9116#else
William M. Brack3d426662005-04-19 14:40:28 +00009117 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009118 if (f != ctxt->value->floatval) {
9119 if (ctxt->value->floatval > 0)
9120 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009121 else {
9122 if (ctxt->value->floatval < 0 && f == 0)
9123 ctxt->value->floatval = xmlXPathNZERO;
9124 else
9125 ctxt->value->floatval = f;
9126 }
9127
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009128 }
Owen Taylor3473f882001-02-23 17:55:21 +00009129#endif
9130}
9131
9132/**
9133 * xmlXPathRoundFunction:
9134 * @ctxt: the XPath Parser context
9135 * @nargs: the number of arguments
9136 *
9137 * Implement the round() XPath function
9138 * number round(number)
9139 * The round function returns the number that is closest to the
9140 * argument and that is an integer. If there are two such numbers,
9141 * then the one that is even is returned.
9142 */
9143void
9144xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9145 double f;
9146
9147 CHECK_ARITY(1);
9148 CAST_TO_NUMBER;
9149 CHECK_TYPE(XPATH_NUMBER);
9150
Daniel Veillardcda96922001-08-21 10:56:31 +00009151 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9152 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9153 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009154 (ctxt->value->floatval == 0.0))
9155 return;
9156
William M. Brack3d426662005-04-19 14:40:28 +00009157 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009158 if (ctxt->value->floatval < 0) {
9159 if (ctxt->value->floatval < f - 0.5)
9160 ctxt->value->floatval = f - 1;
9161 else
9162 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009163 if (ctxt->value->floatval == 0)
9164 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009165 } else {
9166 if (ctxt->value->floatval < f + 0.5)
9167 ctxt->value->floatval = f;
9168 else
9169 ctxt->value->floatval = f + 1;
9170 }
Owen Taylor3473f882001-02-23 17:55:21 +00009171}
9172
9173/************************************************************************
9174 * *
9175 * The Parser *
9176 * *
9177 ************************************************************************/
9178
9179/*
William M. Brack08171912003-12-29 02:52:11 +00009180 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009181 * implementation.
9182 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009183static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009185static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009186static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009187static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9188 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009189
9190/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009191 * xmlXPathCurrentChar:
9192 * @ctxt: the XPath parser context
9193 * @cur: pointer to the beginning of the char
9194 * @len: pointer to the length of the char read
9195 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009196 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009197 * bytes in the input buffer.
9198 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009199 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009200 */
9201
9202static int
9203xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9204 unsigned char c;
9205 unsigned int val;
9206 const xmlChar *cur;
9207
9208 if (ctxt == NULL)
9209 return(0);
9210 cur = ctxt->cur;
9211
9212 /*
9213 * We are supposed to handle UTF8, check it's valid
9214 * From rfc2044: encoding of the Unicode values on UTF-8:
9215 *
9216 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9217 * 0000 0000-0000 007F 0xxxxxxx
9218 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9219 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9220 *
9221 * Check for the 0x110000 limit too
9222 */
9223 c = *cur;
9224 if (c & 0x80) {
9225 if ((cur[1] & 0xc0) != 0x80)
9226 goto encoding_error;
9227 if ((c & 0xe0) == 0xe0) {
9228
9229 if ((cur[2] & 0xc0) != 0x80)
9230 goto encoding_error;
9231 if ((c & 0xf0) == 0xf0) {
9232 if (((c & 0xf8) != 0xf0) ||
9233 ((cur[3] & 0xc0) != 0x80))
9234 goto encoding_error;
9235 /* 4-byte code */
9236 *len = 4;
9237 val = (cur[0] & 0x7) << 18;
9238 val |= (cur[1] & 0x3f) << 12;
9239 val |= (cur[2] & 0x3f) << 6;
9240 val |= cur[3] & 0x3f;
9241 } else {
9242 /* 3-byte code */
9243 *len = 3;
9244 val = (cur[0] & 0xf) << 12;
9245 val |= (cur[1] & 0x3f) << 6;
9246 val |= cur[2] & 0x3f;
9247 }
9248 } else {
9249 /* 2-byte code */
9250 *len = 2;
9251 val = (cur[0] & 0x1f) << 6;
9252 val |= cur[1] & 0x3f;
9253 }
9254 if (!IS_CHAR(val)) {
9255 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9256 }
9257 return(val);
9258 } else {
9259 /* 1-byte code */
9260 *len = 1;
9261 return((int) *cur);
9262 }
9263encoding_error:
9264 /*
William M. Brack08171912003-12-29 02:52:11 +00009265 * If we detect an UTF8 error that probably means that the
9266 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009267 * declaration header. Report the error and switch the encoding
9268 * to ISO-Latin-1 (if you don't like this policy, just declare the
9269 * encoding !)
9270 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009271 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009272 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009273}
9274
9275/**
Owen Taylor3473f882001-02-23 17:55:21 +00009276 * xmlXPathParseNCName:
9277 * @ctxt: the XPath Parser context
9278 *
9279 * parse an XML namespace non qualified name.
9280 *
9281 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9282 *
9283 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9284 * CombiningChar | Extender
9285 *
9286 * Returns the namespace name or NULL
9287 */
9288
9289xmlChar *
9290xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009291 const xmlChar *in;
9292 xmlChar *ret;
9293 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009294
Daniel Veillarda82b1822004-11-08 16:24:57 +00009295 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009296 /*
9297 * Accelerator for simple ASCII names
9298 */
9299 in = ctxt->cur;
9300 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9301 ((*in >= 0x41) && (*in <= 0x5A)) ||
9302 (*in == '_')) {
9303 in++;
9304 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9305 ((*in >= 0x41) && (*in <= 0x5A)) ||
9306 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009307 (*in == '_') || (*in == '.') ||
9308 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009309 in++;
9310 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9311 (*in == '[') || (*in == ']') || (*in == ':') ||
9312 (*in == '@') || (*in == '*')) {
9313 count = in - ctxt->cur;
9314 if (count == 0)
9315 return(NULL);
9316 ret = xmlStrndup(ctxt->cur, count);
9317 ctxt->cur = in;
9318 return(ret);
9319 }
9320 }
9321 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009322}
9323
Daniel Veillard2156a562001-04-28 12:24:34 +00009324
Owen Taylor3473f882001-02-23 17:55:21 +00009325/**
9326 * xmlXPathParseQName:
9327 * @ctxt: the XPath Parser context
9328 * @prefix: a xmlChar **
9329 *
9330 * parse an XML qualified name
9331 *
9332 * [NS 5] QName ::= (Prefix ':')? LocalPart
9333 *
9334 * [NS 6] Prefix ::= NCName
9335 *
9336 * [NS 7] LocalPart ::= NCName
9337 *
9338 * Returns the function returns the local part, and prefix is updated
9339 * to get the Prefix if any.
9340 */
9341
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009342static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009343xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9344 xmlChar *ret = NULL;
9345
9346 *prefix = NULL;
9347 ret = xmlXPathParseNCName(ctxt);
9348 if (CUR == ':') {
9349 *prefix = ret;
9350 NEXT;
9351 ret = xmlXPathParseNCName(ctxt);
9352 }
9353 return(ret);
9354}
9355
9356/**
9357 * xmlXPathParseName:
9358 * @ctxt: the XPath Parser context
9359 *
9360 * parse an XML name
9361 *
9362 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9363 * CombiningChar | Extender
9364 *
9365 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9366 *
9367 * Returns the namespace name or NULL
9368 */
9369
9370xmlChar *
9371xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009372 const xmlChar *in;
9373 xmlChar *ret;
9374 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009375
Daniel Veillarda82b1822004-11-08 16:24:57 +00009376 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009377 /*
9378 * Accelerator for simple ASCII names
9379 */
9380 in = ctxt->cur;
9381 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9382 ((*in >= 0x41) && (*in <= 0x5A)) ||
9383 (*in == '_') || (*in == ':')) {
9384 in++;
9385 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9386 ((*in >= 0x41) && (*in <= 0x5A)) ||
9387 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009388 (*in == '_') || (*in == '-') ||
9389 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009390 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009391 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009392 count = in - ctxt->cur;
9393 ret = xmlStrndup(ctxt->cur, count);
9394 ctxt->cur = in;
9395 return(ret);
9396 }
9397 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009398 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009399}
9400
Daniel Veillard61d80a22001-04-27 17:13:01 +00009401static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009402xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009403 xmlChar buf[XML_MAX_NAMELEN + 5];
9404 int len = 0, l;
9405 int c;
9406
9407 /*
9408 * Handler for more complex cases
9409 */
9410 c = CUR_CHAR(l);
9411 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009412 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9413 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009414 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009415 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009416 return(NULL);
9417 }
9418
9419 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9420 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9421 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009422 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009423 (IS_COMBINING(c)) ||
9424 (IS_EXTENDER(c)))) {
9425 COPY_BUF(l,buf,len,c);
9426 NEXTL(l);
9427 c = CUR_CHAR(l);
9428 if (len >= XML_MAX_NAMELEN) {
9429 /*
9430 * Okay someone managed to make a huge name, so he's ready to pay
9431 * for the processing speed.
9432 */
9433 xmlChar *buffer;
9434 int max = len * 2;
9435
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009436 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009437 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009438 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009439 }
9440 memcpy(buffer, buf, len);
9441 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9442 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009443 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009444 (IS_COMBINING(c)) ||
9445 (IS_EXTENDER(c))) {
9446 if (len + 10 > max) {
9447 max *= 2;
9448 buffer = (xmlChar *) xmlRealloc(buffer,
9449 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009450 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009451 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009452 }
9453 }
9454 COPY_BUF(l,buffer,len,c);
9455 NEXTL(l);
9456 c = CUR_CHAR(l);
9457 }
9458 buffer[len] = 0;
9459 return(buffer);
9460 }
9461 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009462 if (len == 0)
9463 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009464 return(xmlStrndup(buf, len));
9465}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009466
9467#define MAX_FRAC 20
9468
William M. Brack372a4452004-02-17 13:09:23 +00009469/*
9470 * These are used as divisors for the fractional part of a number.
9471 * Since the table includes 1.0 (representing '0' fractional digits),
9472 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9473 */
9474static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009475 1.0, 10.0, 100.0, 1000.0, 10000.0,
9476 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9477 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9478 100000000000000.0,
9479 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009480 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009481};
9482
Owen Taylor3473f882001-02-23 17:55:21 +00009483/**
9484 * xmlXPathStringEvalNumber:
9485 * @str: A string to scan
9486 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009487 * [30a] Float ::= Number ('e' Digits?)?
9488 *
Owen Taylor3473f882001-02-23 17:55:21 +00009489 * [30] Number ::= Digits ('.' Digits?)?
9490 * | '.' Digits
9491 * [31] Digits ::= [0-9]+
9492 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009493 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009494 * In complement of the Number expression, this function also handles
9495 * negative values : '-' Number.
9496 *
9497 * Returns the double value.
9498 */
9499double
9500xmlXPathStringEvalNumber(const xmlChar *str) {
9501 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009502 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009503 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009504 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009505 int exponent = 0;
9506 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009507#ifdef __GNUC__
9508 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009509 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009510#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009511 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009512 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009513 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9514 return(xmlXPathNAN);
9515 }
9516 if (*cur == '-') {
9517 isneg = 1;
9518 cur++;
9519 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009520
9521#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009522 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009523 * tmp/temp is a workaround against a gcc compiler bug
9524 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009525 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009526 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009527 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009528 ret = ret * 10;
9529 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009530 ok = 1;
9531 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009532 temp = (double) tmp;
9533 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009534 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009535#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009536 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009537 while ((*cur >= '0') && (*cur <= '9')) {
9538 ret = ret * 10 + (*cur - '0');
9539 ok = 1;
9540 cur++;
9541 }
9542#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009543
Owen Taylor3473f882001-02-23 17:55:21 +00009544 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009545 int v, frac = 0;
9546 double fraction = 0;
9547
Owen Taylor3473f882001-02-23 17:55:21 +00009548 cur++;
9549 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9550 return(xmlXPathNAN);
9551 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009552 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9553 v = (*cur - '0');
9554 fraction = fraction * 10 + v;
9555 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009556 cur++;
9557 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009558 fraction /= my_pow10[frac];
9559 ret = ret + fraction;
9560 while ((*cur >= '0') && (*cur <= '9'))
9561 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009562 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009563 if ((*cur == 'e') || (*cur == 'E')) {
9564 cur++;
9565 if (*cur == '-') {
9566 is_exponent_negative = 1;
9567 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009568 } else if (*cur == '+') {
9569 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009570 }
9571 while ((*cur >= '0') && (*cur <= '9')) {
9572 exponent = exponent * 10 + (*cur - '0');
9573 cur++;
9574 }
9575 }
William M. Brack76e95df2003-10-18 16:20:14 +00009576 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009577 if (*cur != 0) return(xmlXPathNAN);
9578 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009579 if (is_exponent_negative) exponent = -exponent;
9580 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009581 return(ret);
9582}
9583
9584/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009585 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009586 * @ctxt: the XPath Parser context
9587 *
9588 * [30] Number ::= Digits ('.' Digits?)?
9589 * | '.' Digits
9590 * [31] Digits ::= [0-9]+
9591 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009592 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009593 *
9594 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009595static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009596xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9597{
Owen Taylor3473f882001-02-23 17:55:21 +00009598 double ret = 0.0;
9599 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009600 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009601 int exponent = 0;
9602 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009603#ifdef __GNUC__
9604 unsigned long tmp = 0;
9605 double temp;
9606#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009607
9608 CHECK_ERROR;
9609 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9610 XP_ERROR(XPATH_NUMBER_ERROR);
9611 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009612#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009613 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009614 * tmp/temp is a workaround against a gcc compiler bug
9615 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009616 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009617 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009618 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009619 ret = ret * 10;
9620 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009621 ok = 1;
9622 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00009623 temp = (double) tmp;
9624 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009625 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009626#else
9627 ret = 0;
9628 while ((CUR >= '0') && (CUR <= '9')) {
9629 ret = ret * 10 + (CUR - '0');
9630 ok = 1;
9631 NEXT;
9632 }
9633#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009634 if (CUR == '.') {
9635 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009636 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9637 XP_ERROR(XPATH_NUMBER_ERROR);
9638 }
9639 while ((CUR >= '0') && (CUR <= '9')) {
9640 mult /= 10;
9641 ret = ret + (CUR - '0') * mult;
9642 NEXT;
9643 }
Owen Taylor3473f882001-02-23 17:55:21 +00009644 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009645 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009646 NEXT;
9647 if (CUR == '-') {
9648 is_exponent_negative = 1;
9649 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00009650 } else if (CUR == '+') {
9651 NEXT;
9652 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009653 while ((CUR >= '0') && (CUR <= '9')) {
9654 exponent = exponent * 10 + (CUR - '0');
9655 NEXT;
9656 }
9657 if (is_exponent_negative)
9658 exponent = -exponent;
9659 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00009660 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009661 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009662 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009663}
9664
9665/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009666 * xmlXPathParseLiteral:
9667 * @ctxt: the XPath Parser context
9668 *
9669 * Parse a Literal
9670 *
9671 * [29] Literal ::= '"' [^"]* '"'
9672 * | "'" [^']* "'"
9673 *
9674 * Returns the value found or NULL in case of error
9675 */
9676static xmlChar *
9677xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9678 const xmlChar *q;
9679 xmlChar *ret = NULL;
9680
9681 if (CUR == '"') {
9682 NEXT;
9683 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009684 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009685 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009686 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009687 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009688 } else {
9689 ret = xmlStrndup(q, CUR_PTR - q);
9690 NEXT;
9691 }
9692 } else if (CUR == '\'') {
9693 NEXT;
9694 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009695 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009696 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009697 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009698 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009699 } else {
9700 ret = xmlStrndup(q, CUR_PTR - q);
9701 NEXT;
9702 }
9703 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00009704 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009705 }
9706 return(ret);
9707}
9708
9709/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009710 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00009711 * @ctxt: the XPath Parser context
9712 *
9713 * Parse a Literal and push it on the stack.
9714 *
9715 * [29] Literal ::= '"' [^"]* '"'
9716 * | "'" [^']* "'"
9717 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009718 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00009719 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009720static void
9721xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009722 const xmlChar *q;
9723 xmlChar *ret = NULL;
9724
9725 if (CUR == '"') {
9726 NEXT;
9727 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009728 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00009729 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009730 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009731 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9732 } else {
9733 ret = xmlStrndup(q, CUR_PTR - q);
9734 NEXT;
9735 }
9736 } else if (CUR == '\'') {
9737 NEXT;
9738 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009739 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00009740 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009741 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009742 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9743 } else {
9744 ret = xmlStrndup(q, CUR_PTR - q);
9745 NEXT;
9746 }
9747 } else {
9748 XP_ERROR(XPATH_START_LITERAL_ERROR);
9749 }
9750 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009751 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009752 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009753 xmlFree(ret);
9754}
9755
9756/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009757 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00009758 * @ctxt: the XPath Parser context
9759 *
9760 * Parse a VariableReference, evaluate it and push it on the stack.
9761 *
9762 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00009763 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00009764 * of any of the types that are possible for the value of an expression,
9765 * and may also be of additional types not specified here.
9766 *
9767 * Early evaluation is possible since:
9768 * The variable bindings [...] used to evaluate a subexpression are
9769 * always the same as those used to evaluate the containing expression.
9770 *
9771 * [36] VariableReference ::= '$' QName
9772 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009773static void
9774xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009775 xmlChar *name;
9776 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009777
9778 SKIP_BLANKS;
9779 if (CUR != '$') {
9780 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9781 }
9782 NEXT;
9783 name = xmlXPathParseQName(ctxt, &prefix);
9784 if (name == NULL) {
9785 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9786 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009787 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009788 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
9789 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00009790 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00009791 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9792 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
9793 }
Owen Taylor3473f882001-02-23 17:55:21 +00009794}
9795
9796/**
9797 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00009798 * @name: a name string
9799 *
9800 * Is the name given a NodeType one.
9801 *
9802 * [38] NodeType ::= 'comment'
9803 * | 'text'
9804 * | 'processing-instruction'
9805 * | 'node'
9806 *
9807 * Returns 1 if true 0 otherwise
9808 */
9809int
9810xmlXPathIsNodeType(const xmlChar *name) {
9811 if (name == NULL)
9812 return(0);
9813
Daniel Veillard1971ee22002-01-31 20:29:19 +00009814 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00009815 return(1);
9816 if (xmlStrEqual(name, BAD_CAST "text"))
9817 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009818 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00009819 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009820 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00009821 return(1);
9822 return(0);
9823}
9824
9825/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009826 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00009827 * @ctxt: the XPath Parser context
9828 *
9829 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9830 * [17] Argument ::= Expr
9831 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009832 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00009833 * pushed on the stack
9834 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009835static void
9836xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009837 xmlChar *name;
9838 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009839 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009840 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009841
9842 name = xmlXPathParseQName(ctxt, &prefix);
9843 if (name == NULL) {
9844 XP_ERROR(XPATH_EXPR_ERROR);
9845 }
9846 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009847#ifdef DEBUG_EXPR
9848 if (prefix == NULL)
9849 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
9850 name);
9851 else
9852 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
9853 prefix, name);
9854#endif
9855
Owen Taylor3473f882001-02-23 17:55:21 +00009856 if (CUR != '(') {
9857 XP_ERROR(XPATH_EXPR_ERROR);
9858 }
9859 NEXT;
9860 SKIP_BLANKS;
9861
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009862 /*
9863 * Optimization for count(): we don't need the node-set to be sorted.
9864 */
9865 if ((prefix == NULL) && (name[0] == 'c') &&
9866 xmlStrEqual(name, BAD_CAST "count"))
9867 {
9868 sort = 0;
9869 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009870 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00009871 if (CUR != ')') {
9872 while (CUR != 0) {
9873 int op1 = ctxt->comp->last;
9874 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009875 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +00009876 CHECK_ERROR;
9877 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9878 nbargs++;
9879 if (CUR == ')') break;
9880 if (CUR != ',') {
9881 XP_ERROR(XPATH_EXPR_ERROR);
9882 }
9883 NEXT;
9884 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009885 }
Owen Taylor3473f882001-02-23 17:55:21 +00009886 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009887 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
9888 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00009889 NEXT;
9890 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009891}
9892
9893/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009894 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00009895 * @ctxt: the XPath Parser context
9896 *
9897 * [15] PrimaryExpr ::= VariableReference
9898 * | '(' Expr ')'
9899 * | Literal
9900 * | Number
9901 * | FunctionCall
9902 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009903 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00009904 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009905static void
9906xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009907 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009908 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009909 else if (CUR == '(') {
9910 NEXT;
9911 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009912 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00009913 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00009914 if (CUR != ')') {
9915 XP_ERROR(XPATH_EXPR_ERROR);
9916 }
9917 NEXT;
9918 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00009919 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009920 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009921 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009922 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009923 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009924 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009925 }
9926 SKIP_BLANKS;
9927}
9928
9929/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009930 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00009931 * @ctxt: the XPath Parser context
9932 *
9933 * [20] FilterExpr ::= PrimaryExpr
9934 * | FilterExpr Predicate
9935 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009936 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00009937 * Square brackets are used to filter expressions in the same way that
9938 * they are used in location paths. It is an error if the expression to
9939 * be filtered does not evaluate to a node-set. The context node list
9940 * used for evaluating the expression in square brackets is the node-set
9941 * to be filtered listed in document order.
9942 */
9943
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009944static void
9945xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9946 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009947 CHECK_ERROR;
9948 SKIP_BLANKS;
9949
9950 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009951 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00009952 SKIP_BLANKS;
9953 }
9954
9955
9956}
9957
9958/**
9959 * xmlXPathScanName:
9960 * @ctxt: the XPath Parser context
9961 *
9962 * Trickery: parse an XML name but without consuming the input flow
9963 * Needed to avoid insanity in the parser state.
9964 *
9965 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9966 * CombiningChar | Extender
9967 *
9968 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9969 *
9970 * [6] Names ::= Name (S Name)*
9971 *
9972 * Returns the Name parsed or NULL
9973 */
9974
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009975static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009976xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00009977 int len = 0, l;
9978 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00009979 const xmlChar *cur;
9980 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00009981
Daniel Veillard03226812004-11-01 14:55:21 +00009982 cur = ctxt->cur;
9983
9984 c = CUR_CHAR(l);
9985 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9986 (!IS_LETTER(c) && (c != '_') &&
9987 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00009988 return(NULL);
9989 }
9990
Daniel Veillard03226812004-11-01 14:55:21 +00009991 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9992 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9993 (c == '.') || (c == '-') ||
9994 (c == '_') || (c == ':') ||
9995 (IS_COMBINING(c)) ||
9996 (IS_EXTENDER(c)))) {
9997 len += l;
9998 NEXTL(l);
9999 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010000 }
Daniel Veillard03226812004-11-01 14:55:21 +000010001 ret = xmlStrndup(cur, ctxt->cur - cur);
10002 ctxt->cur = cur;
10003 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010004}
10005
10006/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010007 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010008 * @ctxt: the XPath Parser context
10009 *
10010 * [19] PathExpr ::= LocationPath
10011 * | FilterExpr
10012 * | FilterExpr '/' RelativeLocationPath
10013 * | FilterExpr '//' RelativeLocationPath
10014 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010015 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010016 * The / operator and // operators combine an arbitrary expression
10017 * and a relative location path. It is an error if the expression
10018 * does not evaluate to a node-set.
10019 * The / operator does composition in the same way as when / is
10020 * used in a location path. As in location paths, // is short for
10021 * /descendant-or-self::node()/.
10022 */
10023
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010024static void
10025xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010026 int lc = 1; /* Should we branch to LocationPath ? */
10027 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10028
10029 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010030 if ((CUR == '$') || (CUR == '(') ||
10031 (IS_ASCII_DIGIT(CUR)) ||
10032 (CUR == '\'') || (CUR == '"') ||
10033 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010034 lc = 0;
10035 } else if (CUR == '*') {
10036 /* relative or absolute location path */
10037 lc = 1;
10038 } else if (CUR == '/') {
10039 /* relative or absolute location path */
10040 lc = 1;
10041 } else if (CUR == '@') {
10042 /* relative abbreviated attribute location path */
10043 lc = 1;
10044 } else if (CUR == '.') {
10045 /* relative abbreviated attribute location path */
10046 lc = 1;
10047 } else {
10048 /*
10049 * Problem is finding if we have a name here whether it's:
10050 * - a nodetype
10051 * - a function call in which case it's followed by '('
10052 * - an axis in which case it's followed by ':'
10053 * - a element name
10054 * We do an a priori analysis here rather than having to
10055 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010056 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010057 * read/write/debug.
10058 */
10059 SKIP_BLANKS;
10060 name = xmlXPathScanName(ctxt);
10061 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10062#ifdef DEBUG_STEP
10063 xmlGenericError(xmlGenericErrorContext,
10064 "PathExpr: Axis\n");
10065#endif
10066 lc = 1;
10067 xmlFree(name);
10068 } else if (name != NULL) {
10069 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010070
10071
10072 while (NXT(len) != 0) {
10073 if (NXT(len) == '/') {
10074 /* element name */
10075#ifdef DEBUG_STEP
10076 xmlGenericError(xmlGenericErrorContext,
10077 "PathExpr: AbbrRelLocation\n");
10078#endif
10079 lc = 1;
10080 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010081 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010082 /* ignore blanks */
10083 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010084 } else if (NXT(len) == ':') {
10085#ifdef DEBUG_STEP
10086 xmlGenericError(xmlGenericErrorContext,
10087 "PathExpr: AbbrRelLocation\n");
10088#endif
10089 lc = 1;
10090 break;
10091 } else if ((NXT(len) == '(')) {
10092 /* Note Type or Function */
10093 if (xmlXPathIsNodeType(name)) {
10094#ifdef DEBUG_STEP
10095 xmlGenericError(xmlGenericErrorContext,
10096 "PathExpr: Type search\n");
10097#endif
10098 lc = 1;
10099 } else {
10100#ifdef DEBUG_STEP
10101 xmlGenericError(xmlGenericErrorContext,
10102 "PathExpr: function call\n");
10103#endif
10104 lc = 0;
10105 }
10106 break;
10107 } else if ((NXT(len) == '[')) {
10108 /* element name */
10109#ifdef DEBUG_STEP
10110 xmlGenericError(xmlGenericErrorContext,
10111 "PathExpr: AbbrRelLocation\n");
10112#endif
10113 lc = 1;
10114 break;
10115 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10116 (NXT(len) == '=')) {
10117 lc = 1;
10118 break;
10119 } else {
10120 lc = 1;
10121 break;
10122 }
10123 len++;
10124 }
10125 if (NXT(len) == 0) {
10126#ifdef DEBUG_STEP
10127 xmlGenericError(xmlGenericErrorContext,
10128 "PathExpr: AbbrRelLocation\n");
10129#endif
10130 /* element name */
10131 lc = 1;
10132 }
10133 xmlFree(name);
10134 } else {
William M. Brack08171912003-12-29 02:52:11 +000010135 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010136 XP_ERROR(XPATH_EXPR_ERROR);
10137 }
10138 }
10139
10140 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010141 if (CUR == '/') {
10142 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10143 } else {
10144 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010145 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010146 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010147 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010148 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010149 CHECK_ERROR;
10150 if ((CUR == '/') && (NXT(1) == '/')) {
10151 SKIP(2);
10152 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010153
10154 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10155 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10156 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10157
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010158 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010159 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010160 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010161 }
10162 }
10163 SKIP_BLANKS;
10164}
10165
10166/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010167 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010168 * @ctxt: the XPath Parser context
10169 *
10170 * [18] UnionExpr ::= PathExpr
10171 * | UnionExpr '|' PathExpr
10172 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010173 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010174 */
10175
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010176static void
10177xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10178 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010179 CHECK_ERROR;
10180 SKIP_BLANKS;
10181 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010182 int op1 = ctxt->comp->last;
10183 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010184
10185 NEXT;
10186 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010187 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010188
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010189 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10190
Owen Taylor3473f882001-02-23 17:55:21 +000010191 SKIP_BLANKS;
10192 }
Owen Taylor3473f882001-02-23 17:55:21 +000010193}
10194
10195/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010196 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010197 * @ctxt: the XPath Parser context
10198 *
10199 * [27] UnaryExpr ::= UnionExpr
10200 * | '-' UnaryExpr
10201 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010202 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010203 */
10204
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010205static void
10206xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010207 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010208 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010209
10210 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010211 while (CUR == '-') {
10212 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010213 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010214 NEXT;
10215 SKIP_BLANKS;
10216 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010217
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010218 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010219 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010220 if (found) {
10221 if (minus)
10222 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10223 else
10224 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010225 }
10226}
10227
10228/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010229 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010230 * @ctxt: the XPath Parser context
10231 *
10232 * [26] MultiplicativeExpr ::= UnaryExpr
10233 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10234 * | MultiplicativeExpr 'div' UnaryExpr
10235 * | MultiplicativeExpr 'mod' UnaryExpr
10236 * [34] MultiplyOperator ::= '*'
10237 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010238 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010239 */
10240
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010241static void
10242xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10243 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010244 CHECK_ERROR;
10245 SKIP_BLANKS;
10246 while ((CUR == '*') ||
10247 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10248 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10249 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010250 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010251
10252 if (CUR == '*') {
10253 op = 0;
10254 NEXT;
10255 } else if (CUR == 'd') {
10256 op = 1;
10257 SKIP(3);
10258 } else if (CUR == 'm') {
10259 op = 2;
10260 SKIP(3);
10261 }
10262 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010263 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010264 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010265 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010266 SKIP_BLANKS;
10267 }
10268}
10269
10270/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010271 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010272 * @ctxt: the XPath Parser context
10273 *
10274 * [25] AdditiveExpr ::= MultiplicativeExpr
10275 * | AdditiveExpr '+' MultiplicativeExpr
10276 * | AdditiveExpr '-' MultiplicativeExpr
10277 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010278 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010279 */
10280
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010281static void
10282xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010283
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010284 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010285 CHECK_ERROR;
10286 SKIP_BLANKS;
10287 while ((CUR == '+') || (CUR == '-')) {
10288 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010289 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010290
10291 if (CUR == '+') plus = 1;
10292 else plus = 0;
10293 NEXT;
10294 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010295 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010296 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010297 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010298 SKIP_BLANKS;
10299 }
10300}
10301
10302/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010303 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010304 * @ctxt: the XPath Parser context
10305 *
10306 * [24] RelationalExpr ::= AdditiveExpr
10307 * | RelationalExpr '<' AdditiveExpr
10308 * | RelationalExpr '>' AdditiveExpr
10309 * | RelationalExpr '<=' AdditiveExpr
10310 * | RelationalExpr '>=' AdditiveExpr
10311 *
10312 * A <= B > C is allowed ? Answer from James, yes with
10313 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10314 * which is basically what got implemented.
10315 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010316 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010317 * on the stack
10318 */
10319
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010320static void
10321xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10322 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010323 CHECK_ERROR;
10324 SKIP_BLANKS;
10325 while ((CUR == '<') ||
10326 (CUR == '>') ||
10327 ((CUR == '<') && (NXT(1) == '=')) ||
10328 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010329 int inf, strict;
10330 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010331
10332 if (CUR == '<') inf = 1;
10333 else inf = 0;
10334 if (NXT(1) == '=') strict = 0;
10335 else strict = 1;
10336 NEXT;
10337 if (!strict) NEXT;
10338 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010339 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010340 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010341 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010342 SKIP_BLANKS;
10343 }
10344}
10345
10346/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010347 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010348 * @ctxt: the XPath Parser context
10349 *
10350 * [23] EqualityExpr ::= RelationalExpr
10351 * | EqualityExpr '=' RelationalExpr
10352 * | EqualityExpr '!=' RelationalExpr
10353 *
10354 * A != B != C is allowed ? Answer from James, yes with
10355 * (RelationalExpr = RelationalExpr) = RelationalExpr
10356 * (RelationalExpr != RelationalExpr) != RelationalExpr
10357 * which is basically what got implemented.
10358 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010359 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010360 *
10361 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010362static void
10363xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10364 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010365 CHECK_ERROR;
10366 SKIP_BLANKS;
10367 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010368 int eq;
10369 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010370
10371 if (CUR == '=') eq = 1;
10372 else eq = 0;
10373 NEXT;
10374 if (!eq) NEXT;
10375 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010376 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010377 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010378 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010379 SKIP_BLANKS;
10380 }
10381}
10382
10383/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010384 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010385 * @ctxt: the XPath Parser context
10386 *
10387 * [22] AndExpr ::= EqualityExpr
10388 * | AndExpr 'and' EqualityExpr
10389 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010390 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010391 *
10392 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010393static void
10394xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10395 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010396 CHECK_ERROR;
10397 SKIP_BLANKS;
10398 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010399 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010400 SKIP(3);
10401 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010402 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010403 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010404 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010405 SKIP_BLANKS;
10406 }
10407}
10408
10409/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010410 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010411 * @ctxt: the XPath Parser context
10412 *
10413 * [14] Expr ::= OrExpr
10414 * [21] OrExpr ::= AndExpr
10415 * | OrExpr 'or' AndExpr
10416 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010417 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010418 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010419static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010420xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010421 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010422 CHECK_ERROR;
10423 SKIP_BLANKS;
10424 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010425 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010426 SKIP(2);
10427 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010428 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010429 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010430 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10431 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010432 SKIP_BLANKS;
10433 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010434 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010436 /*
10437 * This is the main place to eliminate sorting for
10438 * operations which don't require a sorted node-set.
10439 * E.g. count().
10440 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010441 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10442 }
Owen Taylor3473f882001-02-23 17:55:21 +000010443}
10444
10445/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010446 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010447 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010448 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010449 *
10450 * [8] Predicate ::= '[' PredicateExpr ']'
10451 * [9] PredicateExpr ::= Expr
10452 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010453 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010454 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010455static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010456xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010457 int op1 = ctxt->comp->last;
10458
10459 SKIP_BLANKS;
10460 if (CUR != '[') {
10461 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10462 }
10463 NEXT;
10464 SKIP_BLANKS;
10465
10466 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010467 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010468 CHECK_ERROR;
10469
10470 if (CUR != ']') {
10471 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10472 }
10473
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010474 if (filter)
10475 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10476 else
10477 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010478
10479 NEXT;
10480 SKIP_BLANKS;
10481}
10482
10483/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010484 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010485 * @ctxt: the XPath Parser context
10486 * @test: pointer to a xmlXPathTestVal
10487 * @type: pointer to a xmlXPathTypeVal
10488 * @prefix: placeholder for a possible name prefix
10489 *
10490 * [7] NodeTest ::= NameTest
10491 * | NodeType '(' ')'
10492 * | 'processing-instruction' '(' Literal ')'
10493 *
10494 * [37] NameTest ::= '*'
10495 * | NCName ':' '*'
10496 * | QName
10497 * [38] NodeType ::= 'comment'
10498 * | 'text'
10499 * | 'processing-instruction'
10500 * | 'node'
10501 *
William M. Brack08171912003-12-29 02:52:11 +000010502 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010503 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010504static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010505xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10506 xmlXPathTypeVal *type, const xmlChar **prefix,
10507 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010508 int blanks;
10509
10510 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10511 STRANGE;
10512 return(NULL);
10513 }
William M. Brack78637da2003-07-31 14:47:38 +000010514 *type = (xmlXPathTypeVal) 0;
10515 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010516 *prefix = NULL;
10517 SKIP_BLANKS;
10518
10519 if ((name == NULL) && (CUR == '*')) {
10520 /*
10521 * All elements
10522 */
10523 NEXT;
10524 *test = NODE_TEST_ALL;
10525 return(NULL);
10526 }
10527
10528 if (name == NULL)
10529 name = xmlXPathParseNCName(ctxt);
10530 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010531 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010532 }
10533
William M. Brack76e95df2003-10-18 16:20:14 +000010534 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010535 SKIP_BLANKS;
10536 if (CUR == '(') {
10537 NEXT;
10538 /*
10539 * NodeType or PI search
10540 */
10541 if (xmlStrEqual(name, BAD_CAST "comment"))
10542 *type = NODE_TYPE_COMMENT;
10543 else if (xmlStrEqual(name, BAD_CAST "node"))
10544 *type = NODE_TYPE_NODE;
10545 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10546 *type = NODE_TYPE_PI;
10547 else if (xmlStrEqual(name, BAD_CAST "text"))
10548 *type = NODE_TYPE_TEXT;
10549 else {
10550 if (name != NULL)
10551 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010552 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010553 }
10554
10555 *test = NODE_TEST_TYPE;
10556
10557 SKIP_BLANKS;
10558 if (*type == NODE_TYPE_PI) {
10559 /*
10560 * Specific case: search a PI by name.
10561 */
Owen Taylor3473f882001-02-23 17:55:21 +000010562 if (name != NULL)
10563 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010564 name = NULL;
10565 if (CUR != ')') {
10566 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010567 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010568 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010569 SKIP_BLANKS;
10570 }
Owen Taylor3473f882001-02-23 17:55:21 +000010571 }
10572 if (CUR != ')') {
10573 if (name != NULL)
10574 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010575 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010576 }
10577 NEXT;
10578 return(name);
10579 }
10580 *test = NODE_TEST_NAME;
10581 if ((!blanks) && (CUR == ':')) {
10582 NEXT;
10583
10584 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010585 * Since currently the parser context don't have a
10586 * namespace list associated:
10587 * The namespace name for this prefix can be computed
10588 * only at evaluation time. The compilation is done
10589 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010590 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010591#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010592 *prefix = xmlXPathNsLookup(ctxt->context, name);
10593 if (name != NULL)
10594 xmlFree(name);
10595 if (*prefix == NULL) {
10596 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10597 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010598#else
10599 *prefix = name;
10600#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010601
10602 if (CUR == '*') {
10603 /*
10604 * All elements
10605 */
10606 NEXT;
10607 *test = NODE_TEST_ALL;
10608 return(NULL);
10609 }
10610
10611 name = xmlXPathParseNCName(ctxt);
10612 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010613 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010614 }
10615 }
10616 return(name);
10617}
10618
10619/**
10620 * xmlXPathIsAxisName:
10621 * @name: a preparsed name token
10622 *
10623 * [6] AxisName ::= 'ancestor'
10624 * | 'ancestor-or-self'
10625 * | 'attribute'
10626 * | 'child'
10627 * | 'descendant'
10628 * | 'descendant-or-self'
10629 * | 'following'
10630 * | 'following-sibling'
10631 * | 'namespace'
10632 * | 'parent'
10633 * | 'preceding'
10634 * | 'preceding-sibling'
10635 * | 'self'
10636 *
10637 * Returns the axis or 0
10638 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010639static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000010640xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000010641 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010642 switch (name[0]) {
10643 case 'a':
10644 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10645 ret = AXIS_ANCESTOR;
10646 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10647 ret = AXIS_ANCESTOR_OR_SELF;
10648 if (xmlStrEqual(name, BAD_CAST "attribute"))
10649 ret = AXIS_ATTRIBUTE;
10650 break;
10651 case 'c':
10652 if (xmlStrEqual(name, BAD_CAST "child"))
10653 ret = AXIS_CHILD;
10654 break;
10655 case 'd':
10656 if (xmlStrEqual(name, BAD_CAST "descendant"))
10657 ret = AXIS_DESCENDANT;
10658 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10659 ret = AXIS_DESCENDANT_OR_SELF;
10660 break;
10661 case 'f':
10662 if (xmlStrEqual(name, BAD_CAST "following"))
10663 ret = AXIS_FOLLOWING;
10664 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10665 ret = AXIS_FOLLOWING_SIBLING;
10666 break;
10667 case 'n':
10668 if (xmlStrEqual(name, BAD_CAST "namespace"))
10669 ret = AXIS_NAMESPACE;
10670 break;
10671 case 'p':
10672 if (xmlStrEqual(name, BAD_CAST "parent"))
10673 ret = AXIS_PARENT;
10674 if (xmlStrEqual(name, BAD_CAST "preceding"))
10675 ret = AXIS_PRECEDING;
10676 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10677 ret = AXIS_PRECEDING_SIBLING;
10678 break;
10679 case 's':
10680 if (xmlStrEqual(name, BAD_CAST "self"))
10681 ret = AXIS_SELF;
10682 break;
10683 }
10684 return(ret);
10685}
10686
10687/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010688 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000010689 * @ctxt: the XPath Parser context
10690 *
10691 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10692 * | AbbreviatedStep
10693 *
10694 * [12] AbbreviatedStep ::= '.' | '..'
10695 *
10696 * [5] AxisSpecifier ::= AxisName '::'
10697 * | AbbreviatedAxisSpecifier
10698 *
10699 * [13] AbbreviatedAxisSpecifier ::= '@'?
10700 *
10701 * Modified for XPtr range support as:
10702 *
10703 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10704 * | AbbreviatedStep
10705 * | 'range-to' '(' Expr ')' Predicate*
10706 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010707 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000010708 * A location step of . is short for self::node(). This is
10709 * particularly useful in conjunction with //. For example, the
10710 * location path .//para is short for
10711 * self::node()/descendant-or-self::node()/child::para
10712 * and so will select all para descendant elements of the context
10713 * node.
10714 * Similarly, a location step of .. is short for parent::node().
10715 * For example, ../title is short for parent::node()/child::title
10716 * and so will select the title children of the parent of the context
10717 * node.
10718 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010719static void
10720xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010721#ifdef LIBXML_XPTR_ENABLED
10722 int rangeto = 0;
10723 int op2 = -1;
10724#endif
10725
Owen Taylor3473f882001-02-23 17:55:21 +000010726 SKIP_BLANKS;
10727 if ((CUR == '.') && (NXT(1) == '.')) {
10728 SKIP(2);
10729 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010730 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10731 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010732 } else if (CUR == '.') {
10733 NEXT;
10734 SKIP_BLANKS;
10735 } else {
10736 xmlChar *name = NULL;
10737 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010738 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000010739 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010740 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010741 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000010742
10743 /*
10744 * The modification needed for XPointer change to the production
10745 */
10746#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010747 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000010748 name = xmlXPathParseNCName(ctxt);
10749 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010750 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010751 xmlFree(name);
10752 SKIP_BLANKS;
10753 if (CUR != '(') {
10754 XP_ERROR(XPATH_EXPR_ERROR);
10755 }
10756 NEXT;
10757 SKIP_BLANKS;
10758
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010759 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010760 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000010761 CHECK_ERROR;
10762
10763 SKIP_BLANKS;
10764 if (CUR != ')') {
10765 XP_ERROR(XPATH_EXPR_ERROR);
10766 }
10767 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010768 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010769 goto eval_predicates;
10770 }
10771 }
10772#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000010773 if (CUR == '*') {
10774 axis = AXIS_CHILD;
10775 } else {
10776 if (name == NULL)
10777 name = xmlXPathParseNCName(ctxt);
10778 if (name != NULL) {
10779 axis = xmlXPathIsAxisName(name);
10780 if (axis != 0) {
10781 SKIP_BLANKS;
10782 if ((CUR == ':') && (NXT(1) == ':')) {
10783 SKIP(2);
10784 xmlFree(name);
10785 name = NULL;
10786 } else {
10787 /* an element name can conflict with an axis one :-\ */
10788 axis = AXIS_CHILD;
10789 }
Owen Taylor3473f882001-02-23 17:55:21 +000010790 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000010791 axis = AXIS_CHILD;
10792 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010793 } else if (CUR == '@') {
10794 NEXT;
10795 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000010796 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000010797 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000010798 }
Owen Taylor3473f882001-02-23 17:55:21 +000010799 }
10800
10801 CHECK_ERROR;
10802
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010803 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000010804 if (test == 0)
10805 return;
10806
Daniel Veillarded6c5492005-07-23 15:00:22 +000010807 if ((prefix != NULL) && (ctxt->context != NULL) &&
10808 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10809 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10810 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10811 }
10812 }
Owen Taylor3473f882001-02-23 17:55:21 +000010813#ifdef DEBUG_STEP
10814 xmlGenericError(xmlGenericErrorContext,
10815 "Basis : computing new set\n");
10816#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010817
Owen Taylor3473f882001-02-23 17:55:21 +000010818#ifdef DEBUG_STEP
10819 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010820 if (ctxt->value == NULL)
10821 xmlGenericError(xmlGenericErrorContext, "no value\n");
10822 else if (ctxt->value->nodesetval == NULL)
10823 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10824 else
10825 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010826#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010827
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010828#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000010829eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010830#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010831 op1 = ctxt->comp->last;
10832 ctxt->comp->last = -1;
10833
Owen Taylor3473f882001-02-23 17:55:21 +000010834 SKIP_BLANKS;
10835 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010836 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010837 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010838
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010839#ifdef LIBXML_XPTR_ENABLED
10840 if (rangeto) {
10841 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10842 } else
10843#endif
10844 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10845 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010846
Owen Taylor3473f882001-02-23 17:55:21 +000010847 }
10848#ifdef DEBUG_STEP
10849 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010850 if (ctxt->value == NULL)
10851 xmlGenericError(xmlGenericErrorContext, "no value\n");
10852 else if (ctxt->value->nodesetval == NULL)
10853 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10854 else
10855 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
10856 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010857#endif
10858}
10859
10860/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010861 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000010862 * @ctxt: the XPath Parser context
10863 *
10864 * [3] RelativeLocationPath ::= Step
10865 * | RelativeLocationPath '/' Step
10866 * | AbbreviatedRelativeLocationPath
10867 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10868 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010869 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000010870 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010871static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010872xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010873(xmlXPathParserContextPtr ctxt) {
10874 SKIP_BLANKS;
10875 if ((CUR == '/') && (NXT(1) == '/')) {
10876 SKIP(2);
10877 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010878 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10879 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010880 } else if (CUR == '/') {
10881 NEXT;
10882 SKIP_BLANKS;
10883 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010884 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010885 SKIP_BLANKS;
10886 while (CUR == '/') {
10887 if ((CUR == '/') && (NXT(1) == '/')) {
10888 SKIP(2);
10889 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010890 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000010891 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010892 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010893 } else if (CUR == '/') {
10894 NEXT;
10895 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010896 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010897 }
10898 SKIP_BLANKS;
10899 }
10900}
10901
10902/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010903 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000010904 * @ctxt: the XPath Parser context
10905 *
10906 * [1] LocationPath ::= RelativeLocationPath
10907 * | AbsoluteLocationPath
10908 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10909 * | AbbreviatedAbsoluteLocationPath
10910 * [10] AbbreviatedAbsoluteLocationPath ::=
10911 * '//' RelativeLocationPath
10912 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010913 * Compile a location path
10914 *
Owen Taylor3473f882001-02-23 17:55:21 +000010915 * // is short for /descendant-or-self::node()/. For example,
10916 * //para is short for /descendant-or-self::node()/child::para and
10917 * so will select any para element in the document (even a para element
10918 * that is a document element will be selected by //para since the
10919 * document element node is a child of the root node); div//para is
10920 * short for div/descendant-or-self::node()/child::para and so will
10921 * select all para descendants of div children.
10922 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010923static void
10924xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010925 SKIP_BLANKS;
10926 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010927 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010928 } else {
10929 while (CUR == '/') {
10930 if ((CUR == '/') && (NXT(1) == '/')) {
10931 SKIP(2);
10932 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010933 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10934 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010935 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010936 } else if (CUR == '/') {
10937 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000010938 SKIP_BLANKS;
10939 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000010940 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000010941 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010942 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010943 }
10944 }
10945 }
10946}
10947
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010948/************************************************************************
10949 * *
10950 * XPath precompiled expression evaluation *
10951 * *
10952 ************************************************************************/
10953
Daniel Veillardf06307e2001-07-03 10:35:50 +000010954static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010955xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10956
10957/**
10958 * xmlXPathNodeCollectAndTest:
10959 * @ctxt: the XPath Parser context
10960 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +000010961 * @first: pointer to the first element in document order
10962 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010963 *
10964 * This is the function implementing a step: based on the current list
10965 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000010966 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010967 *
10968 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010969 *
William M. Brack08171912003-12-29 02:52:11 +000010970 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010971 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010972static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010973xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010974 xmlXPathStepOpPtr op,
10975 xmlNodePtr * first, xmlNodePtr * last)
10976{
William M. Brack78637da2003-07-31 14:47:38 +000010977 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10978 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10979 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010980 const xmlChar *prefix = op->value4;
10981 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +000010982 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010983
10984#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000010985 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010986#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000010987 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010988 xmlNodeSetPtr ret, list;
10989 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010990 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +000010991 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010992 xmlNodePtr cur = NULL;
10993 xmlXPathObjectPtr obj;
10994 xmlNodeSetPtr nodelist;
10995 xmlNodePtr tmp;
10996
Daniel Veillardf06307e2001-07-03 10:35:50 +000010997 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010998 obj = valuePop(ctxt);
10999 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +000011000 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +000011001 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011002 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011003 if (URI == NULL) {
11004 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011005 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011006 }
Daniel Veillarde043ee12001-04-16 14:08:07 +000011007 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011008#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011009 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011010#endif
11011 switch (axis) {
11012 case AXIS_ANCESTOR:
11013#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011014 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011015#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011016 first = NULL;
11017 next = xmlXPathNextAncestor;
11018 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011019 case AXIS_ANCESTOR_OR_SELF:
11020#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011021 xmlGenericError(xmlGenericErrorContext,
11022 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011023#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011024 first = NULL;
11025 next = xmlXPathNextAncestorOrSelf;
11026 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011027 case AXIS_ATTRIBUTE:
11028#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011029 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011030#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011031 first = NULL;
11032 last = NULL;
11033 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +000011034 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011035 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011036 case AXIS_CHILD:
11037#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011038 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011039#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011040 last = NULL;
11041 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +000011042 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011043 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011044 case AXIS_DESCENDANT:
11045#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011046 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011047#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011048 last = NULL;
11049 next = xmlXPathNextDescendant;
11050 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011051 case AXIS_DESCENDANT_OR_SELF:
11052#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011053 xmlGenericError(xmlGenericErrorContext,
11054 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011055#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011056 last = NULL;
11057 next = xmlXPathNextDescendantOrSelf;
11058 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011059 case AXIS_FOLLOWING:
11060#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011061 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011062#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011063 last = NULL;
11064 next = xmlXPathNextFollowing;
11065 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011066 case AXIS_FOLLOWING_SIBLING:
11067#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011068 xmlGenericError(xmlGenericErrorContext,
11069 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011070#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011071 last = NULL;
11072 next = xmlXPathNextFollowingSibling;
11073 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011074 case AXIS_NAMESPACE:
11075#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011076 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011077#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011078 first = NULL;
11079 last = NULL;
11080 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +000011081 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011082 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011083 case AXIS_PARENT:
11084#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011085 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011086#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011087 first = NULL;
11088 next = xmlXPathNextParent;
11089 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011090 case AXIS_PRECEDING:
11091#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011092 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011093#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011094 first = NULL;
11095 next = xmlXPathNextPrecedingInternal;
11096 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011097 case AXIS_PRECEDING_SIBLING:
11098#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011099 xmlGenericError(xmlGenericErrorContext,
11100 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011101#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011102 first = NULL;
11103 next = xmlXPathNextPrecedingSibling;
11104 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011105 case AXIS_SELF:
11106#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011107 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011108#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011109 first = NULL;
11110 last = NULL;
11111 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +000011112 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011113 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011114 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011115 if (next == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011116 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011117 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011118 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011119
11120 nodelist = obj->nodesetval;
11121 if (nodelist == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011122 xmlXPathReleaseObject(ctxt->context, obj);
11123 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011124 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011125 }
11126 addNode = xmlXPathNodeSetAddUnique;
11127 ret = NULL;
11128#ifdef DEBUG_STEP
11129 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011130 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011131 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011132 case NODE_TEST_NONE:
11133 xmlGenericError(xmlGenericErrorContext,
11134 " searching for none !!!\n");
11135 break;
11136 case NODE_TEST_TYPE:
11137 xmlGenericError(xmlGenericErrorContext,
11138 " searching for type %d\n", type);
11139 break;
11140 case NODE_TEST_PI:
11141 xmlGenericError(xmlGenericErrorContext,
11142 " searching for PI !!!\n");
11143 break;
11144 case NODE_TEST_ALL:
11145 xmlGenericError(xmlGenericErrorContext,
11146 " searching for *\n");
11147 break;
11148 case NODE_TEST_NS:
11149 xmlGenericError(xmlGenericErrorContext,
11150 " searching for namespace %s\n",
11151 prefix);
11152 break;
11153 case NODE_TEST_NAME:
11154 xmlGenericError(xmlGenericErrorContext,
11155 " searching for name %s\n", name);
11156 if (prefix != NULL)
11157 xmlGenericError(xmlGenericErrorContext,
11158 " with namespace %s\n", prefix);
11159 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011160 }
11161 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11162#endif
11163 /*
11164 * 2.3 Node Tests
11165 * - For the attribute axis, the principal node type is attribute.
11166 * - For the namespace axis, the principal node type is namespace.
11167 * - For other axes, the principal node type is element.
11168 *
11169 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011170 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011171 * select all element children of the context node
11172 */
11173 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011174 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011175 ctxt->context->node = nodelist->nodeTab[i];
11176
Daniel Veillardf06307e2001-07-03 10:35:50 +000011177 cur = NULL;
11178 list = xmlXPathNodeSetCreate(NULL);
11179 do {
11180 cur = next(ctxt, cur);
11181 if (cur == NULL)
11182 break;
11183 if ((first != NULL) && (*first == cur))
11184 break;
11185 if (((t % 256) == 0) &&
11186 (first != NULL) && (*first != NULL) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011187#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011188 (xmlXPathCmpNodesExt(*first, cur) >= 0))
11189#else
Daniel Veillardf06307e2001-07-03 10:35:50 +000011190 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011191#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011192 break;
11193 if ((last != NULL) && (*last == cur))
11194 break;
11195 if (((t % 256) == 0) &&
11196 (last != NULL) && (*last != NULL) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011197#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011198 (xmlXPathCmpNodesExt(cur, *last) >= 0))
11199#else
Daniel Veillardf06307e2001-07-03 10:35:50 +000011200 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011201#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011202 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011203 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011204#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011205 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
11206#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011207 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011208 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011209 ctxt->context->node = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011210 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011211 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011212 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011213 if ((cur->type == type) ||
11214 ((type == NODE_TYPE_NODE) &&
11215 ((cur->type == XML_DOCUMENT_NODE) ||
11216 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11217 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000011218 (cur->type == XML_NAMESPACE_DECL) ||
11219 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +000011220 (cur->type == XML_PI_NODE) ||
11221 (cur->type == XML_COMMENT_NODE) ||
11222 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +000011223 (cur->type == XML_TEXT_NODE))) ||
11224 ((type == NODE_TYPE_TEXT) &&
11225 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011226#ifdef DEBUG_STEP
11227 n++;
11228#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011229 addNode(list, cur);
11230 }
11231 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011232 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011233 if (cur->type == XML_PI_NODE) {
11234 if ((name != NULL) &&
11235 (!xmlStrEqual(name, cur->name)))
11236 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011237#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011238 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011239#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011240 addNode(list, cur);
11241 }
11242 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011243 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011244 if (axis == AXIS_ATTRIBUTE) {
11245 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011246#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011247 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011248#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011249 addNode(list, cur);
11250 }
11251 } else if (axis == AXIS_NAMESPACE) {
11252 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011253#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011254 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011255#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011256 xmlXPathNodeSetAddNs(list, ctxt->context->node,
11257 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011258 }
11259 } else {
11260 if (cur->type == XML_ELEMENT_NODE) {
11261 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011262#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011263 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011264#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011265 addNode(list, cur);
11266 } else if ((cur->ns != NULL) &&
11267 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011268#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011269 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011270#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011271 addNode(list, cur);
11272 }
11273 }
11274 }
11275 break;
11276 case NODE_TEST_NS:{
11277 TODO;
11278 break;
11279 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011280 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011281 switch (cur->type) {
11282 case XML_ELEMENT_NODE:
11283 if (xmlStrEqual(name, cur->name)) {
11284 if (prefix == NULL) {
11285 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011286#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011287 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011288#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011289 addNode(list, cur);
11290 }
11291 } else {
11292 if ((cur->ns != NULL) &&
11293 (xmlStrEqual(URI,
11294 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011295#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011296 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011297#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011298 addNode(list, cur);
11299 }
11300 }
11301 }
11302 break;
11303 case XML_ATTRIBUTE_NODE:{
11304 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011305
Daniel Veillardf06307e2001-07-03 10:35:50 +000011306 if (xmlStrEqual(name, attr->name)) {
11307 if (prefix == NULL) {
11308 if ((attr->ns == NULL) ||
11309 (attr->ns->prefix == NULL)) {
11310#ifdef DEBUG_STEP
11311 n++;
11312#endif
11313 addNode(list,
11314 (xmlNodePtr) attr);
11315 }
11316 } else {
11317 if ((attr->ns != NULL) &&
11318 (xmlStrEqual(URI,
11319 attr->ns->
11320 href))) {
11321#ifdef DEBUG_STEP
11322 n++;
11323#endif
11324 addNode(list,
11325 (xmlNodePtr) attr);
11326 }
11327 }
11328 }
11329 break;
11330 }
11331 case XML_NAMESPACE_DECL:
11332 if (cur->type == XML_NAMESPACE_DECL) {
11333 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011334
Daniel Veillardf06307e2001-07-03 10:35:50 +000011335 if ((ns->prefix != NULL) && (name != NULL)
11336 && (xmlStrEqual(ns->prefix, name))) {
11337#ifdef DEBUG_STEP
11338 n++;
11339#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011340 xmlXPathNodeSetAddNs(list,
11341 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011342 }
11343 }
11344 break;
11345 default:
11346 break;
11347 }
11348 break;
11349 break;
11350 }
11351 } while (cur != NULL);
11352
11353 /*
11354 * If there is some predicate filtering do it now
11355 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +000011356 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011357 xmlXPathObjectPtr obj2;
11358
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011359 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, list));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011360 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
11361 CHECK_TYPE0(XPATH_NODESET);
11362 obj2 = valuePop(ctxt);
11363 list = obj2->nodesetval;
11364 obj2->nodesetval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011365 xmlXPathReleaseObject(ctxt->context, obj2);
11366
William M. Brack2c19a7b2005-04-10 01:03:23 +000011367 if (ctxt->error != XPATH_EXPRESSION_OK) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011368 xmlXPathReleaseObject(ctxt->context, obj);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011369 xmlXPathFreeNodeSet(list);
11370 return(0);
11371 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011372 }
11373 if (ret == NULL) {
11374 ret = list;
11375 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +000011376 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011377 xmlXPathFreeNodeSet(list);
11378 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011379 }
11380 ctxt->context->node = tmp;
11381#ifdef DEBUG_STEP
11382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 "\nExamined %d nodes, found %d nodes at that step\n",
11384 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011385#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011386 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
11387
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011388 if ((obj->boolval) && (obj->user != NULL)) {
11389 ctxt->value->boolval = 1;
11390 ctxt->value->user = obj->user;
11391 obj->user = NULL;
11392 obj->boolval = 0;
11393 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011394 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011395 return(t);
11396}
11397
11398/**
11399 * xmlXPathNodeCollectAndTestNth:
11400 * @ctxt: the XPath Parser context
11401 * @op: the XPath precompiled step operation
11402 * @indx: the index to collect
11403 * @first: pointer to the first element in document order
11404 * @last: pointer to the last element in document order
11405 *
11406 * This is the function implementing a step: based on the current list
11407 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000011408 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +000011409 *
11410 * Pushes the new NodeSet resulting from the search.
11411 * Returns the number of node traversed
11412 */
11413static int
11414xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
11415 xmlXPathStepOpPtr op, int indx,
11416 xmlNodePtr * first, xmlNodePtr * last)
11417{
William M. Brack78637da2003-07-31 14:47:38 +000011418 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11419 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11420 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011421 const xmlChar *prefix = op->value4;
11422 const xmlChar *name = op->value5;
11423 const xmlChar *URI = NULL;
11424 int n = 0, t = 0;
11425
11426 int i;
11427 xmlNodeSetPtr list;
11428 xmlXPathTraversalFunction next = NULL;
11429 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11430 xmlNodePtr cur = NULL;
11431 xmlXPathObjectPtr obj;
11432 xmlNodeSetPtr nodelist;
11433 xmlNodePtr tmp;
11434
11435 CHECK_TYPE0(XPATH_NODESET);
11436 obj = valuePop(ctxt);
11437 addNode = xmlXPathNodeSetAdd;
11438 if (prefix != NULL) {
11439 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011440 if (URI == NULL) {
11441 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011442 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011443 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011444 }
11445#ifdef DEBUG_STEP_NTH
11446 xmlGenericError(xmlGenericErrorContext, "new step : ");
11447 if (first != NULL) {
11448 if (*first != NULL)
11449 xmlGenericError(xmlGenericErrorContext, "first = %s ",
11450 (*first)->name);
11451 else
11452 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
11453 }
11454 if (last != NULL) {
11455 if (*last != NULL)
11456 xmlGenericError(xmlGenericErrorContext, "last = %s ",
11457 (*last)->name);
11458 else
11459 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
11460 }
11461#endif
11462 switch (axis) {
11463 case AXIS_ANCESTOR:
11464#ifdef DEBUG_STEP_NTH
11465 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11466#endif
11467 first = NULL;
11468 next = xmlXPathNextAncestor;
11469 break;
11470 case AXIS_ANCESTOR_OR_SELF:
11471#ifdef DEBUG_STEP_NTH
11472 xmlGenericError(xmlGenericErrorContext,
11473 "axis 'ancestors-or-self' ");
11474#endif
11475 first = NULL;
11476 next = xmlXPathNextAncestorOrSelf;
11477 break;
11478 case AXIS_ATTRIBUTE:
11479#ifdef DEBUG_STEP_NTH
11480 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11481#endif
11482 first = NULL;
11483 last = NULL;
11484 next = xmlXPathNextAttribute;
11485 break;
11486 case AXIS_CHILD:
11487#ifdef DEBUG_STEP_NTH
11488 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11489#endif
11490 last = NULL;
11491 next = xmlXPathNextChild;
11492 break;
11493 case AXIS_DESCENDANT:
11494#ifdef DEBUG_STEP_NTH
11495 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11496#endif
11497 last = NULL;
11498 next = xmlXPathNextDescendant;
11499 break;
11500 case AXIS_DESCENDANT_OR_SELF:
11501#ifdef DEBUG_STEP_NTH
11502 xmlGenericError(xmlGenericErrorContext,
11503 "axis 'descendant-or-self' ");
11504#endif
11505 last = NULL;
11506 next = xmlXPathNextDescendantOrSelf;
11507 break;
11508 case AXIS_FOLLOWING:
11509#ifdef DEBUG_STEP_NTH
11510 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11511#endif
11512 last = NULL;
11513 next = xmlXPathNextFollowing;
11514 break;
11515 case AXIS_FOLLOWING_SIBLING:
11516#ifdef DEBUG_STEP_NTH
11517 xmlGenericError(xmlGenericErrorContext,
11518 "axis 'following-siblings' ");
11519#endif
11520 last = NULL;
11521 next = xmlXPathNextFollowingSibling;
11522 break;
11523 case AXIS_NAMESPACE:
11524#ifdef DEBUG_STEP_NTH
11525 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11526#endif
11527 last = NULL;
11528 first = NULL;
11529 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11530 break;
11531 case AXIS_PARENT:
11532#ifdef DEBUG_STEP_NTH
11533 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11534#endif
11535 first = NULL;
11536 next = xmlXPathNextParent;
11537 break;
11538 case AXIS_PRECEDING:
11539#ifdef DEBUG_STEP_NTH
11540 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11541#endif
11542 first = NULL;
11543 next = xmlXPathNextPrecedingInternal;
11544 break;
11545 case AXIS_PRECEDING_SIBLING:
11546#ifdef DEBUG_STEP_NTH
11547 xmlGenericError(xmlGenericErrorContext,
11548 "axis 'preceding-sibling' ");
11549#endif
11550 first = NULL;
11551 next = xmlXPathNextPrecedingSibling;
11552 break;
11553 case AXIS_SELF:
11554#ifdef DEBUG_STEP_NTH
11555 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11556#endif
11557 first = NULL;
11558 last = NULL;
11559 next = xmlXPathNextSelf;
11560 break;
11561 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011562 if (next == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011563 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011564 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011565 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011566
11567 nodelist = obj->nodesetval;
11568 if (nodelist == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011569 xmlXPathReleaseObject(ctxt->context, obj);
11570 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571 return(0);
11572 }
11573 addNode = xmlXPathNodeSetAddUnique;
11574#ifdef DEBUG_STEP_NTH
11575 xmlGenericError(xmlGenericErrorContext,
11576 " context contains %d nodes\n", nodelist->nodeNr);
11577 switch (test) {
11578 case NODE_TEST_NONE:
11579 xmlGenericError(xmlGenericErrorContext,
11580 " searching for none !!!\n");
11581 break;
11582 case NODE_TEST_TYPE:
11583 xmlGenericError(xmlGenericErrorContext,
11584 " searching for type %d\n", type);
11585 break;
11586 case NODE_TEST_PI:
11587 xmlGenericError(xmlGenericErrorContext,
11588 " searching for PI !!!\n");
11589 break;
11590 case NODE_TEST_ALL:
11591 xmlGenericError(xmlGenericErrorContext,
11592 " searching for *\n");
11593 break;
11594 case NODE_TEST_NS:
11595 xmlGenericError(xmlGenericErrorContext,
11596 " searching for namespace %s\n",
11597 prefix);
11598 break;
11599 case NODE_TEST_NAME:
11600 xmlGenericError(xmlGenericErrorContext,
11601 " searching for name %s\n", name);
11602 if (prefix != NULL)
11603 xmlGenericError(xmlGenericErrorContext,
11604 " with namespace %s\n", prefix);
11605 break;
11606 }
11607 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11608#endif
11609 /*
11610 * 2.3 Node Tests
11611 * - For the attribute axis, the principal node type is attribute.
11612 * - For the namespace axis, the principal node type is namespace.
11613 * - For other axes, the principal node type is element.
11614 *
11615 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011616 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +000011617 * select all element children of the context node
11618 */
11619 tmp = ctxt->context->node;
11620 list = xmlXPathNodeSetCreate(NULL);
11621 for (i = 0; i < nodelist->nodeNr; i++) {
11622 ctxt->context->node = nodelist->nodeTab[i];
11623
11624 cur = NULL;
11625 n = 0;
11626 do {
11627 cur = next(ctxt, cur);
11628 if (cur == NULL)
11629 break;
11630 if ((first != NULL) && (*first == cur))
11631 break;
11632 if (((t % 256) == 0) &&
11633 (first != NULL) && (*first != NULL) &&
11634 (xmlXPathCmpNodes(*first, cur) >= 0))
11635 break;
11636 if ((last != NULL) && (*last == cur))
11637 break;
11638 if (((t % 256) == 0) &&
11639 (last != NULL) && (*last != NULL) &&
11640 (xmlXPathCmpNodes(cur, *last) >= 0))
11641 break;
11642 t++;
11643 switch (test) {
11644 case NODE_TEST_NONE:
11645 ctxt->context->node = tmp;
11646 STRANGE return(0);
11647 case NODE_TEST_TYPE:
11648 if ((cur->type == type) ||
11649 ((type == NODE_TYPE_NODE) &&
11650 ((cur->type == XML_DOCUMENT_NODE) ||
11651 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11652 (cur->type == XML_ELEMENT_NODE) ||
11653 (cur->type == XML_PI_NODE) ||
11654 (cur->type == XML_COMMENT_NODE) ||
11655 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +000011656 (cur->type == XML_TEXT_NODE))) ||
11657 ((type == NODE_TYPE_TEXT) &&
11658 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011659 n++;
11660 if (n == indx)
11661 addNode(list, cur);
11662 }
11663 break;
11664 case NODE_TEST_PI:
11665 if (cur->type == XML_PI_NODE) {
11666 if ((name != NULL) &&
11667 (!xmlStrEqual(name, cur->name)))
11668 break;
11669 n++;
11670 if (n == indx)
11671 addNode(list, cur);
11672 }
11673 break;
11674 case NODE_TEST_ALL:
11675 if (axis == AXIS_ATTRIBUTE) {
11676 if (cur->type == XML_ATTRIBUTE_NODE) {
11677 n++;
11678 if (n == indx)
11679 addNode(list, cur);
11680 }
11681 } else if (axis == AXIS_NAMESPACE) {
11682 if (cur->type == XML_NAMESPACE_DECL) {
11683 n++;
11684 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011685 xmlXPathNodeSetAddNs(list, ctxt->context->node,
11686 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011687 }
11688 } else {
11689 if (cur->type == XML_ELEMENT_NODE) {
11690 if (prefix == NULL) {
11691 n++;
11692 if (n == indx)
11693 addNode(list, cur);
11694 } else if ((cur->ns != NULL) &&
11695 (xmlStrEqual(URI, cur->ns->href))) {
11696 n++;
11697 if (n == indx)
11698 addNode(list, cur);
11699 }
11700 }
11701 }
11702 break;
11703 case NODE_TEST_NS:{
11704 TODO;
11705 break;
11706 }
11707 case NODE_TEST_NAME:
11708 switch (cur->type) {
11709 case XML_ELEMENT_NODE:
11710 if (xmlStrEqual(name, cur->name)) {
11711 if (prefix == NULL) {
11712 if (cur->ns == NULL) {
11713 n++;
11714 if (n == indx)
11715 addNode(list, cur);
11716 }
11717 } else {
11718 if ((cur->ns != NULL) &&
11719 (xmlStrEqual(URI,
11720 cur->ns->href))) {
11721 n++;
11722 if (n == indx)
11723 addNode(list, cur);
11724 }
11725 }
11726 }
11727 break;
11728 case XML_ATTRIBUTE_NODE:{
11729 xmlAttrPtr attr = (xmlAttrPtr) cur;
11730
11731 if (xmlStrEqual(name, attr->name)) {
11732 if (prefix == NULL) {
11733 if ((attr->ns == NULL) ||
11734 (attr->ns->prefix == NULL)) {
11735 n++;
11736 if (n == indx)
11737 addNode(list, cur);
11738 }
11739 } else {
11740 if ((attr->ns != NULL) &&
11741 (xmlStrEqual(URI,
11742 attr->ns->
11743 href))) {
11744 n++;
11745 if (n == indx)
11746 addNode(list, cur);
11747 }
11748 }
11749 }
11750 break;
11751 }
11752 case XML_NAMESPACE_DECL:
11753 if (cur->type == XML_NAMESPACE_DECL) {
11754 xmlNsPtr ns = (xmlNsPtr) cur;
11755
11756 if ((ns->prefix != NULL) && (name != NULL)
11757 && (xmlStrEqual(ns->prefix, name))) {
11758 n++;
11759 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011760 xmlXPathNodeSetAddNs(list,
11761 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011762 }
11763 }
11764 break;
11765 default:
11766 break;
11767 }
11768 break;
11769 break;
11770 }
11771 } while (n < indx);
11772 }
11773 ctxt->context->node = tmp;
11774#ifdef DEBUG_STEP_NTH
11775 xmlGenericError(xmlGenericErrorContext,
11776 "\nExamined %d nodes, found %d nodes at that step\n",
11777 t, list->nodeNr);
11778#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011779 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011780 if ((obj->boolval) && (obj->user != NULL)) {
11781 ctxt->value->boolval = 1;
11782 ctxt->value->user = obj->user;
11783 obj->user = NULL;
11784 obj->boolval = 0;
11785 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011786 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011787 return(t);
11788}
11789
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011790static int
11791xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11792 xmlXPathStepOpPtr op, xmlNodePtr * first);
11793
Daniel Veillardf06307e2001-07-03 10:35:50 +000011794/**
11795 * xmlXPathCompOpEvalFirst:
11796 * @ctxt: the XPath parser context with the compiled expression
11797 * @op: an XPath compiled operation
11798 * @first: the first elem found so far
11799 *
11800 * Evaluate the Precompiled XPath operation searching only the first
11801 * element in document order
11802 *
11803 * Returns the number of examined objects.
11804 */
11805static int
11806xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11807 xmlXPathStepOpPtr op, xmlNodePtr * first)
11808{
11809 int total = 0, cur;
11810 xmlXPathCompExprPtr comp;
11811 xmlXPathObjectPtr arg1, arg2;
11812
Daniel Veillard556c6682001-10-06 09:59:51 +000011813 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011814 comp = ctxt->comp;
11815 switch (op->op) {
11816 case XPATH_OP_END:
11817 return (0);
11818 case XPATH_OP_UNION:
11819 total =
11820 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11821 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000011822 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011823 if ((ctxt->value != NULL)
11824 && (ctxt->value->type == XPATH_NODESET)
11825 && (ctxt->value->nodesetval != NULL)
11826 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11827 /*
11828 * limit tree traversing to first node in the result
11829 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011830 /*
11831 * OPTIMIZE TODO: This implicitely sorts
11832 * the result, even if not needed. E.g. if the argument
11833 * of the count() function, no sorting is needed.
11834 * OPTIMIZE TODO: How do we know if the node-list wasn't
11835 * aready sorted?
11836 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011837 if (ctxt->value->nodesetval->nodeNr > 1)
11838 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011839 *first = ctxt->value->nodesetval->nodeTab[0];
11840 }
11841 cur =
11842 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11843 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000011844 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011845 CHECK_TYPE0(XPATH_NODESET);
11846 arg2 = valuePop(ctxt);
11847
11848 CHECK_TYPE0(XPATH_NODESET);
11849 arg1 = valuePop(ctxt);
11850
11851 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11852 arg2->nodesetval);
11853 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011854 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011855 /* optimizer */
11856 if (total > cur)
11857 xmlXPathCompSwap(op);
11858 return (total + cur);
11859 case XPATH_OP_ROOT:
11860 xmlXPathRoot(ctxt);
11861 return (0);
11862 case XPATH_OP_NODE:
11863 if (op->ch1 != -1)
11864 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011865 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011866 if (op->ch2 != -1)
11867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011868 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011869 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11870 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011871 return (total);
11872 case XPATH_OP_RESET:
11873 if (op->ch1 != -1)
11874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011875 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011876 if (op->ch2 != -1)
11877 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011878 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011879 ctxt->context->node = NULL;
11880 return (total);
11881 case XPATH_OP_COLLECT:{
11882 if (op->ch1 == -1)
11883 return (total);
11884
11885 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011886 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011887
11888 /*
11889 * Optimization for [n] selection where n is a number
11890 */
11891 if ((op->ch2 != -1) &&
11892 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
11893 (comp->steps[op->ch2].ch1 == -1) &&
11894 (comp->steps[op->ch2].ch2 != -1) &&
11895 (comp->steps[comp->steps[op->ch2].ch2].op ==
11896 XPATH_OP_VALUE)) {
11897 xmlXPathObjectPtr val;
11898
11899 val = comp->steps[comp->steps[op->ch2].ch2].value4;
11900 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
11901 int indx = (int) val->floatval;
11902
11903 if (val->floatval == (float) indx) {
11904 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
11905 first, NULL);
11906 return (total);
11907 }
11908 }
11909 }
11910 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
11911 return (total);
11912 }
11913 case XPATH_OP_VALUE:
11914 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011915 xmlXPathCacheObjectCopy(ctxt->context,
11916 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011917 return (0);
11918 case XPATH_OP_SORT:
11919 if (op->ch1 != -1)
11920 total +=
11921 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11922 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000011923 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011924 if ((ctxt->value != NULL)
11925 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011926 && (ctxt->value->nodesetval != NULL)
11927 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000011928 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11929 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011930#ifdef XP_OPTIMIZED_FILTER_FIRST
11931 case XPATH_OP_FILTER:
11932 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11933 return (total);
11934#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011935 default:
11936 return (xmlXPathCompOpEval(ctxt, op));
11937 }
11938}
11939
11940/**
11941 * xmlXPathCompOpEvalLast:
11942 * @ctxt: the XPath parser context with the compiled expression
11943 * @op: an XPath compiled operation
11944 * @last: the last elem found so far
11945 *
11946 * Evaluate the Precompiled XPath operation searching only the last
11947 * element in document order
11948 *
William M. Brack08171912003-12-29 02:52:11 +000011949 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000011950 */
11951static int
11952xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11953 xmlNodePtr * last)
11954{
11955 int total = 0, cur;
11956 xmlXPathCompExprPtr comp;
11957 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000011958 xmlNodePtr bak;
11959 xmlDocPtr bakd;
11960 int pp;
11961 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011962
Daniel Veillard556c6682001-10-06 09:59:51 +000011963 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011964 comp = ctxt->comp;
11965 switch (op->op) {
11966 case XPATH_OP_END:
11967 return (0);
11968 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000011969 bakd = ctxt->context->doc;
11970 bak = ctxt->context->node;
11971 pp = ctxt->context->proximityPosition;
11972 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011973 total =
11974 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000011975 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011976 if ((ctxt->value != NULL)
11977 && (ctxt->value->type == XPATH_NODESET)
11978 && (ctxt->value->nodesetval != NULL)
11979 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11980 /*
11981 * limit tree traversing to first node in the result
11982 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011983 if (ctxt->value->nodesetval->nodeNr > 1)
11984 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011985 *last =
11986 ctxt->value->nodesetval->nodeTab[ctxt->value->
11987 nodesetval->nodeNr -
11988 1];
11989 }
William M. Brackce4fc562004-01-22 02:47:18 +000011990 ctxt->context->doc = bakd;
11991 ctxt->context->node = bak;
11992 ctxt->context->proximityPosition = pp;
11993 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011994 cur =
11995 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000011996 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011997 if ((ctxt->value != NULL)
11998 && (ctxt->value->type == XPATH_NODESET)
11999 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012000 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012001 }
12002 CHECK_TYPE0(XPATH_NODESET);
12003 arg2 = valuePop(ctxt);
12004
12005 CHECK_TYPE0(XPATH_NODESET);
12006 arg1 = valuePop(ctxt);
12007
12008 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12009 arg2->nodesetval);
12010 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012011 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012012 /* optimizer */
12013 if (total > cur)
12014 xmlXPathCompSwap(op);
12015 return (total + cur);
12016 case XPATH_OP_ROOT:
12017 xmlXPathRoot(ctxt);
12018 return (0);
12019 case XPATH_OP_NODE:
12020 if (op->ch1 != -1)
12021 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012022 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012023 if (op->ch2 != -1)
12024 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012025 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012026 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12027 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012028 return (total);
12029 case XPATH_OP_RESET:
12030 if (op->ch1 != -1)
12031 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012032 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012033 if (op->ch2 != -1)
12034 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012035 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012036 ctxt->context->node = NULL;
12037 return (total);
12038 case XPATH_OP_COLLECT:{
12039 if (op->ch1 == -1)
12040 return (0);
12041
12042 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012043 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012044
12045 /*
12046 * Optimization for [n] selection where n is a number
12047 */
12048 if ((op->ch2 != -1) &&
12049 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12050 (comp->steps[op->ch2].ch1 == -1) &&
12051 (comp->steps[op->ch2].ch2 != -1) &&
12052 (comp->steps[comp->steps[op->ch2].ch2].op ==
12053 XPATH_OP_VALUE)) {
12054 xmlXPathObjectPtr val;
12055
12056 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12057 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12058 int indx = (int) val->floatval;
12059
12060 if (val->floatval == (float) indx) {
12061 total +=
12062 xmlXPathNodeCollectAndTestNth(ctxt, op,
12063 indx, NULL,
12064 last);
12065 return (total);
12066 }
12067 }
12068 }
12069 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
12070 return (total);
12071 }
12072 case XPATH_OP_VALUE:
12073 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012074 xmlXPathCacheObjectCopy(ctxt->context,
12075 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012076 return (0);
12077 case XPATH_OP_SORT:
12078 if (op->ch1 != -1)
12079 total +=
12080 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12081 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012082 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012083 if ((ctxt->value != NULL)
12084 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012085 && (ctxt->value->nodesetval != NULL)
12086 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012087 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12088 return (total);
12089 default:
12090 return (xmlXPathCompOpEval(ctxt, op));
12091 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012092}
12093
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012094#ifdef XP_OPTIMIZED_FILTER_FIRST
12095static int
12096xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12097 xmlXPathStepOpPtr op, xmlNodePtr * first)
12098{
12099 int total = 0;
12100 xmlXPathCompExprPtr comp;
12101 xmlXPathObjectPtr res;
12102 xmlXPathObjectPtr obj;
12103 xmlNodeSetPtr oldset;
12104 xmlNodePtr oldnode;
12105 xmlDocPtr oldDoc;
12106 int i;
12107
12108 CHECK_ERROR0;
12109 comp = ctxt->comp;
12110 /*
12111 * Optimization for ()[last()] selection i.e. the last elem
12112 */
12113 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12114 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12115 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12116 int f = comp->steps[op->ch2].ch1;
12117
12118 if ((f != -1) &&
12119 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12120 (comp->steps[f].value5 == NULL) &&
12121 (comp->steps[f].value == 0) &&
12122 (comp->steps[f].value4 != NULL) &&
12123 (xmlStrEqual
12124 (comp->steps[f].value4, BAD_CAST "last"))) {
12125 xmlNodePtr last = NULL;
12126
12127 total +=
12128 xmlXPathCompOpEvalLast(ctxt,
12129 &comp->steps[op->ch1],
12130 &last);
12131 CHECK_ERROR0;
12132 /*
12133 * The nodeset should be in document order,
12134 * Keep only the last value
12135 */
12136 if ((ctxt->value != NULL) &&
12137 (ctxt->value->type == XPATH_NODESET) &&
12138 (ctxt->value->nodesetval != NULL) &&
12139 (ctxt->value->nodesetval->nodeTab != NULL) &&
12140 (ctxt->value->nodesetval->nodeNr > 1)) {
12141 ctxt->value->nodesetval->nodeTab[0] =
12142 ctxt->value->nodesetval->nodeTab[ctxt->
12143 value->
12144 nodesetval->
12145 nodeNr -
12146 1];
12147 ctxt->value->nodesetval->nodeNr = 1;
12148 *first = *(ctxt->value->nodesetval->nodeTab);
12149 }
12150 return (total);
12151 }
12152 }
12153
12154 if (op->ch1 != -1)
12155 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12156 CHECK_ERROR0;
12157 if (op->ch2 == -1)
12158 return (total);
12159 if (ctxt->value == NULL)
12160 return (total);
12161
12162#ifdef LIBXML_XPTR_ENABLED
12163 oldnode = ctxt->context->node;
12164 /*
12165 * Hum are we filtering the result of an XPointer expression
12166 */
12167 if (ctxt->value->type == XPATH_LOCATIONSET) {
12168 xmlXPathObjectPtr tmp = NULL;
12169 xmlLocationSetPtr newlocset = NULL;
12170 xmlLocationSetPtr oldlocset;
12171
12172 /*
12173 * Extract the old locset, and then evaluate the result of the
12174 * expression for all the element in the locset. use it to grow
12175 * up a new locset.
12176 */
12177 CHECK_TYPE0(XPATH_LOCATIONSET);
12178 obj = valuePop(ctxt);
12179 oldlocset = obj->user;
12180 ctxt->context->node = NULL;
12181
12182 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12183 ctxt->context->contextSize = 0;
12184 ctxt->context->proximityPosition = 0;
12185 if (op->ch2 != -1)
12186 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12187 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012188 if (res != NULL) {
12189 xmlXPathReleaseObject(ctxt->context, res);
12190 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012191 valuePush(ctxt, obj);
12192 CHECK_ERROR0;
12193 return (total);
12194 }
12195 newlocset = xmlXPtrLocationSetCreate(NULL);
12196
12197 for (i = 0; i < oldlocset->locNr; i++) {
12198 /*
12199 * Run the evaluation with a node list made of a
12200 * single item in the nodelocset.
12201 */
12202 ctxt->context->node = oldlocset->locTab[i]->user;
12203 ctxt->context->contextSize = oldlocset->locNr;
12204 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012205 if (tmp == NULL) {
12206 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12207 ctxt->context->node);
12208 } else {
12209 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12210 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012211 }
12212 valuePush(ctxt, tmp);
12213 if (op->ch2 != -1)
12214 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12215 if (ctxt->error != XPATH_EXPRESSION_OK) {
12216 xmlXPathFreeObject(obj);
12217 return(0);
12218 }
12219 /*
12220 * The result of the evaluation need to be tested to
12221 * decided whether the filter succeeded or not
12222 */
12223 res = valuePop(ctxt);
12224 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12225 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012226 xmlXPathCacheObjectCopy(ctxt->context,
12227 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012228 }
12229 /*
12230 * Cleanup
12231 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012232 if (res != NULL) {
12233 xmlXPathReleaseObject(ctxt->context, res);
12234 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012235 if (ctxt->value == tmp) {
12236 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012237 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012238 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012239 * REVISIT TODO: Don't create a temporary nodeset
12240 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012241 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012242 /* OLD: xmlXPathFreeObject(res); */
12243 } else
12244 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012245 ctxt->context->node = NULL;
12246 /*
12247 * Only put the first node in the result, then leave.
12248 */
12249 if (newlocset->locNr > 0) {
12250 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12251 break;
12252 }
12253 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012254 if (tmp != NULL) {
12255 xmlXPathReleaseObject(ctxt->context, tmp);
12256 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012257 /*
12258 * The result is used as the new evaluation locset.
12259 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012260 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012261 ctxt->context->node = NULL;
12262 ctxt->context->contextSize = -1;
12263 ctxt->context->proximityPosition = -1;
12264 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12265 ctxt->context->node = oldnode;
12266 return (total);
12267 }
12268#endif /* LIBXML_XPTR_ENABLED */
12269
12270 /*
12271 * Extract the old set, and then evaluate the result of the
12272 * expression for all the element in the set. use it to grow
12273 * up a new set.
12274 */
12275 CHECK_TYPE0(XPATH_NODESET);
12276 obj = valuePop(ctxt);
12277 oldset = obj->nodesetval;
12278
12279 oldnode = ctxt->context->node;
12280 oldDoc = ctxt->context->doc;
12281 ctxt->context->node = NULL;
12282
12283 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12284 ctxt->context->contextSize = 0;
12285 ctxt->context->proximityPosition = 0;
12286 /* QUESTION TODO: Why was this code commented out?
12287 if (op->ch2 != -1)
12288 total +=
12289 xmlXPathCompOpEval(ctxt,
12290 &comp->steps[op->ch2]);
12291 CHECK_ERROR0;
12292 res = valuePop(ctxt);
12293 if (res != NULL)
12294 xmlXPathFreeObject(res);
12295 */
12296 valuePush(ctxt, obj);
12297 ctxt->context->node = oldnode;
12298 CHECK_ERROR0;
12299 } else {
12300 xmlNodeSetPtr newset;
12301 xmlXPathObjectPtr tmp = NULL;
12302 /*
12303 * Initialize the new set.
12304 * Also set the xpath document in case things like
12305 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012306 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012307 newset = xmlXPathNodeSetCreate(NULL);
12308
12309 for (i = 0; i < oldset->nodeNr; i++) {
12310 /*
12311 * Run the evaluation with a node list made of
12312 * a single item in the nodeset.
12313 */
12314 ctxt->context->node = oldset->nodeTab[i];
12315 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12316 (oldset->nodeTab[i]->doc != NULL))
12317 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012318 if (tmp == NULL) {
12319 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12320 ctxt->context->node);
12321 } else {
12322 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12323 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012324 }
12325 valuePush(ctxt, tmp);
12326 ctxt->context->contextSize = oldset->nodeNr;
12327 ctxt->context->proximityPosition = i + 1;
12328 if (op->ch2 != -1)
12329 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12330 if (ctxt->error != XPATH_EXPRESSION_OK) {
12331 xmlXPathFreeNodeSet(newset);
12332 xmlXPathFreeObject(obj);
12333 return(0);
12334 }
12335 /*
12336 * The result of the evaluation needs to be tested to
12337 * decide whether the filter succeeded or not
12338 */
12339 res = valuePop(ctxt);
12340 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12341 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12342 }
12343 /*
12344 * Cleanup
12345 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012346 if (res != NULL) {
12347 xmlXPathReleaseObject(ctxt->context, res);
12348 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012349 if (ctxt->value == tmp) {
12350 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012351 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012352 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012353 * in order to avoid massive recreation inside this
12354 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012355 */
12356 xmlXPathNodeSetClear(tmp->nodesetval);
12357 } else
12358 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012359 ctxt->context->node = NULL;
12360 /*
12361 * Only put the first node in the result, then leave.
12362 */
12363 if (newset->nodeNr > 0) {
12364 *first = *(newset->nodeTab);
12365 break;
12366 }
12367 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012368 if (tmp != NULL) {
12369 xmlXPathReleaseObject(ctxt->context, tmp);
12370 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012371 /*
12372 * The result is used as the new evaluation set.
12373 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012374 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012375 ctxt->context->node = NULL;
12376 ctxt->context->contextSize = -1;
12377 ctxt->context->proximityPosition = -1;
12378 /* may want to move this past the '}' later */
12379 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012380 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012381 }
12382 ctxt->context->node = oldnode;
12383 return(total);
12384}
12385#endif /* XP_OPTIMIZED_FILTER_FIRST */
12386
Owen Taylor3473f882001-02-23 17:55:21 +000012387/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012388 * xmlXPathCompOpEval:
12389 * @ctxt: the XPath parser context with the compiled expression
12390 * @op: an XPath compiled operation
12391 *
12392 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000012393 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012394 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012395static int
12396xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12397{
12398 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012399 int equal, ret;
12400 xmlXPathCompExprPtr comp;
12401 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012402 xmlNodePtr bak;
12403 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000012404 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000012405 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012406
Daniel Veillard556c6682001-10-06 09:59:51 +000012407 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012408 comp = ctxt->comp;
12409 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012410 case XPATH_OP_END:
12411 return (0);
12412 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012413 bakd = ctxt->context->doc;
12414 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012415 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012416 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012417 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012418 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012419 xmlXPathBooleanFunction(ctxt, 1);
12420 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12421 return (total);
12422 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012423 ctxt->context->doc = bakd;
12424 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012425 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012426 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012427 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012428 if (ctxt->error) {
12429 xmlXPathFreeObject(arg2);
12430 return(0);
12431 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012432 xmlXPathBooleanFunction(ctxt, 1);
12433 arg1 = valuePop(ctxt);
12434 arg1->boolval &= arg2->boolval;
12435 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012436 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012437 return (total);
12438 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012439 bakd = ctxt->context->doc;
12440 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012441 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012442 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012443 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012444 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012445 xmlXPathBooleanFunction(ctxt, 1);
12446 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12447 return (total);
12448 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012449 ctxt->context->doc = bakd;
12450 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012451 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012452 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012453 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012454 if (ctxt->error) {
12455 xmlXPathFreeObject(arg2);
12456 return(0);
12457 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012458 xmlXPathBooleanFunction(ctxt, 1);
12459 arg1 = valuePop(ctxt);
12460 arg1->boolval |= arg2->boolval;
12461 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012462 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012463 return (total);
12464 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012465 bakd = ctxt->context->doc;
12466 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012467 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012468 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012469 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012470 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012471 ctxt->context->doc = bakd;
12472 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012473 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012474 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012475 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012476 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000012477 if (op->value)
12478 equal = xmlXPathEqualValues(ctxt);
12479 else
12480 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012481 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012482 return (total);
12483 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012484 bakd = ctxt->context->doc;
12485 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012486 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012487 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012488 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012489 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012490 ctxt->context->doc = bakd;
12491 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012492 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012493 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012495 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012496 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012497 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012498 return (total);
12499 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012500 bakd = ctxt->context->doc;
12501 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012502 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012503 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012505 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012506 if (op->ch2 != -1) {
12507 ctxt->context->doc = bakd;
12508 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012509 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012510 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012511 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012512 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012513 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012514 if (op->value == 0)
12515 xmlXPathSubValues(ctxt);
12516 else if (op->value == 1)
12517 xmlXPathAddValues(ctxt);
12518 else if (op->value == 2)
12519 xmlXPathValueFlipSign(ctxt);
12520 else if (op->value == 3) {
12521 CAST_TO_NUMBER;
12522 CHECK_TYPE0(XPATH_NUMBER);
12523 }
12524 return (total);
12525 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012526 bakd = ctxt->context->doc;
12527 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012528 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012529 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012530 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012531 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012532 ctxt->context->doc = bakd;
12533 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012534 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012535 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012536 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012537 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012538 if (op->value == 0)
12539 xmlXPathMultValues(ctxt);
12540 else if (op->value == 1)
12541 xmlXPathDivValues(ctxt);
12542 else if (op->value == 2)
12543 xmlXPathModValues(ctxt);
12544 return (total);
12545 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012546 bakd = ctxt->context->doc;
12547 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012548 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012549 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012551 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012552 ctxt->context->doc = bakd;
12553 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012554 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012555 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012556 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012557 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012558 CHECK_TYPE0(XPATH_NODESET);
12559 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012560
Daniel Veillardf06307e2001-07-03 10:35:50 +000012561 CHECK_TYPE0(XPATH_NODESET);
12562 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012563
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012564 if ((arg1->nodesetval == NULL) ||
12565 ((arg2->nodesetval != NULL) &&
12566 (arg2->nodesetval->nodeNr != 0)))
12567 {
12568 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12569 arg2->nodesetval);
12570 }
12571
Daniel Veillardf06307e2001-07-03 10:35:50 +000012572 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012573 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012574 return (total);
12575 case XPATH_OP_ROOT:
12576 xmlXPathRoot(ctxt);
12577 return (total);
12578 case XPATH_OP_NODE:
12579 if (op->ch1 != -1)
12580 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012581 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012582 if (op->ch2 != -1)
12583 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012584 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012585 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12586 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012587 return (total);
12588 case XPATH_OP_RESET:
12589 if (op->ch1 != -1)
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 if (op->ch2 != -1)
12593 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012594 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012595 ctxt->context->node = NULL;
12596 return (total);
12597 case XPATH_OP_COLLECT:{
12598 if (op->ch1 == -1)
12599 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012600
Daniel Veillardf06307e2001-07-03 10:35:50 +000012601 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012602 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012603
Daniel Veillardf06307e2001-07-03 10:35:50 +000012604 /*
12605 * Optimization for [n] selection where n is a number
12606 */
12607 if ((op->ch2 != -1) &&
12608 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12609 (comp->steps[op->ch2].ch1 == -1) &&
12610 (comp->steps[op->ch2].ch2 != -1) &&
12611 (comp->steps[comp->steps[op->ch2].ch2].op ==
12612 XPATH_OP_VALUE)) {
12613 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000012614
Daniel Veillardf06307e2001-07-03 10:35:50 +000012615 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12616 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12617 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012618
Daniel Veillardf06307e2001-07-03 10:35:50 +000012619 if (val->floatval == (float) indx) {
12620 total +=
12621 xmlXPathNodeCollectAndTestNth(ctxt, op,
12622 indx, NULL,
12623 NULL);
12624 return (total);
12625 }
12626 }
12627 }
12628 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
12629 return (total);
12630 }
12631 case XPATH_OP_VALUE:
12632 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012633 xmlXPathCacheObjectCopy(ctxt->context,
12634 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012635 return (total);
12636 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000012637 xmlXPathObjectPtr val;
12638
Daniel Veillardf06307e2001-07-03 10:35:50 +000012639 if (op->ch1 != -1)
12640 total +=
12641 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012642 if (op->value5 == NULL) {
12643 val = xmlXPathVariableLookup(ctxt->context, op->value4);
12644 if (val == NULL) {
12645 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12646 return(0);
12647 }
12648 valuePush(ctxt, val);
12649 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012650 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012651
Daniel Veillardf06307e2001-07-03 10:35:50 +000012652 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12653 if (URI == NULL) {
12654 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012655 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012656 op->value4, op->value5);
12657 return (total);
12658 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012659 val = xmlXPathVariableLookupNS(ctxt->context,
12660 op->value4, URI);
12661 if (val == NULL) {
12662 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12663 return(0);
12664 }
12665 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012666 }
12667 return (total);
12668 }
12669 case XPATH_OP_FUNCTION:{
12670 xmlXPathFunction func;
12671 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000012672 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012673
12674 if (op->ch1 != -1)
12675 total +=
12676 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012677 if (ctxt->valueNr < op->value) {
12678 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012679 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000012680 ctxt->error = XPATH_INVALID_OPERAND;
12681 return (total);
12682 }
12683 for (i = 0; i < op->value; i++)
12684 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
12685 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012686 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000012687 ctxt->error = XPATH_INVALID_OPERAND;
12688 return (total);
12689 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012690 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000012691 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012692 else {
12693 const xmlChar *URI = NULL;
12694
12695 if (op->value5 == NULL)
12696 func =
12697 xmlXPathFunctionLookup(ctxt->context,
12698 op->value4);
12699 else {
12700 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12701 if (URI == NULL) {
12702 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012703 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012704 op->value4, op->value5);
12705 return (total);
12706 }
12707 func = xmlXPathFunctionLookupNS(ctxt->context,
12708 op->value4, URI);
12709 }
12710 if (func == NULL) {
12711 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012712 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012713 op->value4);
12714 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012715 }
William M. Brackad0e67c2004-12-01 14:35:10 +000012716 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012717 op->cacheURI = (void *) URI;
12718 }
12719 oldFunc = ctxt->context->function;
12720 oldFuncURI = ctxt->context->functionURI;
12721 ctxt->context->function = op->value4;
12722 ctxt->context->functionURI = op->cacheURI;
12723 func(ctxt, op->value);
12724 ctxt->context->function = oldFunc;
12725 ctxt->context->functionURI = oldFuncURI;
12726 return (total);
12727 }
12728 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000012729 bakd = ctxt->context->doc;
12730 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000012731 pp = ctxt->context->proximityPosition;
12732 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012733 if (op->ch1 != -1)
12734 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000012735 ctxt->context->contextSize = cs;
12736 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000012737 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000012738 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000012739 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000012740 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012741 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000012742 ctxt->context->doc = bakd;
12743 ctxt->context->node = bak;
12744 CHECK_ERROR0;
12745 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012746 return (total);
12747 case XPATH_OP_PREDICATE:
12748 case XPATH_OP_FILTER:{
12749 xmlXPathObjectPtr res;
12750 xmlXPathObjectPtr obj, tmp;
12751 xmlNodeSetPtr newset = NULL;
12752 xmlNodeSetPtr oldset;
12753 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000012754 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012755 int i;
12756
12757 /*
12758 * Optimization for ()[1] selection i.e. the first elem
12759 */
12760 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012761#ifdef XP_OPTIMIZED_FILTER_FIRST
12762 /*
12763 * FILTER TODO: Can we assume that the inner processing
12764 * will result in an ordered list if we have an
12765 * XPATH_OP_FILTER?
12766 * What about an additional field or flag on
12767 * xmlXPathObject like @sorted ? This way we wouln'd need
12768 * to assume anything, so it would be more robust and
12769 * easier to optimize.
12770 */
12771 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12772 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12773#else
12774 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12775#endif
12776 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012777 xmlXPathObjectPtr val;
12778
12779 val = comp->steps[op->ch2].value4;
12780 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12781 (val->floatval == 1.0)) {
12782 xmlNodePtr first = NULL;
12783
12784 total +=
12785 xmlXPathCompOpEvalFirst(ctxt,
12786 &comp->steps[op->ch1],
12787 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012788 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012789 /*
12790 * The nodeset should be in document order,
12791 * Keep only the first value
12792 */
12793 if ((ctxt->value != NULL) &&
12794 (ctxt->value->type == XPATH_NODESET) &&
12795 (ctxt->value->nodesetval != NULL) &&
12796 (ctxt->value->nodesetval->nodeNr > 1))
12797 ctxt->value->nodesetval->nodeNr = 1;
12798 return (total);
12799 }
12800 }
12801 /*
12802 * Optimization for ()[last()] selection i.e. the last elem
12803 */
12804 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12805 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12806 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12807 int f = comp->steps[op->ch2].ch1;
12808
12809 if ((f != -1) &&
12810 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12811 (comp->steps[f].value5 == NULL) &&
12812 (comp->steps[f].value == 0) &&
12813 (comp->steps[f].value4 != NULL) &&
12814 (xmlStrEqual
12815 (comp->steps[f].value4, BAD_CAST "last"))) {
12816 xmlNodePtr last = NULL;
12817
12818 total +=
12819 xmlXPathCompOpEvalLast(ctxt,
12820 &comp->steps[op->ch1],
12821 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012822 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012823 /*
12824 * The nodeset should be in document order,
12825 * Keep only the last value
12826 */
12827 if ((ctxt->value != NULL) &&
12828 (ctxt->value->type == XPATH_NODESET) &&
12829 (ctxt->value->nodesetval != NULL) &&
12830 (ctxt->value->nodesetval->nodeTab != NULL) &&
12831 (ctxt->value->nodesetval->nodeNr > 1)) {
12832 ctxt->value->nodesetval->nodeTab[0] =
12833 ctxt->value->nodesetval->nodeTab[ctxt->
12834 value->
12835 nodesetval->
12836 nodeNr -
12837 1];
12838 ctxt->value->nodesetval->nodeNr = 1;
12839 }
12840 return (total);
12841 }
12842 }
12843
12844 if (op->ch1 != -1)
12845 total +=
12846 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012847 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012848 if (op->ch2 == -1)
12849 return (total);
12850 if (ctxt->value == NULL)
12851 return (total);
12852
12853 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012854
12855#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000012856 /*
12857 * Hum are we filtering the result of an XPointer expression
12858 */
12859 if (ctxt->value->type == XPATH_LOCATIONSET) {
12860 xmlLocationSetPtr newlocset = NULL;
12861 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012862
Daniel Veillardf06307e2001-07-03 10:35:50 +000012863 /*
12864 * Extract the old locset, and then evaluate the result of the
12865 * expression for all the element in the locset. use it to grow
12866 * up a new locset.
12867 */
12868 CHECK_TYPE0(XPATH_LOCATIONSET);
12869 obj = valuePop(ctxt);
12870 oldlocset = obj->user;
12871 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012872
Daniel Veillardf06307e2001-07-03 10:35:50 +000012873 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12874 ctxt->context->contextSize = 0;
12875 ctxt->context->proximityPosition = 0;
12876 if (op->ch2 != -1)
12877 total +=
12878 xmlXPathCompOpEval(ctxt,
12879 &comp->steps[op->ch2]);
12880 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012881 if (res != NULL) {
12882 xmlXPathReleaseObject(ctxt->context, res);
12883 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012884 valuePush(ctxt, obj);
12885 CHECK_ERROR0;
12886 return (total);
12887 }
12888 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012889
Daniel Veillardf06307e2001-07-03 10:35:50 +000012890 for (i = 0; i < oldlocset->locNr; i++) {
12891 /*
12892 * Run the evaluation with a node list made of a
12893 * single item in the nodelocset.
12894 */
12895 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012896 ctxt->context->contextSize = oldlocset->locNr;
12897 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012898 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12899 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000012900 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012901
Daniel Veillardf06307e2001-07-03 10:35:50 +000012902 if (op->ch2 != -1)
12903 total +=
12904 xmlXPathCompOpEval(ctxt,
12905 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000012906 if (ctxt->error != XPATH_EXPRESSION_OK) {
12907 xmlXPathFreeObject(obj);
12908 return(0);
12909 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012910
Daniel Veillardf06307e2001-07-03 10:35:50 +000012911 /*
12912 * The result of the evaluation need to be tested to
12913 * decided whether the filter succeeded or not
12914 */
12915 res = valuePop(ctxt);
12916 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12917 xmlXPtrLocationSetAdd(newlocset,
12918 xmlXPathObjectCopy
12919 (oldlocset->locTab[i]));
12920 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012921
Daniel Veillardf06307e2001-07-03 10:35:50 +000012922 /*
12923 * Cleanup
12924 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012925 if (res != NULL) {
12926 xmlXPathReleaseObject(ctxt->context, res);
12927 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012928 if (ctxt->value == tmp) {
12929 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012930 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012931 }
12932
12933 ctxt->context->node = NULL;
12934 }
12935
12936 /*
12937 * The result is used as the new evaluation locset.
12938 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012939 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012940 ctxt->context->node = NULL;
12941 ctxt->context->contextSize = -1;
12942 ctxt->context->proximityPosition = -1;
12943 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12944 ctxt->context->node = oldnode;
12945 return (total);
12946 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012947#endif /* LIBXML_XPTR_ENABLED */
12948
Daniel Veillardf06307e2001-07-03 10:35:50 +000012949 /*
12950 * Extract the old set, and then evaluate the result of the
12951 * expression for all the element in the set. use it to grow
12952 * up a new set.
12953 */
12954 CHECK_TYPE0(XPATH_NODESET);
12955 obj = valuePop(ctxt);
12956 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000012957
Daniel Veillardf06307e2001-07-03 10:35:50 +000012958 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000012959 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012960 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012961
Daniel Veillardf06307e2001-07-03 10:35:50 +000012962 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12963 ctxt->context->contextSize = 0;
12964 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000012965/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000012966 if (op->ch2 != -1)
12967 total +=
12968 xmlXPathCompOpEval(ctxt,
12969 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012970 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012971 res = valuePop(ctxt);
12972 if (res != NULL)
12973 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000012974*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000012975 valuePush(ctxt, obj);
12976 ctxt->context->node = oldnode;
12977 CHECK_ERROR0;
12978 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012979 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012980 /*
12981 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000012982 * Also set the xpath document in case things like
12983 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000012984 */
12985 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012986
Daniel Veillardf06307e2001-07-03 10:35:50 +000012987 for (i = 0; i < oldset->nodeNr; i++) {
12988 /*
12989 * Run the evaluation with a node list made of
12990 * a single item in the nodeset.
12991 */
12992 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000012993 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12994 (oldset->nodeTab[i]->doc != NULL))
12995 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012996 if (tmp == NULL) {
12997 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12998 ctxt->context->node);
12999 } else {
13000 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13001 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013002 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013003 valuePush(ctxt, tmp);
13004 ctxt->context->contextSize = oldset->nodeNr;
13005 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013006
Daniel Veillardf06307e2001-07-03 10:35:50 +000013007 if (op->ch2 != -1)
13008 total +=
13009 xmlXPathCompOpEval(ctxt,
13010 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013011 if (ctxt->error != XPATH_EXPRESSION_OK) {
13012 xmlXPathFreeNodeSet(newset);
13013 xmlXPathFreeObject(obj);
13014 return(0);
13015 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013016
Daniel Veillardf06307e2001-07-03 10:35:50 +000013017 /*
William M. Brack08171912003-12-29 02:52:11 +000013018 * The result of the evaluation needs to be tested to
13019 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000013020 */
13021 res = valuePop(ctxt);
13022 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13023 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13024 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013025
Daniel Veillardf06307e2001-07-03 10:35:50 +000013026 /*
13027 * Cleanup
13028 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013029 if (res != NULL) {
13030 xmlXPathReleaseObject(ctxt->context, res);
13031 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013032 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013033 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013034 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013035 /*
13036 * REVISIT TODO: Don't free the temporary nodeset
13037 * in order to avoid massive recreation inside this
13038 * loop.
13039 */
13040 /* xmlXPathFreeObject(res); */
13041 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013042 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013043 ctxt->context->node = NULL;
13044 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013045 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013046 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013047 /*
13048 * The result is used as the new evaluation set.
13049 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013050 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013051 ctxt->context->node = NULL;
13052 ctxt->context->contextSize = -1;
13053 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013054 /* may want to move this past the '}' later */
13055 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013056 valuePush(ctxt,
13057 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013058 }
13059 ctxt->context->node = oldnode;
13060 return (total);
13061 }
13062 case XPATH_OP_SORT:
13063 if (op->ch1 != -1)
13064 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013065 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013066 if ((ctxt->value != NULL) &&
13067 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013068 (ctxt->value->nodesetval != NULL) &&
13069 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013070 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013071 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013072 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013073 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013074#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013075 case XPATH_OP_RANGETO:{
13076 xmlXPathObjectPtr range;
13077 xmlXPathObjectPtr res, obj;
13078 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013079 xmlLocationSetPtr newlocset = NULL;
13080 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013081 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013082 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013083
Daniel Veillardf06307e2001-07-03 10:35:50 +000013084 if (op->ch1 != -1)
13085 total +=
13086 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13087 if (op->ch2 == -1)
13088 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013089
William M. Brack08171912003-12-29 02:52:11 +000013090 if (ctxt->value->type == XPATH_LOCATIONSET) {
13091 /*
13092 * Extract the old locset, and then evaluate the result of the
13093 * expression for all the element in the locset. use it to grow
13094 * up a new locset.
13095 */
13096 CHECK_TYPE0(XPATH_LOCATIONSET);
13097 obj = valuePop(ctxt);
13098 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013099
William M. Brack08171912003-12-29 02:52:11 +000013100 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013101 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013102 ctxt->context->contextSize = 0;
13103 ctxt->context->proximityPosition = 0;
13104 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13105 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013106 if (res != NULL) {
13107 xmlXPathReleaseObject(ctxt->context, res);
13108 }
William M. Brack08171912003-12-29 02:52:11 +000013109 valuePush(ctxt, obj);
13110 CHECK_ERROR0;
13111 return (total);
13112 }
13113 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013114
William M. Brack08171912003-12-29 02:52:11 +000013115 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013116 /*
William M. Brack08171912003-12-29 02:52:11 +000013117 * Run the evaluation with a node list made of a
13118 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013119 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013120 ctxt->context->node = oldlocset->locTab[i]->user;
13121 ctxt->context->contextSize = oldlocset->locNr;
13122 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013123 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13124 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013125 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013126
Daniel Veillardf06307e2001-07-03 10:35:50 +000013127 if (op->ch2 != -1)
13128 total +=
13129 xmlXPathCompOpEval(ctxt,
13130 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013131 if (ctxt->error != XPATH_EXPRESSION_OK) {
13132 xmlXPathFreeObject(obj);
13133 return(0);
13134 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013135
Daniel Veillardf06307e2001-07-03 10:35:50 +000013136 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013137 if (res->type == XPATH_LOCATIONSET) {
13138 xmlLocationSetPtr rloc =
13139 (xmlLocationSetPtr)res->user;
13140 for (j=0; j<rloc->locNr; j++) {
13141 range = xmlXPtrNewRange(
13142 oldlocset->locTab[i]->user,
13143 oldlocset->locTab[i]->index,
13144 rloc->locTab[j]->user2,
13145 rloc->locTab[j]->index2);
13146 if (range != NULL) {
13147 xmlXPtrLocationSetAdd(newlocset, range);
13148 }
13149 }
13150 } else {
13151 range = xmlXPtrNewRangeNodeObject(
13152 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13153 if (range != NULL) {
13154 xmlXPtrLocationSetAdd(newlocset,range);
13155 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013156 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013157
Daniel Veillardf06307e2001-07-03 10:35:50 +000013158 /*
13159 * Cleanup
13160 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013161 if (res != NULL) {
13162 xmlXPathReleaseObject(ctxt->context, res);
13163 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013164 if (ctxt->value == tmp) {
13165 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013166 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013167 }
13168
13169 ctxt->context->node = NULL;
13170 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013171 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013172 CHECK_TYPE0(XPATH_NODESET);
13173 obj = valuePop(ctxt);
13174 oldset = obj->nodesetval;
13175 ctxt->context->node = NULL;
13176
13177 newlocset = xmlXPtrLocationSetCreate(NULL);
13178
13179 if (oldset != NULL) {
13180 for (i = 0; i < oldset->nodeNr; i++) {
13181 /*
13182 * Run the evaluation with a node list made of a single item
13183 * in the nodeset.
13184 */
13185 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013186 /*
13187 * OPTIMIZE TODO: Avoid recreation for every iteration.
13188 */
13189 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13190 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013191 valuePush(ctxt, tmp);
13192
13193 if (op->ch2 != -1)
13194 total +=
13195 xmlXPathCompOpEval(ctxt,
13196 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013197 if (ctxt->error != XPATH_EXPRESSION_OK) {
13198 xmlXPathFreeObject(obj);
13199 return(0);
13200 }
William M. Brack08171912003-12-29 02:52:11 +000013201
William M. Brack08171912003-12-29 02:52:11 +000013202 res = valuePop(ctxt);
13203 range =
13204 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13205 res);
13206 if (range != NULL) {
13207 xmlXPtrLocationSetAdd(newlocset, range);
13208 }
13209
13210 /*
13211 * Cleanup
13212 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013213 if (res != NULL) {
13214 xmlXPathReleaseObject(ctxt->context, res);
13215 }
William M. Brack08171912003-12-29 02:52:11 +000013216 if (ctxt->value == tmp) {
13217 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013218 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013219 }
13220
13221 ctxt->context->node = NULL;
13222 }
13223 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013224 }
13225
13226 /*
13227 * The result is used as the new evaluation set.
13228 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013229 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013230 ctxt->context->node = NULL;
13231 ctxt->context->contextSize = -1;
13232 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013233 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013234 return (total);
13235 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013236#endif /* LIBXML_XPTR_ENABLED */
13237 }
13238 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013239 "XPath: unknown precompiled operation %d\n", op->op);
13240 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013241}
13242
Daniel Veillard56de87e2005-02-16 00:22:29 +000013243#ifdef XPATH_STREAMING
13244/**
13245 * xmlXPathRunStreamEval:
13246 * @ctxt: the XPath parser context with the compiled expression
13247 *
13248 * Evaluate the Precompiled Streamable XPath expression in the given context.
13249 */
13250static xmlXPathObjectPtr
13251xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013252 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013253 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013254 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013255#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13256 int eval_all_nodes;
13257#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000013258 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013259 xmlXPathObjectPtr retval;
13260 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013261
13262 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013263
13264 if ((ctxt == NULL) || (comp == NULL))
13265 return(NULL);
13266 max_depth = xmlPatternMaxDepth(comp);
13267 if (max_depth == -1)
13268 return(NULL);
13269 if (max_depth == -2)
13270 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013271 min_depth = xmlPatternMinDepth(comp);
13272 if (min_depth == -1)
13273 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013274 from_root = xmlPatternFromRoot(comp);
13275 if (from_root < 0)
13276 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013277#if 0
13278 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13279#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013280
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013281 retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013282 if (retval == NULL)
13283 return(NULL);
13284
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013285 /*
13286 * handle the special cases of / amd . being matched
13287 */
13288 if (min_depth == 0) {
13289 if (from_root) {
13290 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
13291 } else {
13292 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
13293 }
13294 }
13295 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013296 return(retval);
13297 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013298
Daniel Veillard56de87e2005-02-16 00:22:29 +000013299 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013300 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013301 } else if (ctxt->node != NULL) {
13302 switch (ctxt->node->type) {
13303 case XML_ELEMENT_NODE:
13304 case XML_DOCUMENT_NODE:
13305 case XML_DOCUMENT_FRAG_NODE:
13306 case XML_HTML_DOCUMENT_NODE:
13307#ifdef LIBXML_DOCB_ENABLED
13308 case XML_DOCB_DOCUMENT_NODE:
13309#endif
13310 cur = ctxt->node;
13311 break;
13312 case XML_ATTRIBUTE_NODE:
13313 case XML_TEXT_NODE:
13314 case XML_CDATA_SECTION_NODE:
13315 case XML_ENTITY_REF_NODE:
13316 case XML_ENTITY_NODE:
13317 case XML_PI_NODE:
13318 case XML_COMMENT_NODE:
13319 case XML_NOTATION_NODE:
13320 case XML_DTD_NODE:
13321 case XML_DOCUMENT_TYPE_NODE:
13322 case XML_ELEMENT_DECL:
13323 case XML_ATTRIBUTE_DECL:
13324 case XML_ENTITY_DECL:
13325 case XML_NAMESPACE_DECL:
13326 case XML_XINCLUDE_START:
13327 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013328 break;
13329 }
13330 limit = cur;
13331 }
13332 if (cur == NULL)
13333 return(retval);
13334
13335 patstream = xmlPatternGetStreamCtxt(comp);
13336 if (patstream == NULL) {
13337 return(retval);
13338 }
13339
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013340#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13341 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13342#endif
13343
Daniel Veillard56de87e2005-02-16 00:22:29 +000013344 if (from_root) {
13345 ret = xmlStreamPush(patstream, NULL, NULL);
13346 if (ret < 0) {
13347 } else if (ret == 1) {
13348 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13349 }
13350 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013351 depth = 0;
13352 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013353next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013354 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013355 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013356
13357 switch (cur->type) {
13358 case XML_ELEMENT_NODE:
13359#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13360 case XML_TEXT_NODE:
13361 case XML_CDATA_SECTION_NODE:
13362 case XML_COMMENT_NODE:
13363 case XML_PI_NODE:
13364#endif
13365 if (cur->type == XML_ELEMENT_NODE) {
13366 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013367 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000013368 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013369#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13370 else if (eval_all_nodes)
13371 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13372 else
13373 break;
13374#endif
13375
13376 if (ret < 0) {
13377 /* NOP. */
13378 } else if (ret == 1) {
13379 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13380 }
13381 if ((cur->children == NULL) || (depth >= max_depth)) {
13382 ret = xmlStreamPop(patstream);
13383 while (cur->next != NULL) {
13384 cur = cur->next;
13385 if ((cur->type != XML_ENTITY_DECL) &&
13386 (cur->type != XML_DTD_NODE))
13387 goto next_node;
13388 }
13389 }
13390 default:
13391 break;
13392 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013393
13394scan_children:
13395 if ((cur->children != NULL) && (depth < max_depth)) {
13396 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013397 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000013398 */
13399 if (cur->children->type != XML_ENTITY_DECL) {
13400 cur = cur->children;
13401 depth++;
13402 /*
13403 * Skip DTDs
13404 */
13405 if (cur->type != XML_DTD_NODE)
13406 continue;
13407 }
13408 }
13409
13410 if (cur == limit)
13411 break;
13412
13413 while (cur->next != NULL) {
13414 cur = cur->next;
13415 if ((cur->type != XML_ENTITY_DECL) &&
13416 (cur->type != XML_DTD_NODE))
13417 goto next_node;
13418 }
13419
13420 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013421 cur = cur->parent;
13422 depth--;
13423 if ((cur == NULL) || (cur == limit))
13424 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013425 if (cur->type == XML_ELEMENT_NODE) {
13426 ret = xmlStreamPop(patstream);
13427 }
13428#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13429 else if ((eval_all_nodes) &&
13430 ((cur->type == XML_TEXT_NODE) ||
13431 (cur->type == XML_CDATA_SECTION_NODE) ||
13432 (cur->type == XML_COMMENT_NODE) ||
13433 (cur->type == XML_PI_NODE)))
13434 {
13435 ret = xmlStreamPop(patstream);
13436 }
13437#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013438 if (cur->next != NULL) {
13439 cur = cur->next;
13440 break;
13441 }
13442 } while (cur != NULL);
13443
13444 } while ((cur != NULL) && (depth >= 0));
13445done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013446#if 0
13447 printf("stream eval: checked %d nodes selected %d\n",
13448 nb_nodes, retval->nodesetval->nodeNr);
13449#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013450 xmlFreeStreamCtxt(patstream);
13451 return(retval);
13452}
13453#endif /* XPATH_STREAMING */
13454
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013455/**
13456 * xmlXPathRunEval:
13457 * @ctxt: the XPath parser context with the compiled expression
13458 *
13459 * Evaluate the Precompiled XPath expression in the given context.
13460 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013461static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013462xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
13463 xmlXPathCompExprPtr comp;
13464
13465 if ((ctxt == NULL) || (ctxt->comp == NULL))
13466 return;
13467
13468 if (ctxt->valueTab == NULL) {
13469 /* Allocate the value stack */
13470 ctxt->valueTab = (xmlXPathObjectPtr *)
13471 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13472 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000013473 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013474 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013475 }
13476 ctxt->valueNr = 0;
13477 ctxt->valueMax = 10;
13478 ctxt->value = NULL;
13479 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013480#ifdef XPATH_STREAMING
13481 if (ctxt->comp->stream) {
13482 xmlXPathObjectPtr ret;
13483 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
13484 if (ret != NULL) {
13485 valuePush(ctxt, ret);
13486 return;
13487 }
13488 }
13489#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013490 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013491 if(comp->last < 0) {
13492 xmlGenericError(xmlGenericErrorContext,
13493 "xmlXPathRunEval: last is less than zero\n");
13494 return;
13495 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013496 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13497}
13498
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013499/************************************************************************
13500 * *
13501 * Public interfaces *
13502 * *
13503 ************************************************************************/
13504
13505/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013506 * xmlXPathEvalPredicate:
13507 * @ctxt: the XPath context
13508 * @res: the Predicate Expression evaluation result
13509 *
13510 * Evaluate a predicate result for the current node.
13511 * A PredicateExpr is evaluated by evaluating the Expr and converting
13512 * the result to a boolean. If the result is a number, the result will
13513 * be converted to true if the number is equal to the position of the
13514 * context node in the context node list (as returned by the position
13515 * function) and will be converted to false otherwise; if the result
13516 * is not a number, then the result will be converted as if by a call
13517 * to the boolean function.
13518 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013519 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013520 */
13521int
13522xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013523 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013524 switch (res->type) {
13525 case XPATH_BOOLEAN:
13526 return(res->boolval);
13527 case XPATH_NUMBER:
13528 return(res->floatval == ctxt->proximityPosition);
13529 case XPATH_NODESET:
13530 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013531 if (res->nodesetval == NULL)
13532 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013533 return(res->nodesetval->nodeNr != 0);
13534 case XPATH_STRING:
13535 return((res->stringval != NULL) &&
13536 (xmlStrlen(res->stringval) != 0));
13537 default:
13538 STRANGE
13539 }
13540 return(0);
13541}
13542
13543/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013544 * xmlXPathEvaluatePredicateResult:
13545 * @ctxt: the XPath Parser context
13546 * @res: the Predicate Expression evaluation result
13547 *
13548 * Evaluate a predicate result for the current node.
13549 * A PredicateExpr is evaluated by evaluating the Expr and converting
13550 * the result to a boolean. If the result is a number, the result will
13551 * be converted to true if the number is equal to the position of the
13552 * context node in the context node list (as returned by the position
13553 * function) and will be converted to false otherwise; if the result
13554 * is not a number, then the result will be converted as if by a call
13555 * to the boolean function.
13556 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013557 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013558 */
13559int
13560xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13561 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013562 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013563 switch (res->type) {
13564 case XPATH_BOOLEAN:
13565 return(res->boolval);
13566 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000013567#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000013568 return((res->floatval == ctxt->context->proximityPosition) &&
13569 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000013570#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013571 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000013572#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013573 case XPATH_NODESET:
13574 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000013575 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000013576 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013577 return(res->nodesetval->nodeNr != 0);
13578 case XPATH_STRING:
13579 return((res->stringval != NULL) &&
13580 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000013581#ifdef LIBXML_XPTR_ENABLED
13582 case XPATH_LOCATIONSET:{
13583 xmlLocationSetPtr ptr = res->user;
13584 if (ptr == NULL)
13585 return(0);
13586 return (ptr->locNr != 0);
13587 }
13588#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013589 default:
13590 STRANGE
13591 }
13592 return(0);
13593}
13594
Daniel Veillard56de87e2005-02-16 00:22:29 +000013595#ifdef XPATH_STREAMING
13596/**
13597 * xmlXPathTryStreamCompile:
13598 * @ctxt: an XPath context
13599 * @str: the XPath expression
13600 *
13601 * Try to compile the XPath expression as a streamable subset.
13602 *
13603 * Returns the compiled expression or NULL if failed to compile.
13604 */
13605static xmlXPathCompExprPtr
13606xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13607 /*
13608 * Optimization: use streaming patterns when the XPath expression can
13609 * be compiled to a stream lookup
13610 */
13611 xmlPatternPtr stream;
13612 xmlXPathCompExprPtr comp;
13613 xmlDictPtr dict = NULL;
13614 const xmlChar **namespaces = NULL;
13615 xmlNsPtr ns;
13616 int i, j;
13617
13618 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13619 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013620 const xmlChar *tmp;
13621
13622 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013623 * We don't try to handle expressions using the verbose axis
13624 * specifiers ("::"), just the simplied form at this point.
13625 * Additionally, if there is no list of namespaces available and
13626 * there's a ":" in the expression, indicating a prefixed QName,
13627 * then we won't try to compile either. xmlPatterncompile() needs
13628 * to have a list of namespaces at compilation time in order to
13629 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013630 */
13631 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013632 if ((tmp != NULL) &&
13633 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13634 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013635
Daniel Veillard56de87e2005-02-16 00:22:29 +000013636 if (ctxt != NULL) {
13637 dict = ctxt->dict;
13638 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000013639 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000013640 if (namespaces == NULL) {
13641 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
13642 return(NULL);
13643 }
13644 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
13645 ns = ctxt->namespaces[j];
13646 namespaces[i++] = ns->href;
13647 namespaces[i++] = ns->prefix;
13648 }
13649 namespaces[i++] = NULL;
13650 namespaces[i++] = NULL;
13651 }
13652 }
13653
William M. Brackea152c02005-06-09 18:12:28 +000013654 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
13655 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013656 if (namespaces != NULL) {
13657 xmlFree((xmlChar **)namespaces);
13658 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013659 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
13660 comp = xmlXPathNewCompExpr();
13661 if (comp == NULL) {
13662 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
13663 return(NULL);
13664 }
13665 comp->stream = stream;
13666 comp->dict = dict;
13667 if (comp->dict)
13668 xmlDictReference(comp->dict);
13669 return(comp);
13670 }
13671 xmlFreePattern(stream);
13672 }
13673 return(NULL);
13674}
13675#endif /* XPATH_STREAMING */
13676
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013677/**
Daniel Veillard4773df22004-01-23 13:15:13 +000013678 * xmlXPathCtxtCompile:
13679 * @ctxt: an XPath context
13680 * @str: the XPath expression
13681 *
13682 * Compile an XPath expression
13683 *
13684 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13685 * the caller has to free the object.
13686 */
13687xmlXPathCompExprPtr
13688xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13689 xmlXPathParserContextPtr pctxt;
13690 xmlXPathCompExprPtr comp;
13691
Daniel Veillard56de87e2005-02-16 00:22:29 +000013692#ifdef XPATH_STREAMING
13693 comp = xmlXPathTryStreamCompile(ctxt, str);
13694 if (comp != NULL)
13695 return(comp);
13696#endif
13697
Daniel Veillard4773df22004-01-23 13:15:13 +000013698 xmlXPathInit();
13699
13700 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013701 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000013702
13703 if( pctxt->error != XPATH_EXPRESSION_OK )
13704 {
13705 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000013706 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000013707 }
13708
13709 if (*pctxt->cur != 0) {
13710 /*
13711 * aleksey: in some cases this line prints *second* error message
13712 * (see bug #78858) and probably this should be fixed.
13713 * However, we are not sure that all error messages are printed
13714 * out in other places. It's not critical so we leave it as-is for now
13715 */
13716 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13717 comp = NULL;
13718 } else {
13719 comp = pctxt->comp;
13720 pctxt->comp = NULL;
13721 }
13722 xmlXPathFreeParserContext(pctxt);
13723 if (comp != NULL) {
13724 comp->expr = xmlStrdup(str);
13725#ifdef DEBUG_EVAL_COUNTS
13726 comp->string = xmlStrdup(str);
13727 comp->nb = 0;
13728#endif
13729 }
13730 return(comp);
13731}
13732
13733/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013734 * xmlXPathCompile:
13735 * @str: the XPath expression
13736 *
13737 * Compile an XPath expression
13738 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000013739 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013740 * the caller has to free the object.
13741 */
13742xmlXPathCompExprPtr
13743xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000013744 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013745}
13746
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013747/**
13748 * xmlXPathCompiledEval:
13749 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000013750 * @ctx: the XPath context
13751 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013752 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000013753 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013754 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000013755 * the caller has to free the object.
13756 */
13757xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013758xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000013759 xmlXPathParserContextPtr ctxt;
13760 xmlXPathObjectPtr res, tmp, init = NULL;
13761 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000013762#ifndef LIBXML_THREAD_ENABLED
13763 static int reentance = 0;
13764#endif
Owen Taylor3473f882001-02-23 17:55:21 +000013765
William M. Brackf13f77f2004-11-12 16:03:48 +000013766 CHECK_CTXT(ctx)
13767
13768 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013769 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000013770 xmlXPathInit();
13771
Daniel Veillard81463942001-10-16 12:34:39 +000013772#ifndef LIBXML_THREAD_ENABLED
13773 reentance++;
13774 if (reentance > 1)
13775 xmlXPathDisableOptimizer = 1;
13776#endif
13777
Daniel Veillardf06307e2001-07-03 10:35:50 +000013778#ifdef DEBUG_EVAL_COUNTS
13779 comp->nb++;
13780 if ((comp->string != NULL) && (comp->nb > 100)) {
13781 fprintf(stderr, "100 x %s\n", comp->string);
13782 comp->nb = 0;
13783 }
13784#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013785 ctxt = xmlXPathCompParserContext(comp, ctx);
13786 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000013787
13788 if (ctxt->value == NULL) {
13789 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013790 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000013791 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000013792 } else {
13793 res = valuePop(ctxt);
13794 }
13795
Daniel Veillardf06307e2001-07-03 10:35:50 +000013796
Owen Taylor3473f882001-02-23 17:55:21 +000013797 do {
13798 tmp = valuePop(ctxt);
13799 if (tmp != NULL) {
13800 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013801 stack++;
13802 xmlXPathReleaseObject(ctx, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000013803 }
13804 } while (tmp != NULL);
13805 if ((stack != 0) && (res != NULL)) {
13806 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013807 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000013808 stack);
13809 }
13810 if (ctxt->error != XPATH_EXPRESSION_OK) {
13811 xmlXPathFreeObject(res);
13812 res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013813 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013814
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013815 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013816 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000013817#ifndef LIBXML_THREAD_ENABLED
13818 reentance--;
13819#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013820 return(res);
13821}
13822
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013823/**
13824 * xmlXPathEvalExpr:
13825 * @ctxt: the XPath Parser context
13826 *
13827 * Parse and evaluate an XPath expression in the given context,
13828 * then push the result on the context stack
13829 */
13830void
13831xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013832#ifdef XPATH_STREAMING
13833 xmlXPathCompExprPtr comp;
13834#endif
13835
Daniel Veillarda82b1822004-11-08 16:24:57 +000013836 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013837
13838#ifdef XPATH_STREAMING
13839 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13840 if (comp != NULL) {
13841 if (ctxt->comp != NULL)
13842 xmlXPathFreeCompExpr(ctxt->comp);
13843 ctxt->comp = comp;
13844 if (ctxt->cur != NULL)
13845 while (*ctxt->cur != 0) ctxt->cur++;
13846 } else
13847#endif
13848 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013849 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013850 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000013851 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013852 xmlXPathRunEval(ctxt);
13853}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013854
13855/**
13856 * xmlXPathEval:
13857 * @str: the XPath expression
13858 * @ctx: the XPath context
13859 *
13860 * Evaluate the XPath Location Path in the given context.
13861 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013862 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013863 * the caller has to free the object.
13864 */
13865xmlXPathObjectPtr
13866xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13867 xmlXPathParserContextPtr ctxt;
13868 xmlXPathObjectPtr res, tmp, init = NULL;
13869 int stack = 0;
13870
William M. Brackf13f77f2004-11-12 16:03:48 +000013871 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013872
William M. Brackf13f77f2004-11-12 16:03:48 +000013873 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013874
13875 ctxt = xmlXPathNewParserContext(str, ctx);
13876 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013877
13878 if (ctxt->value == NULL) {
13879 xmlGenericError(xmlGenericErrorContext,
13880 "xmlXPathEval: evaluation failed\n");
13881 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013882 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
13883#ifdef XPATH_STREAMING
13884 && (ctxt->comp->stream == NULL)
13885#endif
13886 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013887 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13888 res = NULL;
13889 } else {
13890 res = valuePop(ctxt);
13891 }
13892
13893 do {
13894 tmp = valuePop(ctxt);
13895 if (tmp != NULL) {
13896 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013897 stack++;
13898 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013899 }
13900 } while (tmp != NULL);
13901 if ((stack != 0) && (res != NULL)) {
13902 xmlGenericError(xmlGenericErrorContext,
13903 "xmlXPathEval: %d object left on the stack\n",
13904 stack);
13905 }
13906 if (ctxt->error != XPATH_EXPRESSION_OK) {
13907 xmlXPathFreeObject(res);
13908 res = NULL;
13909 }
13910
Owen Taylor3473f882001-02-23 17:55:21 +000013911 xmlXPathFreeParserContext(ctxt);
13912 return(res);
13913}
13914
13915/**
13916 * xmlXPathEvalExpression:
13917 * @str: the XPath expression
13918 * @ctxt: the XPath context
13919 *
13920 * Evaluate the XPath expression in the given context.
13921 *
13922 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13923 * the caller has to free the object.
13924 */
13925xmlXPathObjectPtr
13926xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13927 xmlXPathParserContextPtr pctxt;
13928 xmlXPathObjectPtr res, tmp;
13929 int stack = 0;
13930
William M. Brackf13f77f2004-11-12 16:03:48 +000013931 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000013932
William M. Brackf13f77f2004-11-12 16:03:48 +000013933 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000013934
13935 pctxt = xmlXPathNewParserContext(str, ctxt);
13936 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000013937
13938 if (*pctxt->cur != 0) {
13939 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13940 res = NULL;
13941 } else {
13942 res = valuePop(pctxt);
13943 }
13944 do {
13945 tmp = valuePop(pctxt);
13946 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013947 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000013948 stack++;
13949 }
13950 } while (tmp != NULL);
13951 if ((stack != 0) && (res != NULL)) {
13952 xmlGenericError(xmlGenericErrorContext,
13953 "xmlXPathEvalExpression: %d object left on the stack\n",
13954 stack);
13955 }
13956 xmlXPathFreeParserContext(pctxt);
13957 return(res);
13958}
13959
Daniel Veillard42766c02002-08-22 20:52:17 +000013960/************************************************************************
13961 * *
13962 * Extra functions not pertaining to the XPath spec *
13963 * *
13964 ************************************************************************/
13965/**
13966 * xmlXPathEscapeUriFunction:
13967 * @ctxt: the XPath Parser context
13968 * @nargs: the number of arguments
13969 *
13970 * Implement the escape-uri() XPath function
13971 * string escape-uri(string $str, bool $escape-reserved)
13972 *
13973 * This function applies the URI escaping rules defined in section 2 of [RFC
13974 * 2396] to the string supplied as $uri-part, which typically represents all
13975 * or part of a URI. The effect of the function is to replace any special
13976 * character in the string by an escape sequence of the form %xx%yy...,
13977 * where xxyy... is the hexadecimal representation of the octets used to
13978 * represent the character in UTF-8.
13979 *
13980 * The set of characters that are escaped depends on the setting of the
13981 * boolean argument $escape-reserved.
13982 *
13983 * If $escape-reserved is true, all characters are escaped other than lower
13984 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13985 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13986 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13987 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13988 * A-F).
13989 *
13990 * If $escape-reserved is false, the behavior differs in that characters
13991 * referred to in [RFC 2396] as reserved characters are not escaped. These
13992 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13993 *
13994 * [RFC 2396] does not define whether escaped URIs should use lower case or
13995 * upper case for hexadecimal digits. To ensure that escaped URIs can be
13996 * compared using string comparison functions, this function must always use
13997 * the upper-case letters A-F.
13998 *
13999 * Generally, $escape-reserved should be set to true when escaping a string
14000 * that is to form a single part of a URI, and to false when escaping an
14001 * entire URI or URI reference.
14002 *
14003 * In the case of non-ascii characters, the string is encoded according to
14004 * utf-8 and then converted according to RFC 2396.
14005 *
14006 * Examples
14007 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14008 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14009 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14010 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14011 *
14012 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014013static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014014xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14015 xmlXPathObjectPtr str;
14016 int escape_reserved;
14017 xmlBufferPtr target;
14018 xmlChar *cptr;
14019 xmlChar escape[4];
14020
14021 CHECK_ARITY(2);
14022
14023 escape_reserved = xmlXPathPopBoolean(ctxt);
14024
14025 CAST_TO_STRING;
14026 str = valuePop(ctxt);
14027
14028 target = xmlBufferCreate();
14029
14030 escape[0] = '%';
14031 escape[3] = 0;
14032
14033 if (target) {
14034 for (cptr = str->stringval; *cptr; cptr++) {
14035 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14036 (*cptr >= 'a' && *cptr <= 'z') ||
14037 (*cptr >= '0' && *cptr <= '9') ||
14038 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14039 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14040 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14041 (*cptr == '%' &&
14042 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14043 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14044 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14045 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14046 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14047 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14048 (!escape_reserved &&
14049 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14050 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14051 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14052 *cptr == ','))) {
14053 xmlBufferAdd(target, cptr, 1);
14054 } else {
14055 if ((*cptr >> 4) < 10)
14056 escape[1] = '0' + (*cptr >> 4);
14057 else
14058 escape[1] = 'A' - 10 + (*cptr >> 4);
14059 if ((*cptr & 0xF) < 10)
14060 escape[2] = '0' + (*cptr & 0xF);
14061 else
14062 escape[2] = 'A' - 10 + (*cptr & 0xF);
14063
14064 xmlBufferAdd(target, &escape[0], 3);
14065 }
14066 }
14067 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014068 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14069 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014070 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014071 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014072}
14073
Owen Taylor3473f882001-02-23 17:55:21 +000014074/**
14075 * xmlXPathRegisterAllFunctions:
14076 * @ctxt: the XPath context
14077 *
14078 * Registers all default XPath functions in this context
14079 */
14080void
14081xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14082{
14083 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14084 xmlXPathBooleanFunction);
14085 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14086 xmlXPathCeilingFunction);
14087 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14088 xmlXPathCountFunction);
14089 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14090 xmlXPathConcatFunction);
14091 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14092 xmlXPathContainsFunction);
14093 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14094 xmlXPathIdFunction);
14095 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14096 xmlXPathFalseFunction);
14097 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14098 xmlXPathFloorFunction);
14099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14100 xmlXPathLastFunction);
14101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14102 xmlXPathLangFunction);
14103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14104 xmlXPathLocalNameFunction);
14105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14106 xmlXPathNotFunction);
14107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14108 xmlXPathNameFunction);
14109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14110 xmlXPathNamespaceURIFunction);
14111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14112 xmlXPathNormalizeFunction);
14113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14114 xmlXPathNumberFunction);
14115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14116 xmlXPathPositionFunction);
14117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14118 xmlXPathRoundFunction);
14119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14120 xmlXPathStringFunction);
14121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14122 xmlXPathStringLengthFunction);
14123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14124 xmlXPathStartsWithFunction);
14125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14126 xmlXPathSubstringFunction);
14127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14128 xmlXPathSubstringBeforeFunction);
14129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14130 xmlXPathSubstringAfterFunction);
14131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14132 xmlXPathSumFunction);
14133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14134 xmlXPathTrueFunction);
14135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14136 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014137
14138 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14139 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14140 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014141}
14142
14143#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014144#define bottom_xpath
14145#include "elfgcchack.h"