blob: 4e373c09d26564eb1ac5a2bc7193bee45b4797c9 [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,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000552 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553} 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,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000568 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000569} xmlXPathTypeVal;
570
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000571#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000572
573typedef struct _xmlXPathStepOp xmlXPathStepOp;
574typedef xmlXPathStepOp *xmlXPathStepOpPtr;
575struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000576 xmlXPathOp op; /* The identifier of the operation */
577 int ch1; /* First child */
578 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000579 int value;
580 int value2;
581 int value3;
582 void *value4;
583 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000584 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000585 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000586 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000587};
588
589struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000590 int nbStep; /* Number of steps in this expression */
591 int maxStep; /* Maximum number of steps allocated */
592 xmlXPathStepOp *steps; /* ops for computation of this expression */
593 int last; /* index of last step in expression */
594 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000595 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000596#ifdef DEBUG_EVAL_COUNTS
597 int nb;
598 xmlChar *string;
599#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000600#ifdef XPATH_STREAMING
601 xmlPatternPtr stream;
602#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000603};
604
605/************************************************************************
606 * *
607 * Parser Type functions *
608 * *
609 ************************************************************************/
610
611/**
612 * xmlXPathNewCompExpr:
613 *
614 * Create a new Xpath component
615 *
616 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000618static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000619xmlXPathNewCompExpr(void) {
620 xmlXPathCompExprPtr cur;
621
622 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
623 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000624 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000625 return(NULL);
626 }
627 memset(cur, 0, sizeof(xmlXPathCompExpr));
628 cur->maxStep = 10;
629 cur->nbStep = 0;
630 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
631 sizeof(xmlXPathStepOp));
632 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000633 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000634 xmlFree(cur);
635 return(NULL);
636 }
637 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
638 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000639#ifdef DEBUG_EVAL_COUNTS
640 cur->nb = 0;
641#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000642 return(cur);
643}
644
645/**
646 * xmlXPathFreeCompExpr:
647 * @comp: an XPATH comp
648 *
649 * Free up the memory allocated by @comp
650 */
651void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000652xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
653{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000654 xmlXPathStepOpPtr op;
655 int i;
656
657 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000658 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000659 if (comp->dict == NULL) {
660 for (i = 0; i < comp->nbStep; i++) {
661 op = &comp->steps[i];
662 if (op->value4 != NULL) {
663 if (op->op == XPATH_OP_VALUE)
664 xmlXPathFreeObject(op->value4);
665 else
666 xmlFree(op->value4);
667 }
668 if (op->value5 != NULL)
669 xmlFree(op->value5);
670 }
671 } else {
672 for (i = 0; i < comp->nbStep; i++) {
673 op = &comp->steps[i];
674 if (op->value4 != NULL) {
675 if (op->op == XPATH_OP_VALUE)
676 xmlXPathFreeObject(op->value4);
677 }
678 }
679 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000680 }
681 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000682 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000683 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000684#ifdef DEBUG_EVAL_COUNTS
685 if (comp->string != NULL) {
686 xmlFree(comp->string);
687 }
688#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000689#ifdef XPATH_STREAMING
690 if (comp->stream != NULL) {
691 xmlFreePatternList(comp->stream);
692 }
693#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000694 if (comp->expr != NULL) {
695 xmlFree(comp->expr);
696 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000697
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000698 xmlFree(comp);
699}
700
701/**
702 * xmlXPathCompExprAdd:
703 * @comp: the compiled expression
704 * @ch1: first child index
705 * @ch2: second child index
706 * @op: an op
707 * @value: the first int value
708 * @value2: the second int value
709 * @value3: the third int value
710 * @value4: the first string value
711 * @value5: the second string value
712 *
William M. Brack08171912003-12-29 02:52:11 +0000713 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000714 *
715 * Returns -1 in case of failure, the index otherwise
716 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000717static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000718xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
719 xmlXPathOp op, int value,
720 int value2, int value3, void *value4, void *value5) {
721 if (comp->nbStep >= comp->maxStep) {
722 xmlXPathStepOp *real;
723
724 comp->maxStep *= 2;
725 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
726 comp->maxStep * sizeof(xmlXPathStepOp));
727 if (real == NULL) {
728 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000729 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000730 return(-1);
731 }
732 comp->steps = real;
733 }
734 comp->last = comp->nbStep;
735 comp->steps[comp->nbStep].ch1 = ch1;
736 comp->steps[comp->nbStep].ch2 = ch2;
737 comp->steps[comp->nbStep].op = op;
738 comp->steps[comp->nbStep].value = value;
739 comp->steps[comp->nbStep].value2 = value2;
740 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000741 if ((comp->dict != NULL) &&
742 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
743 (op == XPATH_OP_COLLECT))) {
744 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000745 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000746 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000747 xmlFree(value4);
748 } else
749 comp->steps[comp->nbStep].value4 = NULL;
750 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000751 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000752 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000753 xmlFree(value5);
754 } else
755 comp->steps[comp->nbStep].value5 = NULL;
756 } else {
757 comp->steps[comp->nbStep].value4 = value4;
758 comp->steps[comp->nbStep].value5 = value5;
759 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000760 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000761 return(comp->nbStep++);
762}
763
Daniel Veillardf06307e2001-07-03 10:35:50 +0000764/**
765 * xmlXPathCompSwap:
766 * @comp: the compiled expression
767 * @op: operation index
768 *
769 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000770 */
771static void
772xmlXPathCompSwap(xmlXPathStepOpPtr op) {
773 int tmp;
774
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000775#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000776 /*
777 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000778 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000779 * application
780 */
781 if (xmlXPathDisableOptimizer)
782 return;
783#endif
784
Daniel Veillardf06307e2001-07-03 10:35:50 +0000785 tmp = op->ch1;
786 op->ch1 = op->ch2;
787 op->ch2 = tmp;
788}
789
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000790#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
791 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
792 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000793#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
794 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
795 (op), (val), (val2), (val3), (val4), (val5))
796
797#define PUSH_LEAVE_EXPR(op, val, val2) \
798xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
799
800#define PUSH_UNARY_EXPR(op, ch, val, val2) \
801xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
802
803#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000804xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
805 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000806
807/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000808 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000809 * XPath object cache structures *
810 * *
811 ************************************************************************/
812
813/* #define XP_DEFAULT_CACHE_ON */
814
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000815#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000816
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000817typedef struct _xmlXPathContextCache xmlXPathContextCache;
818typedef xmlXPathContextCache *xmlXPathContextCachePtr;
819struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000820 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
821 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
822 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000825 int maxNodeset;
826 int maxString;
827 int maxBoolean;
828 int maxNumber;
829 int maxMisc;
830#ifdef XP_DEBUG_OBJ_USAGE
831 int dbgCachedAll;
832 int dbgCachedNodeset;
833 int dbgCachedString;
834 int dbgCachedBool;
835 int dbgCachedNumber;
836 int dbgCachedPoint;
837 int dbgCachedRange;
838 int dbgCachedLocset;
839 int dbgCachedUsers;
840 int dbgCachedXSLTTree;
841 int dbgCachedUndefined;
842
843
844 int dbgReusedAll;
845 int dbgReusedNodeset;
846 int dbgReusedString;
847 int dbgReusedBool;
848 int dbgReusedNumber;
849 int dbgReusedPoint;
850 int dbgReusedRange;
851 int dbgReusedLocset;
852 int dbgReusedUsers;
853 int dbgReusedXSLTTree;
854 int dbgReusedUndefined;
855
856#endif
857};
858
859/************************************************************************
860 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000861 * Debugging related functions *
862 * *
863 ************************************************************************/
864
Owen Taylor3473f882001-02-23 17:55:21 +0000865#define STRANGE \
866 xmlGenericError(xmlGenericErrorContext, \
867 "Internal error at %s:%d\n", \
868 __FILE__, __LINE__);
869
870#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000871static void
872xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000873 int i;
874 char shift[100];
875
876 for (i = 0;((i < depth) && (i < 25));i++)
877 shift[2 * i] = shift[2 * i + 1] = ' ';
878 shift[2 * i] = shift[2 * i + 1] = 0;
879 if (cur == NULL) {
880 fprintf(output, shift);
881 fprintf(output, "Node is NULL !\n");
882 return;
883
884 }
885
886 if ((cur->type == XML_DOCUMENT_NODE) ||
887 (cur->type == XML_HTML_DOCUMENT_NODE)) {
888 fprintf(output, shift);
889 fprintf(output, " /\n");
890 } else if (cur->type == XML_ATTRIBUTE_NODE)
891 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
892 else
893 xmlDebugDumpOneNode(output, cur, depth);
894}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000895static void
896xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000897 xmlNodePtr tmp;
898 int i;
899 char shift[100];
900
901 for (i = 0;((i < depth) && (i < 25));i++)
902 shift[2 * i] = shift[2 * i + 1] = ' ';
903 shift[2 * i] = shift[2 * i + 1] = 0;
904 if (cur == NULL) {
905 fprintf(output, shift);
906 fprintf(output, "Node is NULL !\n");
907 return;
908
909 }
910
911 while (cur != NULL) {
912 tmp = cur;
913 cur = cur->next;
914 xmlDebugDumpOneNode(output, tmp, depth);
915 }
916}
Owen Taylor3473f882001-02-23 17:55:21 +0000917
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000918static void
919xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000920 int i;
921 char shift[100];
922
923 for (i = 0;((i < depth) && (i < 25));i++)
924 shift[2 * i] = shift[2 * i + 1] = ' ';
925 shift[2 * i] = shift[2 * i + 1] = 0;
926
927 if (cur == NULL) {
928 fprintf(output, shift);
929 fprintf(output, "NodeSet is NULL !\n");
930 return;
931
932 }
933
Daniel Veillard911f49a2001-04-07 15:39:35 +0000934 if (cur != NULL) {
935 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
936 for (i = 0;i < cur->nodeNr;i++) {
937 fprintf(output, shift);
938 fprintf(output, "%d", i + 1);
939 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
940 }
Owen Taylor3473f882001-02-23 17:55:21 +0000941 }
942}
943
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000944static void
945xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000946 int i;
947 char shift[100];
948
949 for (i = 0;((i < depth) && (i < 25));i++)
950 shift[2 * i] = shift[2 * i + 1] = ' ';
951 shift[2 * i] = shift[2 * i + 1] = 0;
952
953 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
954 fprintf(output, shift);
955 fprintf(output, "Value Tree is NULL !\n");
956 return;
957
958 }
959
960 fprintf(output, shift);
961 fprintf(output, "%d", i + 1);
962 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
963}
Owen Taylor3473f882001-02-23 17:55:21 +0000964#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000965static void
966xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000967 int i;
968 char shift[100];
969
970 for (i = 0;((i < depth) && (i < 25));i++)
971 shift[2 * i] = shift[2 * i + 1] = ' ';
972 shift[2 * i] = shift[2 * i + 1] = 0;
973
974 if (cur == NULL) {
975 fprintf(output, shift);
976 fprintf(output, "LocationSet is NULL !\n");
977 return;
978
979 }
980
981 for (i = 0;i < cur->locNr;i++) {
982 fprintf(output, shift);
983 fprintf(output, "%d : ", i + 1);
984 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
985 }
986}
Daniel Veillard017b1082001-06-21 11:20:21 +0000987#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000988
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000989/**
990 * xmlXPathDebugDumpObject:
991 * @output: the FILE * to dump the output
992 * @cur: the object to inspect
993 * @depth: indentation level
994 *
995 * Dump the content of the object for debugging purposes
996 */
997void
998xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000999 int i;
1000 char shift[100];
1001
Daniel Veillarda82b1822004-11-08 16:24:57 +00001002 if (output == NULL) return;
1003
Owen Taylor3473f882001-02-23 17:55:21 +00001004 for (i = 0;((i < depth) && (i < 25));i++)
1005 shift[2 * i] = shift[2 * i + 1] = ' ';
1006 shift[2 * i] = shift[2 * i + 1] = 0;
1007
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001008
1009 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001010
1011 if (cur == NULL) {
1012 fprintf(output, "Object is empty (NULL)\n");
1013 return;
1014 }
1015 switch(cur->type) {
1016 case XPATH_UNDEFINED:
1017 fprintf(output, "Object is uninitialized\n");
1018 break;
1019 case XPATH_NODESET:
1020 fprintf(output, "Object is a Node Set :\n");
1021 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1022 break;
1023 case XPATH_XSLT_TREE:
1024 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001025 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001026 break;
1027 case XPATH_BOOLEAN:
1028 fprintf(output, "Object is a Boolean : ");
1029 if (cur->boolval) fprintf(output, "true\n");
1030 else fprintf(output, "false\n");
1031 break;
1032 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001033 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001034 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001035 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001036 break;
1037 case -1:
1038 fprintf(output, "Object is a number : -Infinity\n");
1039 break;
1040 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001041 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001042 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001043 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1044 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001045 } else {
1046 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1047 }
1048 }
Owen Taylor3473f882001-02-23 17:55:21 +00001049 break;
1050 case XPATH_STRING:
1051 fprintf(output, "Object is a string : ");
1052 xmlDebugDumpString(output, cur->stringval);
1053 fprintf(output, "\n");
1054 break;
1055 case XPATH_POINT:
1056 fprintf(output, "Object is a point : index %d in node", cur->index);
1057 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1058 fprintf(output, "\n");
1059 break;
1060 case XPATH_RANGE:
1061 if ((cur->user2 == NULL) ||
1062 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1063 fprintf(output, "Object is a collapsed range :\n");
1064 fprintf(output, shift);
1065 if (cur->index >= 0)
1066 fprintf(output, "index %d in ", cur->index);
1067 fprintf(output, "node\n");
1068 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1069 depth + 1);
1070 } else {
1071 fprintf(output, "Object is a range :\n");
1072 fprintf(output, shift);
1073 fprintf(output, "From ");
1074 if (cur->index >= 0)
1075 fprintf(output, "index %d in ", cur->index);
1076 fprintf(output, "node\n");
1077 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1078 depth + 1);
1079 fprintf(output, shift);
1080 fprintf(output, "To ");
1081 if (cur->index2 >= 0)
1082 fprintf(output, "index %d in ", cur->index2);
1083 fprintf(output, "node\n");
1084 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1085 depth + 1);
1086 fprintf(output, "\n");
1087 }
1088 break;
1089 case XPATH_LOCATIONSET:
1090#if defined(LIBXML_XPTR_ENABLED)
1091 fprintf(output, "Object is a Location Set:\n");
1092 xmlXPathDebugDumpLocationSet(output,
1093 (xmlLocationSetPtr) cur->user, depth);
1094#endif
1095 break;
1096 case XPATH_USERS:
1097 fprintf(output, "Object is user defined\n");
1098 break;
1099 }
1100}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001101
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001102static void
1103xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001104 xmlXPathStepOpPtr op, int depth) {
1105 int i;
1106 char shift[100];
1107
1108 for (i = 0;((i < depth) && (i < 25));i++)
1109 shift[2 * i] = shift[2 * i + 1] = ' ';
1110 shift[2 * i] = shift[2 * i + 1] = 0;
1111
1112 fprintf(output, shift);
1113 if (op == NULL) {
1114 fprintf(output, "Step is NULL\n");
1115 return;
1116 }
1117 switch (op->op) {
1118 case XPATH_OP_END:
1119 fprintf(output, "END"); break;
1120 case XPATH_OP_AND:
1121 fprintf(output, "AND"); break;
1122 case XPATH_OP_OR:
1123 fprintf(output, "OR"); break;
1124 case XPATH_OP_EQUAL:
1125 if (op->value)
1126 fprintf(output, "EQUAL =");
1127 else
1128 fprintf(output, "EQUAL !=");
1129 break;
1130 case XPATH_OP_CMP:
1131 if (op->value)
1132 fprintf(output, "CMP <");
1133 else
1134 fprintf(output, "CMP >");
1135 if (!op->value2)
1136 fprintf(output, "=");
1137 break;
1138 case XPATH_OP_PLUS:
1139 if (op->value == 0)
1140 fprintf(output, "PLUS -");
1141 else if (op->value == 1)
1142 fprintf(output, "PLUS +");
1143 else if (op->value == 2)
1144 fprintf(output, "PLUS unary -");
1145 else if (op->value == 3)
1146 fprintf(output, "PLUS unary - -");
1147 break;
1148 case XPATH_OP_MULT:
1149 if (op->value == 0)
1150 fprintf(output, "MULT *");
1151 else if (op->value == 1)
1152 fprintf(output, "MULT div");
1153 else
1154 fprintf(output, "MULT mod");
1155 break;
1156 case XPATH_OP_UNION:
1157 fprintf(output, "UNION"); break;
1158 case XPATH_OP_ROOT:
1159 fprintf(output, "ROOT"); break;
1160 case XPATH_OP_NODE:
1161 fprintf(output, "NODE"); break;
1162 case XPATH_OP_RESET:
1163 fprintf(output, "RESET"); break;
1164 case XPATH_OP_SORT:
1165 fprintf(output, "SORT"); break;
1166 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001167 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1168 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1169 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001170 const xmlChar *prefix = op->value4;
1171 const xmlChar *name = op->value5;
1172
1173 fprintf(output, "COLLECT ");
1174 switch (axis) {
1175 case AXIS_ANCESTOR:
1176 fprintf(output, " 'ancestors' "); break;
1177 case AXIS_ANCESTOR_OR_SELF:
1178 fprintf(output, " 'ancestors-or-self' "); break;
1179 case AXIS_ATTRIBUTE:
1180 fprintf(output, " 'attributes' "); break;
1181 case AXIS_CHILD:
1182 fprintf(output, " 'child' "); break;
1183 case AXIS_DESCENDANT:
1184 fprintf(output, " 'descendant' "); break;
1185 case AXIS_DESCENDANT_OR_SELF:
1186 fprintf(output, " 'descendant-or-self' "); break;
1187 case AXIS_FOLLOWING:
1188 fprintf(output, " 'following' "); break;
1189 case AXIS_FOLLOWING_SIBLING:
1190 fprintf(output, " 'following-siblings' "); break;
1191 case AXIS_NAMESPACE:
1192 fprintf(output, " 'namespace' "); break;
1193 case AXIS_PARENT:
1194 fprintf(output, " 'parent' "); break;
1195 case AXIS_PRECEDING:
1196 fprintf(output, " 'preceding' "); break;
1197 case AXIS_PRECEDING_SIBLING:
1198 fprintf(output, " 'preceding-sibling' "); break;
1199 case AXIS_SELF:
1200 fprintf(output, " 'self' "); break;
1201 }
1202 switch (test) {
1203 case NODE_TEST_NONE:
1204 fprintf(output, "'none' "); break;
1205 case NODE_TEST_TYPE:
1206 fprintf(output, "'type' "); break;
1207 case NODE_TEST_PI:
1208 fprintf(output, "'PI' "); break;
1209 case NODE_TEST_ALL:
1210 fprintf(output, "'all' "); break;
1211 case NODE_TEST_NS:
1212 fprintf(output, "'namespace' "); break;
1213 case NODE_TEST_NAME:
1214 fprintf(output, "'name' "); break;
1215 }
1216 switch (type) {
1217 case NODE_TYPE_NODE:
1218 fprintf(output, "'node' "); break;
1219 case NODE_TYPE_COMMENT:
1220 fprintf(output, "'comment' "); break;
1221 case NODE_TYPE_TEXT:
1222 fprintf(output, "'text' "); break;
1223 case NODE_TYPE_PI:
1224 fprintf(output, "'PI' "); break;
1225 }
1226 if (prefix != NULL)
1227 fprintf(output, "%s:", prefix);
1228 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001229 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001230 break;
1231
1232 }
1233 case XPATH_OP_VALUE: {
1234 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1235
1236 fprintf(output, "ELEM ");
1237 xmlXPathDebugDumpObject(output, object, 0);
1238 goto finish;
1239 }
1240 case XPATH_OP_VARIABLE: {
1241 const xmlChar *prefix = op->value5;
1242 const xmlChar *name = op->value4;
1243
1244 if (prefix != NULL)
1245 fprintf(output, "VARIABLE %s:%s", prefix, name);
1246 else
1247 fprintf(output, "VARIABLE %s", name);
1248 break;
1249 }
1250 case XPATH_OP_FUNCTION: {
1251 int nbargs = op->value;
1252 const xmlChar *prefix = op->value5;
1253 const xmlChar *name = op->value4;
1254
1255 if (prefix != NULL)
1256 fprintf(output, "FUNCTION %s:%s(%d args)",
1257 prefix, name, nbargs);
1258 else
1259 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1260 break;
1261 }
1262 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1263 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001264 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001265#ifdef LIBXML_XPTR_ENABLED
1266 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1267#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001268 default:
1269 fprintf(output, "UNKNOWN %d\n", op->op); return;
1270 }
1271 fprintf(output, "\n");
1272finish:
1273 if (op->ch1 >= 0)
1274 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1275 if (op->ch2 >= 0)
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1277}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001278
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001279/**
1280 * xmlXPathDebugDumpCompExpr:
1281 * @output: the FILE * for the output
1282 * @comp: the precompiled XPath expression
1283 * @depth: the indentation level.
1284 *
1285 * Dumps the tree of the compiled XPath expression.
1286 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001287void
1288xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1289 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001290 int i;
1291 char shift[100];
1292
Daniel Veillarda82b1822004-11-08 16:24:57 +00001293 if ((output == NULL) || (comp == NULL)) return;
1294
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001295 for (i = 0;((i < depth) && (i < 25));i++)
1296 shift[2 * i] = shift[2 * i + 1] = ' ';
1297 shift[2 * i] = shift[2 * i + 1] = 0;
1298
1299 fprintf(output, shift);
1300
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001301 fprintf(output, "Compiled Expression : %d elements\n",
1302 comp->nbStep);
1303 i = comp->last;
1304 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1305}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001306
1307#ifdef XP_DEBUG_OBJ_USAGE
1308
1309/*
1310* XPath object usage related debugging variables.
1311*/
1312static int xmlXPathDebugObjCounterUndefined = 0;
1313static int xmlXPathDebugObjCounterNodeset = 0;
1314static int xmlXPathDebugObjCounterBool = 0;
1315static int xmlXPathDebugObjCounterNumber = 0;
1316static int xmlXPathDebugObjCounterString = 0;
1317static int xmlXPathDebugObjCounterPoint = 0;
1318static int xmlXPathDebugObjCounterRange = 0;
1319static int xmlXPathDebugObjCounterLocset = 0;
1320static int xmlXPathDebugObjCounterUsers = 0;
1321static int xmlXPathDebugObjCounterXSLTTree = 0;
1322static int xmlXPathDebugObjCounterAll = 0;
1323
1324static int xmlXPathDebugObjTotalUndefined = 0;
1325static int xmlXPathDebugObjTotalNodeset = 0;
1326static int xmlXPathDebugObjTotalBool = 0;
1327static int xmlXPathDebugObjTotalNumber = 0;
1328static int xmlXPathDebugObjTotalString = 0;
1329static int xmlXPathDebugObjTotalPoint = 0;
1330static int xmlXPathDebugObjTotalRange = 0;
1331static int xmlXPathDebugObjTotalLocset = 0;
1332static int xmlXPathDebugObjTotalUsers = 0;
1333static int xmlXPathDebugObjTotalXSLTTree = 0;
1334static int xmlXPathDebugObjTotalAll = 0;
1335
1336static int xmlXPathDebugObjMaxUndefined = 0;
1337static int xmlXPathDebugObjMaxNodeset = 0;
1338static int xmlXPathDebugObjMaxBool = 0;
1339static int xmlXPathDebugObjMaxNumber = 0;
1340static int xmlXPathDebugObjMaxString = 0;
1341static int xmlXPathDebugObjMaxPoint = 0;
1342static int xmlXPathDebugObjMaxRange = 0;
1343static int xmlXPathDebugObjMaxLocset = 0;
1344static int xmlXPathDebugObjMaxUsers = 0;
1345static int xmlXPathDebugObjMaxXSLTTree = 0;
1346static int xmlXPathDebugObjMaxAll = 0;
1347
1348/* REVISIT TODO: Make this static when committing */
1349static void
1350xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1351{
1352 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001353 if (ctxt->cache != NULL) {
1354 xmlXPathContextCachePtr cache =
1355 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001356
1357 cache->dbgCachedAll = 0;
1358 cache->dbgCachedNodeset = 0;
1359 cache->dbgCachedString = 0;
1360 cache->dbgCachedBool = 0;
1361 cache->dbgCachedNumber = 0;
1362 cache->dbgCachedPoint = 0;
1363 cache->dbgCachedRange = 0;
1364 cache->dbgCachedLocset = 0;
1365 cache->dbgCachedUsers = 0;
1366 cache->dbgCachedXSLTTree = 0;
1367 cache->dbgCachedUndefined = 0;
1368
1369 cache->dbgReusedAll = 0;
1370 cache->dbgReusedNodeset = 0;
1371 cache->dbgReusedString = 0;
1372 cache->dbgReusedBool = 0;
1373 cache->dbgReusedNumber = 0;
1374 cache->dbgReusedPoint = 0;
1375 cache->dbgReusedRange = 0;
1376 cache->dbgReusedLocset = 0;
1377 cache->dbgReusedUsers = 0;
1378 cache->dbgReusedXSLTTree = 0;
1379 cache->dbgReusedUndefined = 0;
1380 }
1381 }
1382
1383 xmlXPathDebugObjCounterUndefined = 0;
1384 xmlXPathDebugObjCounterNodeset = 0;
1385 xmlXPathDebugObjCounterBool = 0;
1386 xmlXPathDebugObjCounterNumber = 0;
1387 xmlXPathDebugObjCounterString = 0;
1388 xmlXPathDebugObjCounterPoint = 0;
1389 xmlXPathDebugObjCounterRange = 0;
1390 xmlXPathDebugObjCounterLocset = 0;
1391 xmlXPathDebugObjCounterUsers = 0;
1392 xmlXPathDebugObjCounterXSLTTree = 0;
1393 xmlXPathDebugObjCounterAll = 0;
1394
1395 xmlXPathDebugObjTotalUndefined = 0;
1396 xmlXPathDebugObjTotalNodeset = 0;
1397 xmlXPathDebugObjTotalBool = 0;
1398 xmlXPathDebugObjTotalNumber = 0;
1399 xmlXPathDebugObjTotalString = 0;
1400 xmlXPathDebugObjTotalPoint = 0;
1401 xmlXPathDebugObjTotalRange = 0;
1402 xmlXPathDebugObjTotalLocset = 0;
1403 xmlXPathDebugObjTotalUsers = 0;
1404 xmlXPathDebugObjTotalXSLTTree = 0;
1405 xmlXPathDebugObjTotalAll = 0;
1406
1407 xmlXPathDebugObjMaxUndefined = 0;
1408 xmlXPathDebugObjMaxNodeset = 0;
1409 xmlXPathDebugObjMaxBool = 0;
1410 xmlXPathDebugObjMaxNumber = 0;
1411 xmlXPathDebugObjMaxString = 0;
1412 xmlXPathDebugObjMaxPoint = 0;
1413 xmlXPathDebugObjMaxRange = 0;
1414 xmlXPathDebugObjMaxLocset = 0;
1415 xmlXPathDebugObjMaxUsers = 0;
1416 xmlXPathDebugObjMaxXSLTTree = 0;
1417 xmlXPathDebugObjMaxAll = 0;
1418
1419}
1420
1421static void
1422xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1423 xmlXPathObjectType objType)
1424{
1425 int isCached = 0;
1426
1427 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001428 if (ctxt->cache != NULL) {
1429 xmlXPathContextCachePtr cache =
1430 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001431
1432 isCached = 1;
1433
1434 cache->dbgReusedAll++;
1435 switch (objType) {
1436 case XPATH_UNDEFINED:
1437 cache->dbgReusedUndefined++;
1438 break;
1439 case XPATH_NODESET:
1440 cache->dbgReusedNodeset++;
1441 break;
1442 case XPATH_BOOLEAN:
1443 cache->dbgReusedBool++;
1444 break;
1445 case XPATH_NUMBER:
1446 cache->dbgReusedNumber++;
1447 break;
1448 case XPATH_STRING:
1449 cache->dbgReusedString++;
1450 break;
1451 case XPATH_POINT:
1452 cache->dbgReusedPoint++;
1453 break;
1454 case XPATH_RANGE:
1455 cache->dbgReusedRange++;
1456 break;
1457 case XPATH_LOCATIONSET:
1458 cache->dbgReusedLocset++;
1459 break;
1460 case XPATH_USERS:
1461 cache->dbgReusedUsers++;
1462 break;
1463 case XPATH_XSLT_TREE:
1464 cache->dbgReusedXSLTTree++;
1465 break;
1466 default:
1467 break;
1468 }
1469 }
1470 }
1471
1472 switch (objType) {
1473 case XPATH_UNDEFINED:
1474 if (! isCached)
1475 xmlXPathDebugObjTotalUndefined++;
1476 xmlXPathDebugObjCounterUndefined++;
1477 if (xmlXPathDebugObjCounterUndefined >
1478 xmlXPathDebugObjMaxUndefined)
1479 xmlXPathDebugObjMaxUndefined =
1480 xmlXPathDebugObjCounterUndefined;
1481 break;
1482 case XPATH_NODESET:
1483 if (! isCached)
1484 xmlXPathDebugObjTotalNodeset++;
1485 xmlXPathDebugObjCounterNodeset++;
1486 if (xmlXPathDebugObjCounterNodeset >
1487 xmlXPathDebugObjMaxNodeset)
1488 xmlXPathDebugObjMaxNodeset =
1489 xmlXPathDebugObjCounterNodeset;
1490 break;
1491 case XPATH_BOOLEAN:
1492 if (! isCached)
1493 xmlXPathDebugObjTotalBool++;
1494 xmlXPathDebugObjCounterBool++;
1495 if (xmlXPathDebugObjCounterBool >
1496 xmlXPathDebugObjMaxBool)
1497 xmlXPathDebugObjMaxBool =
1498 xmlXPathDebugObjCounterBool;
1499 break;
1500 case XPATH_NUMBER:
1501 if (! isCached)
1502 xmlXPathDebugObjTotalNumber++;
1503 xmlXPathDebugObjCounterNumber++;
1504 if (xmlXPathDebugObjCounterNumber >
1505 xmlXPathDebugObjMaxNumber)
1506 xmlXPathDebugObjMaxNumber =
1507 xmlXPathDebugObjCounterNumber;
1508 break;
1509 case XPATH_STRING:
1510 if (! isCached)
1511 xmlXPathDebugObjTotalString++;
1512 xmlXPathDebugObjCounterString++;
1513 if (xmlXPathDebugObjCounterString >
1514 xmlXPathDebugObjMaxString)
1515 xmlXPathDebugObjMaxString =
1516 xmlXPathDebugObjCounterString;
1517 break;
1518 case XPATH_POINT:
1519 if (! isCached)
1520 xmlXPathDebugObjTotalPoint++;
1521 xmlXPathDebugObjCounterPoint++;
1522 if (xmlXPathDebugObjCounterPoint >
1523 xmlXPathDebugObjMaxPoint)
1524 xmlXPathDebugObjMaxPoint =
1525 xmlXPathDebugObjCounterPoint;
1526 break;
1527 case XPATH_RANGE:
1528 if (! isCached)
1529 xmlXPathDebugObjTotalRange++;
1530 xmlXPathDebugObjCounterRange++;
1531 if (xmlXPathDebugObjCounterRange >
1532 xmlXPathDebugObjMaxRange)
1533 xmlXPathDebugObjMaxRange =
1534 xmlXPathDebugObjCounterRange;
1535 break;
1536 case XPATH_LOCATIONSET:
1537 if (! isCached)
1538 xmlXPathDebugObjTotalLocset++;
1539 xmlXPathDebugObjCounterLocset++;
1540 if (xmlXPathDebugObjCounterLocset >
1541 xmlXPathDebugObjMaxLocset)
1542 xmlXPathDebugObjMaxLocset =
1543 xmlXPathDebugObjCounterLocset;
1544 break;
1545 case XPATH_USERS:
1546 if (! isCached)
1547 xmlXPathDebugObjTotalUsers++;
1548 xmlXPathDebugObjCounterUsers++;
1549 if (xmlXPathDebugObjCounterUsers >
1550 xmlXPathDebugObjMaxUsers)
1551 xmlXPathDebugObjMaxUsers =
1552 xmlXPathDebugObjCounterUsers;
1553 break;
1554 case XPATH_XSLT_TREE:
1555 if (! isCached)
1556 xmlXPathDebugObjTotalXSLTTree++;
1557 xmlXPathDebugObjCounterXSLTTree++;
1558 if (xmlXPathDebugObjCounterXSLTTree >
1559 xmlXPathDebugObjMaxXSLTTree)
1560 xmlXPathDebugObjMaxXSLTTree =
1561 xmlXPathDebugObjCounterXSLTTree;
1562 break;
1563 default:
1564 break;
1565 }
1566 if (! isCached)
1567 xmlXPathDebugObjTotalAll++;
1568 xmlXPathDebugObjCounterAll++;
1569 if (xmlXPathDebugObjCounterAll >
1570 xmlXPathDebugObjMaxAll)
1571 xmlXPathDebugObjMaxAll =
1572 xmlXPathDebugObjCounterAll;
1573}
1574
1575static void
1576xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1577 xmlXPathObjectType objType)
1578{
1579 int isCached = 0;
1580
1581 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001582 if (ctxt->cache != NULL) {
1583 xmlXPathContextCachePtr cache =
1584 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001585
1586 isCached = 1;
1587
1588 cache->dbgCachedAll++;
1589 switch (objType) {
1590 case XPATH_UNDEFINED:
1591 cache->dbgCachedUndefined++;
1592 break;
1593 case XPATH_NODESET:
1594 cache->dbgCachedNodeset++;
1595 break;
1596 case XPATH_BOOLEAN:
1597 cache->dbgCachedBool++;
1598 break;
1599 case XPATH_NUMBER:
1600 cache->dbgCachedNumber++;
1601 break;
1602 case XPATH_STRING:
1603 cache->dbgCachedString++;
1604 break;
1605 case XPATH_POINT:
1606 cache->dbgCachedPoint++;
1607 break;
1608 case XPATH_RANGE:
1609 cache->dbgCachedRange++;
1610 break;
1611 case XPATH_LOCATIONSET:
1612 cache->dbgCachedLocset++;
1613 break;
1614 case XPATH_USERS:
1615 cache->dbgCachedUsers++;
1616 break;
1617 case XPATH_XSLT_TREE:
1618 cache->dbgCachedXSLTTree++;
1619 break;
1620 default:
1621 break;
1622 }
1623
1624 }
1625 }
1626 switch (objType) {
1627 case XPATH_UNDEFINED:
1628 xmlXPathDebugObjCounterUndefined--;
1629 break;
1630 case XPATH_NODESET:
1631 xmlXPathDebugObjCounterNodeset--;
1632 break;
1633 case XPATH_BOOLEAN:
1634 xmlXPathDebugObjCounterBool--;
1635 break;
1636 case XPATH_NUMBER:
1637 xmlXPathDebugObjCounterNumber--;
1638 break;
1639 case XPATH_STRING:
1640 xmlXPathDebugObjCounterString--;
1641 break;
1642 case XPATH_POINT:
1643 xmlXPathDebugObjCounterPoint--;
1644 break;
1645 case XPATH_RANGE:
1646 xmlXPathDebugObjCounterRange--;
1647 break;
1648 case XPATH_LOCATIONSET:
1649 xmlXPathDebugObjCounterLocset--;
1650 break;
1651 case XPATH_USERS:
1652 xmlXPathDebugObjCounterUsers--;
1653 break;
1654 case XPATH_XSLT_TREE:
1655 xmlXPathDebugObjCounterXSLTTree--;
1656 break;
1657 default:
1658 break;
1659 }
1660 xmlXPathDebugObjCounterAll--;
1661}
1662
1663/* REVISIT TODO: Make this static when committing */
1664static void
1665xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1666{
1667 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1668 reqXSLTTree, reqUndefined;
1669 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1670 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1671 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1672 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1673 int leftObjs = xmlXPathDebugObjCounterAll;
1674
1675 reqAll = xmlXPathDebugObjTotalAll;
1676 reqNodeset = xmlXPathDebugObjTotalNodeset;
1677 reqString = xmlXPathDebugObjTotalString;
1678 reqBool = xmlXPathDebugObjTotalBool;
1679 reqNumber = xmlXPathDebugObjTotalNumber;
1680 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1681 reqUndefined = xmlXPathDebugObjTotalUndefined;
1682
1683 printf("# XPath object usage:\n");
1684
1685 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001686 if (ctxt->cache != NULL) {
1687 xmlXPathContextCachePtr cache =
1688 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001689
1690 reAll = cache->dbgReusedAll;
1691 reqAll += reAll;
1692 reNodeset = cache->dbgReusedNodeset;
1693 reqNodeset += reNodeset;
1694 reString = cache->dbgReusedString;
1695 reqString += reString;
1696 reBool = cache->dbgReusedBool;
1697 reqBool += reBool;
1698 reNumber = cache->dbgReusedNumber;
1699 reqNumber += reNumber;
1700 reXSLTTree = cache->dbgReusedXSLTTree;
1701 reqXSLTTree += reXSLTTree;
1702 reUndefined = cache->dbgReusedUndefined;
1703 reqUndefined += reUndefined;
1704
1705 caAll = cache->dbgCachedAll;
1706 caBool = cache->dbgCachedBool;
1707 caNodeset = cache->dbgCachedNodeset;
1708 caString = cache->dbgCachedString;
1709 caNumber = cache->dbgCachedNumber;
1710 caXSLTTree = cache->dbgCachedXSLTTree;
1711 caUndefined = cache->dbgCachedUndefined;
1712
1713 if (cache->nodesetObjs)
1714 leftObjs -= cache->nodesetObjs->number;
1715 if (cache->stringObjs)
1716 leftObjs -= cache->stringObjs->number;
1717 if (cache->booleanObjs)
1718 leftObjs -= cache->booleanObjs->number;
1719 if (cache->numberObjs)
1720 leftObjs -= cache->numberObjs->number;
1721 if (cache->miscObjs)
1722 leftObjs -= cache->miscObjs->number;
1723 }
1724 }
1725
1726 printf("# all\n");
1727 printf("# total : %d\n", reqAll);
1728 printf("# left : %d\n", leftObjs);
1729 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1730 printf("# reused : %d\n", reAll);
1731 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1732
1733 printf("# node-sets\n");
1734 printf("# total : %d\n", reqNodeset);
1735 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1736 printf("# reused : %d\n", reNodeset);
1737 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1738
1739 printf("# strings\n");
1740 printf("# total : %d\n", reqString);
1741 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1742 printf("# reused : %d\n", reString);
1743 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1744
1745 printf("# booleans\n");
1746 printf("# total : %d\n", reqBool);
1747 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1748 printf("# reused : %d\n", reBool);
1749 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1750
1751 printf("# numbers\n");
1752 printf("# total : %d\n", reqNumber);
1753 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1754 printf("# reused : %d\n", reNumber);
1755 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1756
1757 printf("# XSLT result tree fragments\n");
1758 printf("# total : %d\n", reqXSLTTree);
1759 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1760 printf("# reused : %d\n", reXSLTTree);
1761 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1762
1763 printf("# undefined\n");
1764 printf("# total : %d\n", reqUndefined);
1765 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1766 printf("# reused : %d\n", reUndefined);
1767 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1768
1769}
1770
1771#endif /* XP_DEBUG_OBJ_USAGE */
1772
Daniel Veillard017b1082001-06-21 11:20:21 +00001773#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001774
1775/************************************************************************
1776 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001777 * XPath object caching *
1778 * *
1779 ************************************************************************/
1780
1781/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001782 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001783 *
1784 * Create a new object cache
1785 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001786 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001787 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001788static xmlXPathContextCachePtr
1789xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001790{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001791 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001792
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001793 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794 if (ret == NULL) {
1795 xmlXPathErrMemory(NULL, "creating object cache\n");
1796 return(NULL);
1797 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001798 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001799 ret->maxNodeset = 100;
1800 ret->maxString = 100;
1801 ret->maxBoolean = 100;
1802 ret->maxNumber = 100;
1803 ret->maxMisc = 100;
1804 return(ret);
1805}
1806
1807static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001808xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001809{
1810 int i;
1811 xmlXPathObjectPtr obj;
1812
1813 if (list == NULL)
1814 return;
1815
1816 for (i = 0; i < list->number; i++) {
1817 obj = list->items[i];
1818 /*
1819 * Note that it is already assured that we don't need to
1820 * look out for namespace nodes in the node-set.
1821 */
1822 if (obj->nodesetval != NULL) {
1823 if (obj->nodesetval->nodeTab != NULL)
1824 xmlFree(obj->nodesetval->nodeTab);
1825 xmlFree(obj->nodesetval);
1826 }
1827 xmlFree(obj);
1828#ifdef XP_DEBUG_OBJ_USAGE
1829 xmlXPathDebugObjCounterAll--;
1830#endif
1831 }
1832 xmlPointerListFree(list);
1833}
1834
1835static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001836xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001837{
1838 if (cache == NULL)
1839 return;
1840 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001841 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001842 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001843 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001844 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 xmlFree(cache);
1851}
1852
1853/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001854 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001855 *
1856 * @ctxt: the XPath context
1857 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001858 * @value: a value with semantics dependant on @options
1859 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001860 *
1861 * Creates/frees an object cache on the XPath context.
1862 * If activates XPath objects (xmlXPathObject) will be cached internally
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001863 * to be reused.
1864 * @options:
1865 * 0: This will set the XPath object caching:
1866 * @value:
1867 * This will set the maximum number of XPath objects
1868 * to be cached per slot
1869 * There are 5 slots for: node-set, string, number, boolean, and
1870 * misc objects. Use <0 for the default number (100).
1871 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001872 *
1873 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1874 */
1875int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001876xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1877 int active,
1878 int value,
1879 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001880{
1881 if (ctxt == NULL)
1882 return(-1);
1883 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001884 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001885
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001886 if (ctxt->cache == NULL) {
1887 ctxt->cache = xmlXPathNewCache();
1888 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001889 return(-1);
1890 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001891 cache = (xmlXPathContextCachePtr) ctxt->cache;
1892 if (options == 0) {
1893 if (value < 0)
1894 value = 100;
1895 cache->maxNodeset = value;
1896 cache->maxString = value;
1897 cache->maxNumber = value;
1898 cache->maxBoolean = value;
1899 cache->maxMisc = value;
1900 }
1901 } else if (ctxt->cache != NULL) {
1902 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1903 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001904 }
1905 return(0);
1906}
1907
1908/**
1909 * xmlXPathCacheWrapNodeSet:
1910 * @ctxt: the XPath context
1911 * @val: the NodePtr value
1912 *
1913 * This is the cached version of xmlXPathWrapNodeSet().
1914 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1915 *
1916 * Returns the created or reused object.
1917 */
1918static xmlXPathObjectPtr
1919xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1920{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001921 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1922 xmlXPathContextCachePtr cache =
1923 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001924
1925 if ((cache->miscObjs != NULL) &&
1926 (cache->miscObjs->number != 0))
1927 {
1928 xmlXPathObjectPtr ret;
1929
1930 ret = (xmlXPathObjectPtr)
1931 cache->miscObjs->items[--cache->miscObjs->number];
1932 ret->type = XPATH_NODESET;
1933 ret->nodesetval = val;
1934#ifdef XP_DEBUG_OBJ_USAGE
1935 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1936#endif
1937 return(ret);
1938 }
1939 }
1940
1941 return(xmlXPathWrapNodeSet(val));
1942
1943}
1944
1945/**
1946 * xmlXPathCacheWrapString:
1947 * @ctxt: the XPath context
1948 * @val: the xmlChar * value
1949 *
1950 * This is the cached version of xmlXPathWrapString().
1951 * Wraps the @val string into an XPath object.
1952 *
1953 * Returns the created or reused object.
1954 */
1955static xmlXPathObjectPtr
1956xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1957{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001958 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1959 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001960
1961 if ((cache->stringObjs != NULL) &&
1962 (cache->stringObjs->number != 0))
1963 {
1964
1965 xmlXPathObjectPtr ret;
1966
1967 ret = (xmlXPathObjectPtr)
1968 cache->stringObjs->items[--cache->stringObjs->number];
1969 ret->type = XPATH_STRING;
1970 ret->stringval = val;
1971#ifdef XP_DEBUG_OBJ_USAGE
1972 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1973#endif
1974 return(ret);
1975 } else if ((cache->miscObjs != NULL) &&
1976 (cache->miscObjs->number != 0))
1977 {
1978 xmlXPathObjectPtr ret;
1979 /*
1980 * Fallback to misc-cache.
1981 */
1982 ret = (xmlXPathObjectPtr)
1983 cache->miscObjs->items[--cache->miscObjs->number];
1984
1985 ret->type = XPATH_STRING;
1986 ret->stringval = val;
1987#ifdef XP_DEBUG_OBJ_USAGE
1988 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1989#endif
1990 return(ret);
1991 }
1992 }
1993 return(xmlXPathWrapString(val));
1994}
1995
1996/**
1997 * xmlXPathCacheNewNodeSet:
1998 * @ctxt: the XPath context
1999 * @val: the NodePtr value
2000 *
2001 * This is the cached version of xmlXPathNewNodeSet().
2002 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2003 * it with the single Node @val
2004 *
2005 * Returns the created or reused object.
2006 */
2007static xmlXPathObjectPtr
2008xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2009{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002010 if ((ctxt != NULL) && (ctxt->cache)) {
2011 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002012
2013 if ((cache->nodesetObjs != NULL) &&
2014 (cache->nodesetObjs->number != 0))
2015 {
2016 xmlXPathObjectPtr ret;
2017 /*
2018 * Use the nodset-cache.
2019 */
2020 ret = (xmlXPathObjectPtr)
2021 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2022 ret->type = XPATH_NODESET;
2023 ret->boolval = 0;
2024 if (val) {
2025 if ((ret->nodesetval->nodeMax == 0) ||
2026 (val->type == XML_NAMESPACE_DECL))
2027 {
2028 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2029 } else {
2030 ret->nodesetval->nodeTab[0] = val;
2031 ret->nodesetval->nodeNr = 1;
2032 }
2033 }
2034#ifdef XP_DEBUG_OBJ_USAGE
2035 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2036#endif
2037 return(ret);
2038 } else if ((cache->miscObjs != NULL) &&
2039 (cache->miscObjs->number != 0))
2040 {
2041 xmlXPathObjectPtr ret;
2042 /*
2043 * Fallback to misc-cache.
2044 */
2045
2046 ret = (xmlXPathObjectPtr)
2047 cache->miscObjs->items[--cache->miscObjs->number];
2048
2049 ret->type = XPATH_NODESET;
2050 ret->boolval = 0;
2051 ret->nodesetval = xmlXPathNodeSetCreate(val);
2052#ifdef XP_DEBUG_OBJ_USAGE
2053 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2054#endif
2055 return(ret);
2056 }
2057 }
2058 return(xmlXPathNewNodeSet(val));
2059}
2060
2061/**
2062 * xmlXPathCacheNewCString:
2063 * @ctxt: the XPath context
2064 * @val: the char * value
2065 *
2066 * This is the cached version of xmlXPathNewCString().
2067 * Acquire an xmlXPathObjectPtr of type string and of value @val
2068 *
2069 * Returns the created or reused object.
2070 */
2071static xmlXPathObjectPtr
2072xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2073{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002074 if ((ctxt != NULL) && (ctxt->cache)) {
2075 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002076
2077 if ((cache->stringObjs != NULL) &&
2078 (cache->stringObjs->number != 0))
2079 {
2080 xmlXPathObjectPtr ret;
2081
2082 ret = (xmlXPathObjectPtr)
2083 cache->stringObjs->items[--cache->stringObjs->number];
2084
2085 ret->type = XPATH_STRING;
2086 ret->stringval = xmlStrdup(BAD_CAST val);
2087#ifdef XP_DEBUG_OBJ_USAGE
2088 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2089#endif
2090 return(ret);
2091 } else if ((cache->miscObjs != NULL) &&
2092 (cache->miscObjs->number != 0))
2093 {
2094 xmlXPathObjectPtr ret;
2095
2096 ret = (xmlXPathObjectPtr)
2097 cache->miscObjs->items[--cache->miscObjs->number];
2098
2099 ret->type = XPATH_STRING;
2100 ret->stringval = xmlStrdup(BAD_CAST val);
2101#ifdef XP_DEBUG_OBJ_USAGE
2102 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2103#endif
2104 return(ret);
2105 }
2106 }
2107 return(xmlXPathNewCString(val));
2108}
2109
2110/**
2111 * xmlXPathCacheNewString:
2112 * @ctxt: the XPath context
2113 * @val: the xmlChar * value
2114 *
2115 * This is the cached version of xmlXPathNewString().
2116 * Acquire an xmlXPathObjectPtr of type string and of value @val
2117 *
2118 * Returns the created or reused object.
2119 */
2120static xmlXPathObjectPtr
2121xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2122{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002123 if ((ctxt != NULL) && (ctxt->cache)) {
2124 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002125
2126 if ((cache->stringObjs != NULL) &&
2127 (cache->stringObjs->number != 0))
2128 {
2129 xmlXPathObjectPtr ret;
2130
2131 ret = (xmlXPathObjectPtr)
2132 cache->stringObjs->items[--cache->stringObjs->number];
2133 ret->type = XPATH_STRING;
2134 if (val != NULL)
2135 ret->stringval = xmlStrdup(val);
2136 else
2137 ret->stringval = xmlStrdup((const xmlChar *)"");
2138#ifdef XP_DEBUG_OBJ_USAGE
2139 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2140#endif
2141 return(ret);
2142 } else if ((cache->miscObjs != NULL) &&
2143 (cache->miscObjs->number != 0))
2144 {
2145 xmlXPathObjectPtr ret;
2146
2147 ret = (xmlXPathObjectPtr)
2148 cache->miscObjs->items[--cache->miscObjs->number];
2149
2150 ret->type = XPATH_STRING;
2151 if (val != NULL)
2152 ret->stringval = xmlStrdup(val);
2153 else
2154 ret->stringval = xmlStrdup((const xmlChar *)"");
2155#ifdef XP_DEBUG_OBJ_USAGE
2156 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2157#endif
2158 return(ret);
2159 }
2160 }
2161 return(xmlXPathNewString(val));
2162}
2163
2164/**
2165 * xmlXPathCacheNewBoolean:
2166 * @ctxt: the XPath context
2167 * @val: the boolean value
2168 *
2169 * This is the cached version of xmlXPathNewBoolean().
2170 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2171 *
2172 * Returns the created or reused object.
2173 */
2174static xmlXPathObjectPtr
2175xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2176{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002177 if ((ctxt != NULL) && (ctxt->cache)) {
2178 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002179
2180 if ((cache->booleanObjs != NULL) &&
2181 (cache->booleanObjs->number != 0))
2182 {
2183 xmlXPathObjectPtr ret;
2184
2185 ret = (xmlXPathObjectPtr)
2186 cache->booleanObjs->items[--cache->booleanObjs->number];
2187 ret->type = XPATH_BOOLEAN;
2188 ret->boolval = (val != 0);
2189#ifdef XP_DEBUG_OBJ_USAGE
2190 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2191#endif
2192 return(ret);
2193 } else if ((cache->miscObjs != NULL) &&
2194 (cache->miscObjs->number != 0))
2195 {
2196 xmlXPathObjectPtr ret;
2197
2198 ret = (xmlXPathObjectPtr)
2199 cache->miscObjs->items[--cache->miscObjs->number];
2200
2201 ret->type = XPATH_BOOLEAN;
2202 ret->boolval = (val != 0);
2203#ifdef XP_DEBUG_OBJ_USAGE
2204 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2205#endif
2206 return(ret);
2207 }
2208 }
2209 return(xmlXPathNewBoolean(val));
2210}
2211
2212/**
2213 * xmlXPathCacheNewFloat:
2214 * @ctxt: the XPath context
2215 * @val: the double value
2216 *
2217 * This is the cached version of xmlXPathNewFloat().
2218 * Acquires an xmlXPathObjectPtr of type double and of value @val
2219 *
2220 * Returns the created or reused object.
2221 */
2222static xmlXPathObjectPtr
2223xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2224{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002225 if ((ctxt != NULL) && (ctxt->cache)) {
2226 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002227
2228 if ((cache->numberObjs != NULL) &&
2229 (cache->numberObjs->number != 0))
2230 {
2231 xmlXPathObjectPtr ret;
2232
2233 ret = (xmlXPathObjectPtr)
2234 cache->numberObjs->items[--cache->numberObjs->number];
2235 ret->type = XPATH_NUMBER;
2236 ret->floatval = val;
2237#ifdef XP_DEBUG_OBJ_USAGE
2238 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2239#endif
2240 return(ret);
2241 } else if ((cache->miscObjs != NULL) &&
2242 (cache->miscObjs->number != 0))
2243 {
2244 xmlXPathObjectPtr ret;
2245
2246 ret = (xmlXPathObjectPtr)
2247 cache->miscObjs->items[--cache->miscObjs->number];
2248
2249 ret->type = XPATH_NUMBER;
2250 ret->floatval = val;
2251#ifdef XP_DEBUG_OBJ_USAGE
2252 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2253#endif
2254 return(ret);
2255 }
2256 }
2257 return(xmlXPathNewFloat(val));
2258}
2259
2260/**
2261 * xmlXPathCacheConvertString:
2262 * @ctxt: the XPath context
2263 * @val: an XPath object
2264 *
2265 * This is the cached version of xmlXPathConvertString().
2266 * Converts an existing object to its string() equivalent
2267 *
2268 * Returns a created or reused object, the old one is freed (cached)
2269 * (or the operation is done directly on @val)
2270 */
2271
2272static xmlXPathObjectPtr
2273xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2274 xmlChar *res = NULL;
2275
2276 if (val == NULL)
2277 return(xmlXPathCacheNewCString(ctxt, ""));
2278
2279 switch (val->type) {
2280 case XPATH_UNDEFINED:
2281#ifdef DEBUG_EXPR
2282 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2283#endif
2284 break;
2285 case XPATH_NODESET:
2286 case XPATH_XSLT_TREE:
2287 res = xmlXPathCastNodeSetToString(val->nodesetval);
2288 break;
2289 case XPATH_STRING:
2290 return(val);
2291 case XPATH_BOOLEAN:
2292 res = xmlXPathCastBooleanToString(val->boolval);
2293 break;
2294 case XPATH_NUMBER:
2295 res = xmlXPathCastNumberToString(val->floatval);
2296 break;
2297 case XPATH_USERS:
2298 case XPATH_POINT:
2299 case XPATH_RANGE:
2300 case XPATH_LOCATIONSET:
2301 TODO;
2302 break;
2303 }
2304 xmlXPathReleaseObject(ctxt, val);
2305 if (res == NULL)
2306 return(xmlXPathCacheNewCString(ctxt, ""));
2307 return(xmlXPathCacheWrapString(ctxt, res));
2308}
2309
2310/**
2311 * xmlXPathCacheObjectCopy:
2312 * @ctxt: the XPath context
2313 * @val: the original object
2314 *
2315 * This is the cached version of xmlXPathObjectCopy().
2316 * Acquire a copy of a given object
2317 *
2318 * Returns a created or reused created object.
2319 */
2320static xmlXPathObjectPtr
2321xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2322{
2323 if (val == NULL)
2324 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002325
2326 switch (val->type) {
2327 case XPATH_NODESET:
2328 if (XP_HAS_CACHE(ctxt))
2329 return(xmlXPathCacheWrapNodeSet(ctxt,
2330 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2331 case XPATH_STRING:
2332 if (XP_HAS_CACHE(ctxt))
2333 return(xmlXPathCacheNewString(ctxt, val->stringval));
2334 case XPATH_BOOLEAN:
2335 if (XP_HAS_CACHE(ctxt))
2336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2337 case XPATH_NUMBER:
2338 if (XP_HAS_CACHE(ctxt))
2339 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2340 default:
2341 break;
2342 }
2343 return(xmlXPathObjectCopy(val));
2344}
2345
2346/**
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val: an XPath object
2350 *
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2353 *
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 * is done directly on @val)
2356 */
2357static xmlXPathObjectPtr
2358xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359 xmlXPathObjectPtr ret;
2360
2361 if (val == NULL)
2362 return(xmlXPathCacheNewBoolean(ctxt, 0));
2363 if (val->type == XPATH_BOOLEAN)
2364 return(val);
2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366 xmlXPathReleaseObject(ctxt, val);
2367 return(ret);
2368}
2369
2370/**
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val: an XPath object
2374 *
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2377 *
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 * is done directly on @val)
2380 */
2381static xmlXPathObjectPtr
2382xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383 xmlXPathObjectPtr ret;
2384
2385 if (val == NULL)
2386 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387 if (val->type == XPATH_NUMBER)
2388 return(val);
2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390 xmlXPathReleaseObject(ctxt, val);
2391 return(ret);
2392}
2393
2394/************************************************************************
2395 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002396 * Parser stacks related functions and macros *
2397 * *
2398 ************************************************************************/
2399
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002400/**
2401 * valuePop:
2402 * @ctxt: an XPath evaluation context
2403 *
2404 * Pops the top XPath object from the value stack
2405 *
2406 * Returns the XPath object just removed
2407 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002408xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002409valuePop(xmlXPathParserContextPtr ctxt)
2410{
2411 xmlXPathObjectPtr ret;
2412
Daniel Veillarda82b1822004-11-08 16:24:57 +00002413 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002414 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002415 ctxt->valueNr--;
2416 if (ctxt->valueNr > 0)
2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2418 else
2419 ctxt->value = NULL;
2420 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002421 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002422 return (ret);
2423}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002424/**
2425 * valuePush:
2426 * @ctxt: an XPath evaluation context
2427 * @value: the XPath object
2428 *
2429 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002430 *
2431 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002432 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002433int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002434valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002436 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002437 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002438 xmlXPathObjectPtr *tmp;
2439
2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002442 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002443 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2445 return (0);
2446 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002447 ctxt->valueMax *= 2;
2448 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002449 }
2450 ctxt->valueTab[ctxt->valueNr] = value;
2451 ctxt->value = value;
2452 return (ctxt->valueNr++);
2453}
Owen Taylor3473f882001-02-23 17:55:21 +00002454
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002455/**
2456 * xmlXPathPopBoolean:
2457 * @ctxt: an XPath parser context
2458 *
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2461 *
2462 * Returns the boolean
2463 */
2464int
2465xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466 xmlXPathObjectPtr obj;
2467 int ret;
2468
2469 obj = valuePop(ctxt);
2470 if (obj == NULL) {
2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2472 return(0);
2473 }
William M. Brack08171912003-12-29 02:52:11 +00002474 if (obj->type != XPATH_BOOLEAN)
2475 ret = xmlXPathCastToBoolean(obj);
2476 else
2477 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002478 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002479 return(ret);
2480}
2481
2482/**
2483 * xmlXPathPopNumber:
2484 * @ctxt: an XPath parser context
2485 *
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2488 *
2489 * Returns the number
2490 */
2491double
2492xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493 xmlXPathObjectPtr obj;
2494 double ret;
2495
2496 obj = valuePop(ctxt);
2497 if (obj == NULL) {
2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2499 return(0);
2500 }
William M. Brack08171912003-12-29 02:52:11 +00002501 if (obj->type != XPATH_NUMBER)
2502 ret = xmlXPathCastToNumber(obj);
2503 else
2504 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002505 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002506 return(ret);
2507}
2508
2509/**
2510 * xmlXPathPopString:
2511 * @ctxt: an XPath parser context
2512 *
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2515 *
2516 * Returns the string
2517 */
2518xmlChar *
2519xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520 xmlXPathObjectPtr obj;
2521 xmlChar * ret;
2522
2523 obj = valuePop(ctxt);
2524 if (obj == NULL) {
2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2526 return(NULL);
2527 }
William M. Brack08171912003-12-29 02:52:11 +00002528 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002529 /* TODO: needs refactoring somewhere else */
2530 if (obj->stringval == ret)
2531 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002532 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002533 return(ret);
2534}
2535
2536/**
2537 * xmlXPathPopNodeSet:
2538 * @ctxt: an XPath parser context
2539 *
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2542 *
2543 * Returns the node-set
2544 */
2545xmlNodeSetPtr
2546xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547 xmlXPathObjectPtr obj;
2548 xmlNodeSetPtr ret;
2549
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002550 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002551 if (ctxt->value == NULL) {
2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2553 return(NULL);
2554 }
2555 if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 xmlXPathSetTypeError(ctxt);
2557 return(NULL);
2558 }
2559 obj = valuePop(ctxt);
2560 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002561#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002562 /* to fix memory leak of not clearing obj->user */
2563 if (obj->boolval && obj->user != NULL)
2564 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002565#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002566 obj->nodesetval = NULL;
2567 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002568 return(ret);
2569}
2570
2571/**
2572 * xmlXPathPopExternal:
2573 * @ctxt: an XPath parser context
2574 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002575 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002576 * Check error with #xmlXPathCheckError.
2577 *
2578 * Returns the object
2579 */
2580void *
2581xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582 xmlXPathObjectPtr obj;
2583 void * ret;
2584
Daniel Veillarda82b1822004-11-08 16:24:57 +00002585 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2587 return(NULL);
2588 }
2589 if (ctxt->value->type != XPATH_USERS) {
2590 xmlXPathSetTypeError(ctxt);
2591 return(NULL);
2592 }
2593 obj = valuePop(ctxt);
2594 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002595 obj->user = NULL;
2596 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002597 return(ret);
2598}
2599
Owen Taylor3473f882001-02-23 17:55:21 +00002600/*
2601 * Macros for accessing the content. Those should be used only by the parser,
2602 * and not exported.
2603 *
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 *
2606 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 * CUR returns the current xmlChar value, i.e. a 8 bit value
2608 * in ISO-Latin or UTF-8.
2609 * This should be used internally by the parser
2610 * only to compare to ASCII values otherwise it would break when
2611 * running with UTF-8 encoding.
2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2613 * to compare on ASCII based substring.
2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 * strings within the parser.
2616 * CURRENT Returns the current char value, with the full decoding of
2617 * UTF-8 if we are using this mode. It returns an int.
2618 * NEXT Skip to the next character, this does the proper decoding
2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 * It returns the pointer to the current xmlChar.
2621 */
2622
2623#define CUR (*ctxt->cur)
2624#define SKIP(val) ctxt->cur += (val)
2625#define NXT(val) ctxt->cur[(val)]
2626#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002627#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628
2629#define COPY_BUF(l,b,i,v) \
2630 if (l == 1) b[i++] = (xmlChar) v; \
2631 else i += xmlCopyChar(l,&b[i],v)
2632
2633#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002634
2635#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638#define CURRENT (*ctxt->cur)
2639#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2640
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002641
2642#ifndef DBL_DIG
2643#define DBL_DIG 16
2644#endif
2645#ifndef DBL_EPSILON
2646#define DBL_EPSILON 1E-9
2647#endif
2648
2649#define UPPER_DOUBLE 1E9
2650#define LOWER_DOUBLE 1E-5
2651
2652#define INTEGER_DIGITS DBL_DIG
2653#define FRACTION_DIGITS (DBL_DIG + 1)
2654#define EXPONENT_DIGITS (3 + 2)
2655
2656/**
2657 * xmlXPathFormatNumber:
2658 * @number: number to format
2659 * @buffer: output buffer
2660 * @buffersize: size of output buffer
2661 *
2662 * Convert the number into a string representation.
2663 */
2664static void
2665xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2666{
Daniel Veillardcda96922001-08-21 10:56:31 +00002667 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002668 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002669 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002670 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002671 break;
2672 case -1:
2673 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002674 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002675 break;
2676 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002677 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002678 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002679 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002680 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002681 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002682 } else if (number == ((int) number)) {
2683 char work[30];
2684 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002685 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002686
2687 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002688 if (value == 0) {
2689 *ptr++ = '0';
2690 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002691 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002692 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002693 while ((*cur) && (ptr - buffer < buffersize)) {
2694 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002695 }
2696 }
2697 if (ptr - buffer < buffersize) {
2698 *ptr = 0;
2699 } else if (buffersize > 0) {
2700 ptr--;
2701 *ptr = 0;
2702 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002703 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002704 /* 3 is sign, decimal point, and terminating zero */
2705 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2706 int integer_place, fraction_place;
2707 char *ptr;
2708 char *after_fraction;
2709 double absolute_value;
2710 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002711
Bjorn Reese70a9da52001-04-21 16:57:29 +00002712 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002713
Bjorn Reese70a9da52001-04-21 16:57:29 +00002714 /*
2715 * First choose format - scientific or regular floating point.
2716 * In either case, result is in work, and after_fraction points
2717 * just past the fractional part.
2718 */
2719 if ( ((absolute_value > UPPER_DOUBLE) ||
2720 (absolute_value < LOWER_DOUBLE)) &&
2721 (absolute_value != 0.0) ) {
2722 /* Use scientific notation */
2723 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2724 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002725 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002726 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002727 while ((size > 0) && (work[size] != 'e')) size--;
2728 after_fraction = work + size;
2729
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002730 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002731 else {
2732 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002733 if (absolute_value > 0.0)
2734 integer_place = 1 + (int)log10(absolute_value);
2735 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002736 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002737 fraction_place = (integer_place > 0)
2738 ? DBL_DIG - integer_place
2739 : DBL_DIG;
2740 size = snprintf(work, sizeof(work), "%0.*f",
2741 fraction_place, number);
2742 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002743 }
2744
Bjorn Reese70a9da52001-04-21 16:57:29 +00002745 /* Remove fractional trailing zeroes */
2746 ptr = after_fraction;
2747 while (*(--ptr) == '0')
2748 ;
2749 if (*ptr != '.')
2750 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002751 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002752
2753 /* Finally copy result back to caller */
2754 size = strlen(work) + 1;
2755 if (size > buffersize) {
2756 work[buffersize - 1] = 0;
2757 size = buffersize;
2758 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002759 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002760 }
2761 break;
2762 }
2763}
2764
Owen Taylor3473f882001-02-23 17:55:21 +00002765
2766/************************************************************************
2767 * *
2768 * Routines to handle NodeSets *
2769 * *
2770 ************************************************************************/
2771
2772/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002773 * xmlXPathOrderDocElems:
2774 * @doc: an input document
2775 *
2776 * Call this routine to speed up XPath computation on static documents.
2777 * This stamps all the element nodes with the document order
2778 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002779 * field, the value stored is actually - the node number (starting at -1)
2780 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002781 *
William M. Brack08171912003-12-29 02:52:11 +00002782 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002783 * of error.
2784 */
2785long
2786xmlXPathOrderDocElems(xmlDocPtr doc) {
2787 long count = 0;
2788 xmlNodePtr cur;
2789
2790 if (doc == NULL)
2791 return(-1);
2792 cur = doc->children;
2793 while (cur != NULL) {
2794 if (cur->type == XML_ELEMENT_NODE) {
2795 cur->content = (void *) (-(++count));
2796 if (cur->children != NULL) {
2797 cur = cur->children;
2798 continue;
2799 }
2800 }
2801 if (cur->next != NULL) {
2802 cur = cur->next;
2803 continue;
2804 }
2805 do {
2806 cur = cur->parent;
2807 if (cur == NULL)
2808 break;
2809 if (cur == (xmlNodePtr) doc) {
2810 cur = NULL;
2811 break;
2812 }
2813 if (cur->next != NULL) {
2814 cur = cur->next;
2815 break;
2816 }
2817 } while (cur != NULL);
2818 }
2819 return(count);
2820}
2821
2822/**
Owen Taylor3473f882001-02-23 17:55:21 +00002823 * xmlXPathCmpNodes:
2824 * @node1: the first node
2825 * @node2: the second node
2826 *
2827 * Compare two nodes w.r.t document order
2828 *
2829 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002830 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002831 */
2832int
2833xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2834 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002835 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002836 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002837 xmlNodePtr cur, root;
2838
2839 if ((node1 == NULL) || (node2 == NULL))
2840 return(-2);
2841 /*
2842 * a couple of optimizations which will avoid computations in most cases
2843 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002844 if (node1->type == XML_ATTRIBUTE_NODE) {
2845 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002846 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002847 node1 = node1->parent;
2848 }
2849 if (node2->type == XML_ATTRIBUTE_NODE) {
2850 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002851 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002852 node2 = node2->parent;
2853 }
2854 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002855 if (attr1 == attr2) {
2856 /* not required, but we keep attributes in order */
2857 if (attr1 != 0) {
2858 cur = attrNode2->prev;
2859 while (cur != NULL) {
2860 if (cur == attrNode1)
2861 return (1);
2862 cur = cur->prev;
2863 }
2864 return (-1);
2865 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002866 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002867 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002868 if (attr2 == 1)
2869 return(1);
2870 return(-1);
2871 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002872 if ((node1->type == XML_NAMESPACE_DECL) ||
2873 (node2->type == XML_NAMESPACE_DECL))
2874 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002875 if (node1 == node2->prev)
2876 return(1);
2877 if (node1 == node2->next)
2878 return(-1);
2879
2880 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002881 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002882 */
2883 if ((node1->type == XML_ELEMENT_NODE) &&
2884 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002885 (0 > (long) node1->content) &&
2886 (0 > (long) node2->content) &&
2887 (node1->doc == node2->doc)) {
2888 long l1, l2;
2889
2890 l1 = -((long) node1->content);
2891 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002892 if (l1 < l2)
2893 return(1);
2894 if (l1 > l2)
2895 return(-1);
2896 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002897
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002898 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002899 * compute depth to root
2900 */
2901 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2902 if (cur == node1)
2903 return(1);
2904 depth2++;
2905 }
2906 root = cur;
2907 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2908 if (cur == node2)
2909 return(-1);
2910 depth1++;
2911 }
2912 /*
2913 * Distinct document (or distinct entities :-( ) case.
2914 */
2915 if (root != cur) {
2916 return(-2);
2917 }
2918 /*
2919 * get the nearest common ancestor.
2920 */
2921 while (depth1 > depth2) {
2922 depth1--;
2923 node1 = node1->parent;
2924 }
2925 while (depth2 > depth1) {
2926 depth2--;
2927 node2 = node2->parent;
2928 }
2929 while (node1->parent != node2->parent) {
2930 node1 = node1->parent;
2931 node2 = node2->parent;
2932 /* should not happen but just in case ... */
2933 if ((node1 == NULL) || (node2 == NULL))
2934 return(-2);
2935 }
2936 /*
2937 * Find who's first.
2938 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002939 if (node1 == node2->prev)
2940 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002941 if (node1 == node2->next)
2942 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002943 /*
2944 * Speedup using document order if availble.
2945 */
2946 if ((node1->type == XML_ELEMENT_NODE) &&
2947 (node2->type == XML_ELEMENT_NODE) &&
2948 (0 > (long) node1->content) &&
2949 (0 > (long) node2->content) &&
2950 (node1->doc == node2->doc)) {
2951 long l1, l2;
2952
2953 l1 = -((long) node1->content);
2954 l2 = -((long) node2->content);
2955 if (l1 < l2)
2956 return(1);
2957 if (l1 > l2)
2958 return(-1);
2959 }
2960
Owen Taylor3473f882001-02-23 17:55:21 +00002961 for (cur = node1->next;cur != NULL;cur = cur->next)
2962 if (cur == node2)
2963 return(1);
2964 return(-1); /* assume there is no sibling list corruption */
2965}
2966
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002967#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002968/**
2969 * xmlXPathCmpNodesExt:
2970 * @node1: the first node
2971 * @node2: the second node
2972 *
2973 * Compare two nodes w.r.t document order.
2974 * This one is optimized for handling of non-element nodes.
2975 *
2976 * Returns -2 in case of error 1 if first point < second point, 0 if
2977 * it's the same node, -1 otherwise
2978 */
2979static int
2980xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2981 int depth1, depth2;
2982 int misc = 0, precedence1 = 0, precedence2 = 0;
2983 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2984 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002985 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002986
2987 if ((node1 == NULL) || (node2 == NULL))
2988 return(-2);
2989
2990 if (node1 == node2)
2991 return(0);
2992
2993 /*
2994 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002995 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002996 switch (node1->type) {
2997 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002998 if (node2->type == XML_ELEMENT_NODE) {
2999 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3000 (0 > (long) node2->content) &&
3001 (node1->doc == node2->doc))
3002 {
3003 l1 = -((long) node1->content);
3004 l2 = -((long) node2->content);
3005 if (l1 < l2)
3006 return(1);
3007 if (l1 > l2)
3008 return(-1);
3009 } else
3010 goto turtle_comparison;
3011 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003012 break;
3013 case XML_ATTRIBUTE_NODE:
3014 precedence1 = 1; /* element is owner */
3015 miscNode1 = node1;
3016 node1 = node1->parent;
3017 misc = 1;
3018 break;
3019 case XML_TEXT_NODE:
3020 case XML_CDATA_SECTION_NODE:
3021 case XML_COMMENT_NODE:
3022 case XML_PI_NODE: {
3023 miscNode1 = node1;
3024 /*
3025 * Find nearest element node.
3026 */
3027 if (node1->prev != NULL) {
3028 do {
3029 node1 = node1->prev;
3030 if (node1->type == XML_ELEMENT_NODE) {
3031 precedence1 = 3; /* element in prev-sibl axis */
3032 break;
3033 }
3034 if (node1->prev == NULL) {
3035 precedence1 = 2; /* element is parent */
3036 /*
3037 * URGENT TODO: Are there any cases, where the
3038 * parent of such a node is not an element node?
3039 */
3040 node1 = node1->parent;
3041 break;
3042 }
3043 } while (1);
3044 } else {
3045 precedence1 = 2; /* element is parent */
3046 node1 = node1->parent;
3047 }
3048 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3049 /*
3050 * Fallback for whatever case.
3051 */
3052 node1 = miscNode1;
3053 precedence1 = 0;
3054 } else
3055 misc = 1;
3056 }
3057 break;
3058 case XML_NAMESPACE_DECL:
3059 /*
3060 * TODO: why do we return 1 for namespace nodes?
3061 */
3062 return(1);
3063 default:
3064 break;
3065 }
3066 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003067 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003068 break;
3069 case XML_ATTRIBUTE_NODE:
3070 precedence2 = 1; /* element is owner */
3071 miscNode2 = node2;
3072 node2 = node2->parent;
3073 misc = 1;
3074 break;
3075 case XML_TEXT_NODE:
3076 case XML_CDATA_SECTION_NODE:
3077 case XML_COMMENT_NODE:
3078 case XML_PI_NODE: {
3079 miscNode2 = node2;
3080 if (node2->prev != NULL) {
3081 do {
3082 node2 = node2->prev;
3083 if (node2->type == XML_ELEMENT_NODE) {
3084 precedence2 = 3; /* element in prev-sibl axis */
3085 break;
3086 }
3087 if (node2->prev == NULL) {
3088 precedence2 = 2; /* element is parent */
3089 node2 = node2->parent;
3090 break;
3091 }
3092 } while (1);
3093 } else {
3094 precedence2 = 2; /* element is parent */
3095 node2 = node2->parent;
3096 }
3097 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3098 (0 <= (long) node1->content))
3099 {
3100 node2 = miscNode2;
3101 precedence2 = 0;
3102 } else
3103 misc = 1;
3104 }
3105 break;
3106 case XML_NAMESPACE_DECL:
3107 return(1);
3108 default:
3109 break;
3110 }
3111 if (misc) {
3112 if (node1 == node2) {
3113 if (precedence1 == precedence2) {
3114 /*
3115 * The ugly case; but normally there aren't many
3116 * adjacent non-element nodes around.
3117 */
3118 cur = miscNode2->prev;
3119 while (cur != NULL) {
3120 if (cur == miscNode1)
3121 return(1);
3122 if (cur->type == XML_ELEMENT_NODE)
3123 return(-1);
3124 cur = cur->prev;
3125 }
3126 return (-1);
3127 } else {
3128 /*
3129 * Evaluate based on higher precedence wrt to the element.
3130 * TODO: This assumes attributes are sorted before content.
3131 * Is this 100% correct?
3132 */
3133 if (precedence1 < precedence2)
3134 return(1);
3135 else
3136 return(-1);
3137 }
3138 }
3139 /*
3140 * Special case: One of the helper-elements is contained by the other.
3141 * <foo>
3142 * <node2>
3143 * <node1>Text-1(precedence1 == 2)</node1>
3144 * </node2>
3145 * Text-6(precedence2 == 3)
3146 * </foo>
3147 */
3148 if ((precedence2 == 3) && (precedence1 > 1)) {
3149 cur = node1->parent;
3150 while (cur) {
3151 if (cur == node2)
3152 return(1);
3153 cur = cur->parent;
3154 }
3155 }
3156 if ((precedence1 == 3) && (precedence2 > 1)) {
3157 cur = node2->parent;
3158 while (cur) {
3159 if (cur == node1)
3160 return(-1);
3161 cur = cur->parent;
3162 }
3163 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003164 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003165
3166 /*
3167 * Speedup using document order if availble.
3168 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003169 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003170 (node2->type == XML_ELEMENT_NODE) &&
3171 (0 > (long) node1->content) &&
3172 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003173 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003174
3175 l1 = -((long) node1->content);
3176 l2 = -((long) node2->content);
3177 if (l1 < l2)
3178 return(1);
3179 if (l1 > l2)
3180 return(-1);
3181 }
3182
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003183turtle_comparison:
3184
3185 if (node1 == node2->prev)
3186 return(1);
3187 if (node1 == node2->next)
3188 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003189 /*
3190 * compute depth to root
3191 */
3192 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3193 if (cur == node1)
3194 return(1);
3195 depth2++;
3196 }
3197 root = cur;
3198 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3199 if (cur == node2)
3200 return(-1);
3201 depth1++;
3202 }
3203 /*
3204 * Distinct document (or distinct entities :-( ) case.
3205 */
3206 if (root != cur) {
3207 return(-2);
3208 }
3209 /*
3210 * get the nearest common ancestor.
3211 */
3212 while (depth1 > depth2) {
3213 depth1--;
3214 node1 = node1->parent;
3215 }
3216 while (depth2 > depth1) {
3217 depth2--;
3218 node2 = node2->parent;
3219 }
3220 while (node1->parent != node2->parent) {
3221 node1 = node1->parent;
3222 node2 = node2->parent;
3223 /* should not happen but just in case ... */
3224 if ((node1 == NULL) || (node2 == NULL))
3225 return(-2);
3226 }
3227 /*
3228 * Find who's first.
3229 */
3230 if (node1 == node2->prev)
3231 return(1);
3232 if (node1 == node2->next)
3233 return(-1);
3234 /*
3235 * Speedup using document order if availble.
3236 */
3237 if ((node1->type == XML_ELEMENT_NODE) &&
3238 (node2->type == XML_ELEMENT_NODE) &&
3239 (0 > (long) node1->content) &&
3240 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003241 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003242
3243 l1 = -((long) node1->content);
3244 l2 = -((long) node2->content);
3245 if (l1 < l2)
3246 return(1);
3247 if (l1 > l2)
3248 return(-1);
3249 }
3250
3251 for (cur = node1->next;cur != NULL;cur = cur->next)
3252 if (cur == node2)
3253 return(1);
3254 return(-1); /* assume there is no sibling list corruption */
3255}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003256#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003257
Owen Taylor3473f882001-02-23 17:55:21 +00003258/**
3259 * xmlXPathNodeSetSort:
3260 * @set: the node set
3261 *
3262 * Sort the node set in document order
3263 */
3264void
3265xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003266 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003267 xmlNodePtr tmp;
3268
3269 if (set == NULL)
3270 return;
3271
3272 /* Use Shell's sort to sort the node-set */
3273 len = set->nodeNr;
3274 for (incr = len / 2; incr > 0; incr /= 2) {
3275 for (i = incr; i < len; i++) {
3276 j = i - incr;
3277 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003278#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003279 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3280 set->nodeTab[j + incr]) == -1)
3281#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003282 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003283 set->nodeTab[j + incr]) == -1)
3284#endif
3285 {
Owen Taylor3473f882001-02-23 17:55:21 +00003286 tmp = set->nodeTab[j];
3287 set->nodeTab[j] = set->nodeTab[j + incr];
3288 set->nodeTab[j + incr] = tmp;
3289 j -= incr;
3290 } else
3291 break;
3292 }
3293 }
3294 }
3295}
3296
3297#define XML_NODESET_DEFAULT 10
3298/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003299 * xmlXPathNodeSetDupNs:
3300 * @node: the parent node of the namespace XPath node
3301 * @ns: the libxml namespace declaration node.
3302 *
3303 * Namespace node in libxml don't match the XPath semantic. In a node set
3304 * the namespace nodes are duplicated and the next pointer is set to the
3305 * parent node in the XPath semantic.
3306 *
3307 * Returns the newly created object.
3308 */
3309static xmlNodePtr
3310xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3311 xmlNsPtr cur;
3312
3313 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3314 return(NULL);
3315 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3316 return((xmlNodePtr) ns);
3317
3318 /*
3319 * Allocate a new Namespace and fill the fields.
3320 */
3321 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3322 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003323 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003324 return(NULL);
3325 }
3326 memset(cur, 0, sizeof(xmlNs));
3327 cur->type = XML_NAMESPACE_DECL;
3328 if (ns->href != NULL)
3329 cur->href = xmlStrdup(ns->href);
3330 if (ns->prefix != NULL)
3331 cur->prefix = xmlStrdup(ns->prefix);
3332 cur->next = (xmlNsPtr) node;
3333 return((xmlNodePtr) cur);
3334}
3335
3336/**
3337 * xmlXPathNodeSetFreeNs:
3338 * @ns: the XPath namespace node found in a nodeset.
3339 *
William M. Brack08171912003-12-29 02:52:11 +00003340 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003341 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003342 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003343 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003344void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003345xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3346 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3347 return;
3348
3349 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3350 if (ns->href != NULL)
3351 xmlFree((xmlChar *)ns->href);
3352 if (ns->prefix != NULL)
3353 xmlFree((xmlChar *)ns->prefix);
3354 xmlFree(ns);
3355 }
3356}
3357
3358/**
Owen Taylor3473f882001-02-23 17:55:21 +00003359 * xmlXPathNodeSetCreate:
3360 * @val: an initial xmlNodePtr, or NULL
3361 *
3362 * Create a new xmlNodeSetPtr of type double and of value @val
3363 *
3364 * Returns the newly created object.
3365 */
3366xmlNodeSetPtr
3367xmlXPathNodeSetCreate(xmlNodePtr val) {
3368 xmlNodeSetPtr ret;
3369
3370 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3371 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003372 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003373 return(NULL);
3374 }
3375 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3376 if (val != NULL) {
3377 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3378 sizeof(xmlNodePtr));
3379 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003380 xmlXPathErrMemory(NULL, "creating nodeset\n");
3381 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003382 return(NULL);
3383 }
3384 memset(ret->nodeTab, 0 ,
3385 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3386 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003387 if (val->type == XML_NAMESPACE_DECL) {
3388 xmlNsPtr ns = (xmlNsPtr) val;
3389
3390 ret->nodeTab[ret->nodeNr++] =
3391 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3392 } else
3393 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003394 }
3395 return(ret);
3396}
3397
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003398/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003399 * xmlXPathNodeSetContains:
3400 * @cur: the node-set
3401 * @val: the node
3402 *
3403 * checks whether @cur contains @val
3404 *
3405 * Returns true (1) if @cur contains @val, false (0) otherwise
3406 */
3407int
3408xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3409 int i;
3410
Daniel Veillarda82b1822004-11-08 16:24:57 +00003411 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003412 if (val->type == XML_NAMESPACE_DECL) {
3413 for (i = 0; i < cur->nodeNr; i++) {
3414 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3415 xmlNsPtr ns1, ns2;
3416
3417 ns1 = (xmlNsPtr) val;
3418 ns2 = (xmlNsPtr) cur->nodeTab[i];
3419 if (ns1 == ns2)
3420 return(1);
3421 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3422 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3423 return(1);
3424 }
3425 }
3426 } else {
3427 for (i = 0; i < cur->nodeNr; i++) {
3428 if (cur->nodeTab[i] == val)
3429 return(1);
3430 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003431 }
3432 return(0);
3433}
3434
3435/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003436 * xmlXPathNodeSetAddNs:
3437 * @cur: the initial node set
3438 * @node: the hosting node
3439 * @ns: a the namespace node
3440 *
3441 * add a new namespace node to an existing NodeSet
3442 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003443void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003444xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3445 int i;
3446
Daniel Veillarda82b1822004-11-08 16:24:57 +00003447
3448 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3449 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003450 (node->type != XML_ELEMENT_NODE))
3451 return;
3452
William M. Brack08171912003-12-29 02:52:11 +00003453 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003454 /*
William M. Brack08171912003-12-29 02:52:11 +00003455 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003456 */
3457 for (i = 0;i < cur->nodeNr;i++) {
3458 if ((cur->nodeTab[i] != NULL) &&
3459 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003460 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003461 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3462 return;
3463 }
3464
3465 /*
3466 * grow the nodeTab if needed
3467 */
3468 if (cur->nodeMax == 0) {
3469 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3470 sizeof(xmlNodePtr));
3471 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003472 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003473 return;
3474 }
3475 memset(cur->nodeTab, 0 ,
3476 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3477 cur->nodeMax = XML_NODESET_DEFAULT;
3478 } else if (cur->nodeNr == cur->nodeMax) {
3479 xmlNodePtr *temp;
3480
3481 cur->nodeMax *= 2;
3482 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3483 sizeof(xmlNodePtr));
3484 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003485 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003486 return;
3487 }
3488 cur->nodeTab = temp;
3489 }
3490 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3491}
3492
3493/**
Owen Taylor3473f882001-02-23 17:55:21 +00003494 * xmlXPathNodeSetAdd:
3495 * @cur: the initial node set
3496 * @val: a new xmlNodePtr
3497 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003498 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003499 */
3500void
3501xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3502 int i;
3503
Daniel Veillarda82b1822004-11-08 16:24:57 +00003504 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003505
Daniel Veillardef0b4502003-03-24 13:57:34 +00003506#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003507 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3508 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003509#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003510
William M. Brack08171912003-12-29 02:52:11 +00003511 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003512 /*
William M. Brack08171912003-12-29 02:52:11 +00003513 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003514 */
3515 for (i = 0;i < cur->nodeNr;i++)
3516 if (cur->nodeTab[i] == val) return;
3517
3518 /*
3519 * grow the nodeTab if needed
3520 */
3521 if (cur->nodeMax == 0) {
3522 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3523 sizeof(xmlNodePtr));
3524 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003525 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003526 return;
3527 }
3528 memset(cur->nodeTab, 0 ,
3529 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3530 cur->nodeMax = XML_NODESET_DEFAULT;
3531 } else if (cur->nodeNr == cur->nodeMax) {
3532 xmlNodePtr *temp;
3533
3534 cur->nodeMax *= 2;
3535 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3536 sizeof(xmlNodePtr));
3537 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003538 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003539 return;
3540 }
3541 cur->nodeTab = temp;
3542 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003543 if (val->type == XML_NAMESPACE_DECL) {
3544 xmlNsPtr ns = (xmlNsPtr) val;
3545
3546 cur->nodeTab[cur->nodeNr++] =
3547 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3548 } else
3549 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003550}
3551
3552/**
3553 * xmlXPathNodeSetAddUnique:
3554 * @cur: the initial node set
3555 * @val: a new xmlNodePtr
3556 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003557 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003558 * when we are sure the node is not already in the set.
3559 */
3560void
3561xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003562 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003563
Daniel Veillardef0b4502003-03-24 13:57:34 +00003564#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003565 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3566 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003567#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003568
William M. Brack08171912003-12-29 02:52:11 +00003569 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003570 /*
3571 * grow the nodeTab if needed
3572 */
3573 if (cur->nodeMax == 0) {
3574 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3575 sizeof(xmlNodePtr));
3576 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003577 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003578 return;
3579 }
3580 memset(cur->nodeTab, 0 ,
3581 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3582 cur->nodeMax = XML_NODESET_DEFAULT;
3583 } else if (cur->nodeNr == cur->nodeMax) {
3584 xmlNodePtr *temp;
3585
3586 cur->nodeMax *= 2;
3587 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3588 sizeof(xmlNodePtr));
3589 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003590 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003591 return;
3592 }
3593 cur->nodeTab = temp;
3594 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003595 if (val->type == XML_NAMESPACE_DECL) {
3596 xmlNsPtr ns = (xmlNsPtr) val;
3597
3598 cur->nodeTab[cur->nodeNr++] =
3599 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3600 } else
3601 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003602}
3603
3604/**
3605 * xmlXPathNodeSetMerge:
3606 * @val1: the first NodeSet or NULL
3607 * @val2: the second NodeSet
3608 *
3609 * Merges two nodesets, all nodes from @val2 are added to @val1
3610 * if @val1 is NULL, a new set is created and copied from @val2
3611 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003612 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003613 */
3614xmlNodeSetPtr
3615xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003616 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003617 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003618
3619 if (val2 == NULL) return(val1);
3620 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003621 val1 = xmlXPathNodeSetCreate(NULL);
3622#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003623 /*
3624 * TODO: The optimization won't work in every case, since
3625 * those nasty namespace nodes need to be added with
3626 * xmlXPathNodeSetDupNs() to the set; thus a pure
3627 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003628 * If there was a flag on the nodesetval, indicating that
3629 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003630 */
3631 /*
3632 * Optimization: Create an equally sized node-set
3633 * and memcpy the content.
3634 */
3635 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3636 if (val1 == NULL)
3637 return(NULL);
3638 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003639 if (val2->nodeNr == 1)
3640 *(val1->nodeTab) = *(val2->nodeTab);
3641 else {
3642 memcpy(val1->nodeTab, val2->nodeTab,
3643 val2->nodeNr * sizeof(xmlNodePtr));
3644 }
3645 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003646 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003647 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003648#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003649 }
3650
William M. Brack08171912003-12-29 02:52:11 +00003651 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003652 initNr = val1->nodeNr;
3653
3654 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003655 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003656 /*
William M. Brack08171912003-12-29 02:52:11 +00003657 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003658 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003659 skip = 0;
3660 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003661 n1 = val1->nodeTab[j];
3662 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003663 skip = 1;
3664 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003665 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3666 (n2->type == XML_NAMESPACE_DECL)) {
3667 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3668 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3669 ((xmlNsPtr) n2)->prefix)))
3670 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003671 skip = 1;
3672 break;
3673 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003674 }
3675 }
3676 if (skip)
3677 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003678
3679 /*
3680 * grow the nodeTab if needed
3681 */
3682 if (val1->nodeMax == 0) {
3683 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3684 sizeof(xmlNodePtr));
3685 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003686 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003687 return(NULL);
3688 }
3689 memset(val1->nodeTab, 0 ,
3690 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3691 val1->nodeMax = XML_NODESET_DEFAULT;
3692 } else if (val1->nodeNr == val1->nodeMax) {
3693 xmlNodePtr *temp;
3694
3695 val1->nodeMax *= 2;
3696 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3697 sizeof(xmlNodePtr));
3698 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003699 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003700 return(NULL);
3701 }
3702 val1->nodeTab = temp;
3703 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003704 if (n2->type == XML_NAMESPACE_DECL) {
3705 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003706
3707 val1->nodeTab[val1->nodeNr++] =
3708 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3709 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003710 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003711 }
3712
3713 return(val1);
3714}
3715
3716/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003717 * xmlXPathNodeSetMergeUnique:
3718 * @val1: the first NodeSet or NULL
3719 * @val2: the second NodeSet
3720 *
3721 * Merges two nodesets, all nodes from @val2 are added to @val1
3722 * if @val1 is NULL, a new set is created and copied from @val2
3723 *
3724 * Returns @val1 once extended or NULL in case of error.
3725 */
3726static xmlNodeSetPtr
3727xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003728 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003729
3730 if (val2 == NULL) return(val1);
3731 if (val1 == NULL) {
3732 val1 = xmlXPathNodeSetCreate(NULL);
3733 }
3734
William M. Brack08171912003-12-29 02:52:11 +00003735 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003736
3737 for (i = 0;i < val2->nodeNr;i++) {
3738 /*
3739 * grow the nodeTab if needed
3740 */
3741 if (val1->nodeMax == 0) {
3742 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3743 sizeof(xmlNodePtr));
3744 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003745 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003746 return(NULL);
3747 }
3748 memset(val1->nodeTab, 0 ,
3749 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3750 val1->nodeMax = XML_NODESET_DEFAULT;
3751 } else if (val1->nodeNr == val1->nodeMax) {
3752 xmlNodePtr *temp;
3753
3754 val1->nodeMax *= 2;
3755 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3756 sizeof(xmlNodePtr));
3757 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003758 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003759 return(NULL);
3760 }
3761 val1->nodeTab = temp;
3762 }
3763 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3764 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3765
3766 val1->nodeTab[val1->nodeNr++] =
3767 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3768 } else
3769 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3770 }
3771
3772 return(val1);
3773}
3774
3775/**
Owen Taylor3473f882001-02-23 17:55:21 +00003776 * xmlXPathNodeSetDel:
3777 * @cur: the initial node set
3778 * @val: an xmlNodePtr
3779 *
3780 * Removes an xmlNodePtr from an existing NodeSet
3781 */
3782void
3783xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3784 int i;
3785
3786 if (cur == NULL) return;
3787 if (val == NULL) return;
3788
3789 /*
William M. Brack08171912003-12-29 02:52:11 +00003790 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00003791 */
3792 for (i = 0;i < cur->nodeNr;i++)
3793 if (cur->nodeTab[i] == val) break;
3794
William M. Brack08171912003-12-29 02:52:11 +00003795 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00003796#ifdef DEBUG
3797 xmlGenericError(xmlGenericErrorContext,
3798 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
3799 val->name);
3800#endif
3801 return;
3802 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003803 if ((cur->nodeTab[i] != NULL) &&
3804 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3805 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003806 cur->nodeNr--;
3807 for (;i < cur->nodeNr;i++)
3808 cur->nodeTab[i] = cur->nodeTab[i + 1];
3809 cur->nodeTab[cur->nodeNr] = NULL;
3810}
3811
3812/**
3813 * xmlXPathNodeSetRemove:
3814 * @cur: the initial node set
3815 * @val: the index to remove
3816 *
3817 * Removes an entry from an existing NodeSet list.
3818 */
3819void
3820xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3821 if (cur == NULL) return;
3822 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003823 if ((cur->nodeTab[val] != NULL) &&
3824 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3825 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00003826 cur->nodeNr--;
3827 for (;val < cur->nodeNr;val++)
3828 cur->nodeTab[val] = cur->nodeTab[val + 1];
3829 cur->nodeTab[cur->nodeNr] = NULL;
3830}
3831
3832/**
3833 * xmlXPathFreeNodeSet:
3834 * @obj: the xmlNodeSetPtr to free
3835 *
3836 * Free the NodeSet compound (not the actual nodes !).
3837 */
3838void
3839xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3840 if (obj == NULL) return;
3841 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003842 int i;
3843
William M. Brack08171912003-12-29 02:52:11 +00003844 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003845 for (i = 0;i < obj->nodeNr;i++)
3846 if ((obj->nodeTab[i] != NULL) &&
3847 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3848 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003849 xmlFree(obj->nodeTab);
3850 }
Owen Taylor3473f882001-02-23 17:55:21 +00003851 xmlFree(obj);
3852}
3853
3854/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003855 * xmlXPathNodeSetClear:
3856 * @set: the xmlNodeSetPtr to free
3857 *
3858 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3859 * are feed), but does *not* free the list itself. Sets the length of the
3860 * list to 0.
3861 */
3862static void
3863xmlXPathNodeSetClear(xmlNodeSetPtr set)
3864{
3865 int i;
3866 xmlNodePtr node;
3867
3868 if ((set == NULL) || (set->nodeNr <= 0))
3869 return;
3870
3871 for (i = 0; i < set->nodeNr; i++) {
3872 node = set->nodeTab[i];
3873 if ((node != NULL) &&
3874 (node->type == XML_NAMESPACE_DECL))
3875 {
3876 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3877 }
3878 }
3879 set->nodeNr = 0;
3880}
3881
3882/**
Owen Taylor3473f882001-02-23 17:55:21 +00003883 * xmlXPathFreeValueTree:
3884 * @obj: the xmlNodeSetPtr to free
3885 *
3886 * Free the NodeSet compound and the actual tree, this is different
3887 * from xmlXPathFreeNodeSet()
3888 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003889static void
Owen Taylor3473f882001-02-23 17:55:21 +00003890xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3891 int i;
3892
3893 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003894
3895 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003896 for (i = 0;i < obj->nodeNr;i++) {
3897 if (obj->nodeTab[i] != NULL) {
3898 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3899 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3900 } else {
3901 xmlFreeNodeList(obj->nodeTab[i]);
3902 }
3903 }
3904 }
Owen Taylor3473f882001-02-23 17:55:21 +00003905 xmlFree(obj->nodeTab);
3906 }
Owen Taylor3473f882001-02-23 17:55:21 +00003907 xmlFree(obj);
3908}
3909
3910#if defined(DEBUG) || defined(DEBUG_STEP)
3911/**
3912 * xmlGenericErrorContextNodeSet:
3913 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00003914 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00003915 *
3916 * Quick display of a NodeSet
3917 */
3918void
3919xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
3920 int i;
3921
3922 if (output == NULL) output = xmlGenericErrorContext;
3923 if (obj == NULL) {
3924 fprintf(output, "NodeSet == NULL !\n");
3925 return;
3926 }
3927 if (obj->nodeNr == 0) {
3928 fprintf(output, "NodeSet is empty\n");
3929 return;
3930 }
3931 if (obj->nodeTab == NULL) {
3932 fprintf(output, " nodeTab == NULL !\n");
3933 return;
3934 }
3935 for (i = 0; i < obj->nodeNr; i++) {
3936 if (obj->nodeTab[i] == NULL) {
3937 fprintf(output, " NULL !\n");
3938 return;
3939 }
3940 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
3941 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
3942 fprintf(output, " /");
3943 else if (obj->nodeTab[i]->name == NULL)
3944 fprintf(output, " noname!");
3945 else fprintf(output, " %s", obj->nodeTab[i]->name);
3946 }
3947 fprintf(output, "\n");
3948}
3949#endif
3950
3951/**
3952 * xmlXPathNewNodeSet:
3953 * @val: the NodePtr value
3954 *
3955 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3956 * it with the single Node @val
3957 *
3958 * Returns the newly created object.
3959 */
3960xmlXPathObjectPtr
3961xmlXPathNewNodeSet(xmlNodePtr val) {
3962 xmlXPathObjectPtr ret;
3963
3964 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3965 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003966 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003967 return(NULL);
3968 }
3969 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3970 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00003971 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003972 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00003973 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003974#ifdef XP_DEBUG_OBJ_USAGE
3975 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
3976#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003977 return(ret);
3978}
3979
3980/**
3981 * xmlXPathNewValueTree:
3982 * @val: the NodePtr value
3983 *
3984 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3985 * it with the tree root @val
3986 *
3987 * Returns the newly created object.
3988 */
3989xmlXPathObjectPtr
3990xmlXPathNewValueTree(xmlNodePtr val) {
3991 xmlXPathObjectPtr ret;
3992
3993 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3994 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003995 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003996 return(NULL);
3997 }
3998 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3999 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004000 ret->boolval = 1;
4001 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004002 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004003#ifdef XP_DEBUG_OBJ_USAGE
4004 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4005#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004006 return(ret);
4007}
4008
4009/**
4010 * xmlXPathNewNodeSetList:
4011 * @val: an existing NodeSet
4012 *
4013 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4014 * it with the Nodeset @val
4015 *
4016 * Returns the newly created object.
4017 */
4018xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004019xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4020{
Owen Taylor3473f882001-02-23 17:55:21 +00004021 xmlXPathObjectPtr ret;
4022 int i;
4023
4024 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004025 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004026 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004027 ret = xmlXPathNewNodeSet(NULL);
4028 else {
4029 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4030 for (i = 1; i < val->nodeNr; ++i)
4031 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4032 }
Owen Taylor3473f882001-02-23 17:55:21 +00004033
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004034 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004035}
4036
4037/**
4038 * xmlXPathWrapNodeSet:
4039 * @val: the NodePtr value
4040 *
4041 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4042 *
4043 * Returns the newly created object.
4044 */
4045xmlXPathObjectPtr
4046xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4047 xmlXPathObjectPtr ret;
4048
4049 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4050 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004051 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004052 return(NULL);
4053 }
4054 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4055 ret->type = XPATH_NODESET;
4056 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004057#ifdef XP_DEBUG_OBJ_USAGE
4058 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4059#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004060 return(ret);
4061}
4062
4063/**
4064 * xmlXPathFreeNodeSetList:
4065 * @obj: an existing NodeSetList object
4066 *
4067 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4068 * the list contrary to xmlXPathFreeObject().
4069 */
4070void
4071xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4072 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004073#ifdef XP_DEBUG_OBJ_USAGE
4074 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4075#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004076 xmlFree(obj);
4077}
4078
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004079/**
4080 * xmlXPathDifference:
4081 * @nodes1: a node-set
4082 * @nodes2: a node-set
4083 *
4084 * Implements the EXSLT - Sets difference() function:
4085 * node-set set:difference (node-set, node-set)
4086 *
4087 * Returns the difference between the two node sets, or nodes1 if
4088 * nodes2 is empty
4089 */
4090xmlNodeSetPtr
4091xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4092 xmlNodeSetPtr ret;
4093 int i, l1;
4094 xmlNodePtr cur;
4095
4096 if (xmlXPathNodeSetIsEmpty(nodes2))
4097 return(nodes1);
4098
4099 ret = xmlXPathNodeSetCreate(NULL);
4100 if (xmlXPathNodeSetIsEmpty(nodes1))
4101 return(ret);
4102
4103 l1 = xmlXPathNodeSetGetLength(nodes1);
4104
4105 for (i = 0; i < l1; i++) {
4106 cur = xmlXPathNodeSetItem(nodes1, i);
4107 if (!xmlXPathNodeSetContains(nodes2, cur))
4108 xmlXPathNodeSetAddUnique(ret, cur);
4109 }
4110 return(ret);
4111}
4112
4113/**
4114 * xmlXPathIntersection:
4115 * @nodes1: a node-set
4116 * @nodes2: a node-set
4117 *
4118 * Implements the EXSLT - Sets intersection() function:
4119 * node-set set:intersection (node-set, node-set)
4120 *
4121 * Returns a node set comprising the nodes that are within both the
4122 * node sets passed as arguments
4123 */
4124xmlNodeSetPtr
4125xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4126 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4127 int i, l1;
4128 xmlNodePtr cur;
4129
4130 if (xmlXPathNodeSetIsEmpty(nodes1))
4131 return(ret);
4132 if (xmlXPathNodeSetIsEmpty(nodes2))
4133 return(ret);
4134
4135 l1 = xmlXPathNodeSetGetLength(nodes1);
4136
4137 for (i = 0; i < l1; i++) {
4138 cur = xmlXPathNodeSetItem(nodes1, i);
4139 if (xmlXPathNodeSetContains(nodes2, cur))
4140 xmlXPathNodeSetAddUnique(ret, cur);
4141 }
4142 return(ret);
4143}
4144
4145/**
4146 * xmlXPathDistinctSorted:
4147 * @nodes: a node-set, sorted by document order
4148 *
4149 * Implements the EXSLT - Sets distinct() function:
4150 * node-set set:distinct (node-set)
4151 *
4152 * Returns a subset of the nodes contained in @nodes, or @nodes if
4153 * it is empty
4154 */
4155xmlNodeSetPtr
4156xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4157 xmlNodeSetPtr ret;
4158 xmlHashTablePtr hash;
4159 int i, l;
4160 xmlChar * strval;
4161 xmlNodePtr cur;
4162
4163 if (xmlXPathNodeSetIsEmpty(nodes))
4164 return(nodes);
4165
4166 ret = xmlXPathNodeSetCreate(NULL);
4167 l = xmlXPathNodeSetGetLength(nodes);
4168 hash = xmlHashCreate (l);
4169 for (i = 0; i < l; i++) {
4170 cur = xmlXPathNodeSetItem(nodes, i);
4171 strval = xmlXPathCastNodeToString(cur);
4172 if (xmlHashLookup(hash, strval) == NULL) {
4173 xmlHashAddEntry(hash, strval, strval);
4174 xmlXPathNodeSetAddUnique(ret, cur);
4175 } else {
4176 xmlFree(strval);
4177 }
4178 }
4179 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4180 return(ret);
4181}
4182
4183/**
4184 * xmlXPathDistinct:
4185 * @nodes: a node-set
4186 *
4187 * Implements the EXSLT - Sets distinct() function:
4188 * node-set set:distinct (node-set)
4189 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4190 * is called with the sorted node-set
4191 *
4192 * Returns a subset of the nodes contained in @nodes, or @nodes if
4193 * it is empty
4194 */
4195xmlNodeSetPtr
4196xmlXPathDistinct (xmlNodeSetPtr nodes) {
4197 if (xmlXPathNodeSetIsEmpty(nodes))
4198 return(nodes);
4199
4200 xmlXPathNodeSetSort(nodes);
4201 return(xmlXPathDistinctSorted(nodes));
4202}
4203
4204/**
4205 * xmlXPathHasSameNodes:
4206 * @nodes1: a node-set
4207 * @nodes2: a node-set
4208 *
4209 * Implements the EXSLT - Sets has-same-nodes function:
4210 * boolean set:has-same-node(node-set, node-set)
4211 *
4212 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4213 * otherwise
4214 */
4215int
4216xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4217 int i, l;
4218 xmlNodePtr cur;
4219
4220 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4221 xmlXPathNodeSetIsEmpty(nodes2))
4222 return(0);
4223
4224 l = xmlXPathNodeSetGetLength(nodes1);
4225 for (i = 0; i < l; i++) {
4226 cur = xmlXPathNodeSetItem(nodes1, i);
4227 if (xmlXPathNodeSetContains(nodes2, cur))
4228 return(1);
4229 }
4230 return(0);
4231}
4232
4233/**
4234 * xmlXPathNodeLeadingSorted:
4235 * @nodes: a node-set, sorted by document order
4236 * @node: a node
4237 *
4238 * Implements the EXSLT - Sets leading() function:
4239 * node-set set:leading (node-set, node-set)
4240 *
4241 * Returns the nodes in @nodes that precede @node in document order,
4242 * @nodes if @node is NULL or an empty node-set if @nodes
4243 * doesn't contain @node
4244 */
4245xmlNodeSetPtr
4246xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4247 int i, l;
4248 xmlNodePtr cur;
4249 xmlNodeSetPtr ret;
4250
4251 if (node == NULL)
4252 return(nodes);
4253
4254 ret = xmlXPathNodeSetCreate(NULL);
4255 if (xmlXPathNodeSetIsEmpty(nodes) ||
4256 (!xmlXPathNodeSetContains(nodes, node)))
4257 return(ret);
4258
4259 l = xmlXPathNodeSetGetLength(nodes);
4260 for (i = 0; i < l; i++) {
4261 cur = xmlXPathNodeSetItem(nodes, i);
4262 if (cur == node)
4263 break;
4264 xmlXPathNodeSetAddUnique(ret, cur);
4265 }
4266 return(ret);
4267}
4268
4269/**
4270 * xmlXPathNodeLeading:
4271 * @nodes: a node-set
4272 * @node: a node
4273 *
4274 * Implements the EXSLT - Sets leading() function:
4275 * node-set set:leading (node-set, node-set)
4276 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4277 * is called.
4278 *
4279 * Returns the nodes in @nodes that precede @node in document order,
4280 * @nodes if @node is NULL or an empty node-set if @nodes
4281 * doesn't contain @node
4282 */
4283xmlNodeSetPtr
4284xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4285 xmlXPathNodeSetSort(nodes);
4286 return(xmlXPathNodeLeadingSorted(nodes, node));
4287}
4288
4289/**
4290 * xmlXPathLeadingSorted:
4291 * @nodes1: a node-set, sorted by document order
4292 * @nodes2: a node-set, sorted by document order
4293 *
4294 * Implements the EXSLT - Sets leading() function:
4295 * node-set set:leading (node-set, node-set)
4296 *
4297 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4298 * in document order, @nodes1 if @nodes2 is NULL or empty or
4299 * an empty node-set if @nodes1 doesn't contain @nodes2
4300 */
4301xmlNodeSetPtr
4302xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4303 if (xmlXPathNodeSetIsEmpty(nodes2))
4304 return(nodes1);
4305 return(xmlXPathNodeLeadingSorted(nodes1,
4306 xmlXPathNodeSetItem(nodes2, 1)));
4307}
4308
4309/**
4310 * xmlXPathLeading:
4311 * @nodes1: a node-set
4312 * @nodes2: a node-set
4313 *
4314 * Implements the EXSLT - Sets leading() function:
4315 * node-set set:leading (node-set, node-set)
4316 * @nodes1 and @nodes2 are sorted by document order, then
4317 * #exslSetsLeadingSorted is called.
4318 *
4319 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4320 * in document order, @nodes1 if @nodes2 is NULL or empty or
4321 * an empty node-set if @nodes1 doesn't contain @nodes2
4322 */
4323xmlNodeSetPtr
4324xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4325 if (xmlXPathNodeSetIsEmpty(nodes2))
4326 return(nodes1);
4327 if (xmlXPathNodeSetIsEmpty(nodes1))
4328 return(xmlXPathNodeSetCreate(NULL));
4329 xmlXPathNodeSetSort(nodes1);
4330 xmlXPathNodeSetSort(nodes2);
4331 return(xmlXPathNodeLeadingSorted(nodes1,
4332 xmlXPathNodeSetItem(nodes2, 1)));
4333}
4334
4335/**
4336 * xmlXPathNodeTrailingSorted:
4337 * @nodes: a node-set, sorted by document order
4338 * @node: a node
4339 *
4340 * Implements the EXSLT - Sets trailing() function:
4341 * node-set set:trailing (node-set, node-set)
4342 *
4343 * Returns the nodes in @nodes that follow @node in document order,
4344 * @nodes if @node is NULL or an empty node-set if @nodes
4345 * doesn't contain @node
4346 */
4347xmlNodeSetPtr
4348xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4349 int i, l;
4350 xmlNodePtr cur;
4351 xmlNodeSetPtr ret;
4352
4353 if (node == NULL)
4354 return(nodes);
4355
4356 ret = xmlXPathNodeSetCreate(NULL);
4357 if (xmlXPathNodeSetIsEmpty(nodes) ||
4358 (!xmlXPathNodeSetContains(nodes, node)))
4359 return(ret);
4360
4361 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004362 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004363 cur = xmlXPathNodeSetItem(nodes, i);
4364 if (cur == node)
4365 break;
4366 xmlXPathNodeSetAddUnique(ret, cur);
4367 }
4368 return(ret);
4369}
4370
4371/**
4372 * xmlXPathNodeTrailing:
4373 * @nodes: a node-set
4374 * @node: a node
4375 *
4376 * Implements the EXSLT - Sets trailing() function:
4377 * node-set set:trailing (node-set, node-set)
4378 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4379 * is called.
4380 *
4381 * Returns the nodes in @nodes that follow @node in document order,
4382 * @nodes if @node is NULL or an empty node-set if @nodes
4383 * doesn't contain @node
4384 */
4385xmlNodeSetPtr
4386xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4387 xmlXPathNodeSetSort(nodes);
4388 return(xmlXPathNodeTrailingSorted(nodes, node));
4389}
4390
4391/**
4392 * xmlXPathTrailingSorted:
4393 * @nodes1: a node-set, sorted by document order
4394 * @nodes2: a node-set, sorted by document order
4395 *
4396 * Implements the EXSLT - Sets trailing() function:
4397 * node-set set:trailing (node-set, node-set)
4398 *
4399 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4400 * in document order, @nodes1 if @nodes2 is NULL or empty or
4401 * an empty node-set if @nodes1 doesn't contain @nodes2
4402 */
4403xmlNodeSetPtr
4404xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4405 if (xmlXPathNodeSetIsEmpty(nodes2))
4406 return(nodes1);
4407 return(xmlXPathNodeTrailingSorted(nodes1,
4408 xmlXPathNodeSetItem(nodes2, 0)));
4409}
4410
4411/**
4412 * xmlXPathTrailing:
4413 * @nodes1: a node-set
4414 * @nodes2: a node-set
4415 *
4416 * Implements the EXSLT - Sets trailing() function:
4417 * node-set set:trailing (node-set, node-set)
4418 * @nodes1 and @nodes2 are sorted by document order, then
4419 * #xmlXPathTrailingSorted is called.
4420 *
4421 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4422 * in document order, @nodes1 if @nodes2 is NULL or empty or
4423 * an empty node-set if @nodes1 doesn't contain @nodes2
4424 */
4425xmlNodeSetPtr
4426xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4427 if (xmlXPathNodeSetIsEmpty(nodes2))
4428 return(nodes1);
4429 if (xmlXPathNodeSetIsEmpty(nodes1))
4430 return(xmlXPathNodeSetCreate(NULL));
4431 xmlXPathNodeSetSort(nodes1);
4432 xmlXPathNodeSetSort(nodes2);
4433 return(xmlXPathNodeTrailingSorted(nodes1,
4434 xmlXPathNodeSetItem(nodes2, 0)));
4435}
4436
Owen Taylor3473f882001-02-23 17:55:21 +00004437/************************************************************************
4438 * *
4439 * Routines to handle extra functions *
4440 * *
4441 ************************************************************************/
4442
4443/**
4444 * xmlXPathRegisterFunc:
4445 * @ctxt: the XPath context
4446 * @name: the function name
4447 * @f: the function implementation or NULL
4448 *
4449 * Register a new function. If @f is NULL it unregisters the function
4450 *
4451 * Returns 0 in case of success, -1 in case of error
4452 */
4453int
4454xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4455 xmlXPathFunction f) {
4456 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4457}
4458
4459/**
4460 * xmlXPathRegisterFuncNS:
4461 * @ctxt: the XPath context
4462 * @name: the function name
4463 * @ns_uri: the function namespace URI
4464 * @f: the function implementation or NULL
4465 *
4466 * Register a new function. If @f is NULL it unregisters the function
4467 *
4468 * Returns 0 in case of success, -1 in case of error
4469 */
4470int
4471xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4472 const xmlChar *ns_uri, xmlXPathFunction f) {
4473 if (ctxt == NULL)
4474 return(-1);
4475 if (name == NULL)
4476 return(-1);
4477
4478 if (ctxt->funcHash == NULL)
4479 ctxt->funcHash = xmlHashCreate(0);
4480 if (ctxt->funcHash == NULL)
4481 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004482 if (f == NULL)
4483 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004484 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004485}
4486
4487/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004488 * xmlXPathRegisterFuncLookup:
4489 * @ctxt: the XPath context
4490 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004491 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004492 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004493 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004494 */
4495void
4496xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4497 xmlXPathFuncLookupFunc f,
4498 void *funcCtxt) {
4499 if (ctxt == NULL)
4500 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004501 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004502 ctxt->funcLookupData = funcCtxt;
4503}
4504
4505/**
Owen Taylor3473f882001-02-23 17:55:21 +00004506 * xmlXPathFunctionLookup:
4507 * @ctxt: the XPath context
4508 * @name: the function name
4509 *
4510 * Search in the Function array of the context for the given
4511 * function.
4512 *
4513 * Returns the xmlXPathFunction or NULL if not found
4514 */
4515xmlXPathFunction
4516xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004517 if (ctxt == NULL)
4518 return (NULL);
4519
4520 if (ctxt->funcLookupFunc != NULL) {
4521 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004522 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004523
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004524 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004525 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004526 if (ret != NULL)
4527 return(ret);
4528 }
Owen Taylor3473f882001-02-23 17:55:21 +00004529 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4530}
4531
4532/**
4533 * xmlXPathFunctionLookupNS:
4534 * @ctxt: the XPath context
4535 * @name: the function name
4536 * @ns_uri: the function namespace URI
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
4544xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4545 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004546 xmlXPathFunction ret;
4547
Owen Taylor3473f882001-02-23 17:55:21 +00004548 if (ctxt == NULL)
4549 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004550 if (name == NULL)
4551 return(NULL);
4552
Thomas Broyerba4ad322001-07-26 16:55:21 +00004553 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004554 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004555
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004556 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004557 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004558 if (ret != NULL)
4559 return(ret);
4560 }
4561
4562 if (ctxt->funcHash == NULL)
4563 return(NULL);
4564
William M. Brackad0e67c2004-12-01 14:35:10 +00004565 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4566 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004567}
4568
4569/**
4570 * xmlXPathRegisteredFuncsCleanup:
4571 * @ctxt: the XPath context
4572 *
4573 * Cleanup the XPath context data associated to registered functions
4574 */
4575void
4576xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4577 if (ctxt == NULL)
4578 return;
4579
4580 xmlHashFree(ctxt->funcHash, NULL);
4581 ctxt->funcHash = NULL;
4582}
4583
4584/************************************************************************
4585 * *
William M. Brack08171912003-12-29 02:52:11 +00004586 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004587 * *
4588 ************************************************************************/
4589
4590/**
4591 * xmlXPathRegisterVariable:
4592 * @ctxt: the XPath context
4593 * @name: the variable name
4594 * @value: the variable value or NULL
4595 *
4596 * Register a new variable value. If @value is NULL it unregisters
4597 * the variable
4598 *
4599 * Returns 0 in case of success, -1 in case of error
4600 */
4601int
4602xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4603 xmlXPathObjectPtr value) {
4604 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4605}
4606
4607/**
4608 * xmlXPathRegisterVariableNS:
4609 * @ctxt: the XPath context
4610 * @name: the variable name
4611 * @ns_uri: the variable namespace URI
4612 * @value: the variable value or NULL
4613 *
4614 * Register a new variable value. If @value is NULL it unregisters
4615 * the variable
4616 *
4617 * Returns 0 in case of success, -1 in case of error
4618 */
4619int
4620xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4621 const xmlChar *ns_uri,
4622 xmlXPathObjectPtr value) {
4623 if (ctxt == NULL)
4624 return(-1);
4625 if (name == NULL)
4626 return(-1);
4627
4628 if (ctxt->varHash == NULL)
4629 ctxt->varHash = xmlHashCreate(0);
4630 if (ctxt->varHash == NULL)
4631 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004632 if (value == NULL)
4633 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4634 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004635 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4636 (void *) value,
4637 (xmlHashDeallocator)xmlXPathFreeObject));
4638}
4639
4640/**
4641 * xmlXPathRegisterVariableLookup:
4642 * @ctxt: the XPath context
4643 * @f: the lookup function
4644 * @data: the lookup data
4645 *
4646 * register an external mechanism to do variable lookup
4647 */
4648void
4649xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4650 xmlXPathVariableLookupFunc f, void *data) {
4651 if (ctxt == NULL)
4652 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004653 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004654 ctxt->varLookupData = data;
4655}
4656
4657/**
4658 * xmlXPathVariableLookup:
4659 * @ctxt: the XPath context
4660 * @name: the variable name
4661 *
4662 * Search in the Variable array of the context for the given
4663 * variable value.
4664 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004665 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004666 */
4667xmlXPathObjectPtr
4668xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4669 if (ctxt == NULL)
4670 return(NULL);
4671
4672 if (ctxt->varLookupFunc != NULL) {
4673 xmlXPathObjectPtr ret;
4674
4675 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4676 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004677 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004678 }
4679 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4680}
4681
4682/**
4683 * xmlXPathVariableLookupNS:
4684 * @ctxt: the XPath context
4685 * @name: the variable name
4686 * @ns_uri: the variable namespace URI
4687 *
4688 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004689 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004690 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004691 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004692 */
4693xmlXPathObjectPtr
4694xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4695 const xmlChar *ns_uri) {
4696 if (ctxt == NULL)
4697 return(NULL);
4698
4699 if (ctxt->varLookupFunc != NULL) {
4700 xmlXPathObjectPtr ret;
4701
4702 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4703 (ctxt->varLookupData, name, ns_uri);
4704 if (ret != NULL) return(ret);
4705 }
4706
4707 if (ctxt->varHash == NULL)
4708 return(NULL);
4709 if (name == NULL)
4710 return(NULL);
4711
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004712 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004713 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004714}
4715
4716/**
4717 * xmlXPathRegisteredVariablesCleanup:
4718 * @ctxt: the XPath context
4719 *
4720 * Cleanup the XPath context data associated to registered variables
4721 */
4722void
4723xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4724 if (ctxt == NULL)
4725 return;
4726
Daniel Veillard76d66f42001-05-16 21:05:17 +00004727 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004728 ctxt->varHash = NULL;
4729}
4730
4731/**
4732 * xmlXPathRegisterNs:
4733 * @ctxt: the XPath context
4734 * @prefix: the namespace prefix
4735 * @ns_uri: the namespace name
4736 *
4737 * Register a new namespace. If @ns_uri is NULL it unregisters
4738 * the namespace
4739 *
4740 * Returns 0 in case of success, -1 in case of error
4741 */
4742int
4743xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4744 const xmlChar *ns_uri) {
4745 if (ctxt == NULL)
4746 return(-1);
4747 if (prefix == NULL)
4748 return(-1);
4749
4750 if (ctxt->nsHash == NULL)
4751 ctxt->nsHash = xmlHashCreate(10);
4752 if (ctxt->nsHash == NULL)
4753 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004754 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004755 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004756 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004757 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004758 (xmlHashDeallocator)xmlFree));
4759}
4760
4761/**
4762 * xmlXPathNsLookup:
4763 * @ctxt: the XPath context
4764 * @prefix: the namespace prefix value
4765 *
4766 * Search in the namespace declaration array of the context for the given
4767 * namespace name associated to the given prefix
4768 *
4769 * Returns the value or NULL if not found
4770 */
4771const xmlChar *
4772xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4773 if (ctxt == NULL)
4774 return(NULL);
4775 if (prefix == NULL)
4776 return(NULL);
4777
4778#ifdef XML_XML_NAMESPACE
4779 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4780 return(XML_XML_NAMESPACE);
4781#endif
4782
Daniel Veillardc8f620b2001-04-30 20:31:33 +00004783 if (ctxt->namespaces != NULL) {
4784 int i;
4785
4786 for (i = 0;i < ctxt->nsNr;i++) {
4787 if ((ctxt->namespaces[i] != NULL) &&
4788 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4789 return(ctxt->namespaces[i]->href);
4790 }
4791 }
Owen Taylor3473f882001-02-23 17:55:21 +00004792
4793 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4794}
4795
4796/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004797 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00004798 * @ctxt: the XPath context
4799 *
4800 * Cleanup the XPath context data associated to registered variables
4801 */
4802void
4803xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4804 if (ctxt == NULL)
4805 return;
4806
Daniel Veillard42766c02002-08-22 20:52:17 +00004807 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00004808 ctxt->nsHash = NULL;
4809}
4810
4811/************************************************************************
4812 * *
4813 * Routines to handle Values *
4814 * *
4815 ************************************************************************/
4816
William M. Brack08171912003-12-29 02:52:11 +00004817/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00004818
4819/**
4820 * xmlXPathNewFloat:
4821 * @val: the double value
4822 *
4823 * Create a new xmlXPathObjectPtr of type double and of value @val
4824 *
4825 * Returns the newly created object.
4826 */
4827xmlXPathObjectPtr
4828xmlXPathNewFloat(double val) {
4829 xmlXPathObjectPtr ret;
4830
4831 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4832 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004833 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004834 return(NULL);
4835 }
4836 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4837 ret->type = XPATH_NUMBER;
4838 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004839#ifdef XP_DEBUG_OBJ_USAGE
4840 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
4841#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004842 return(ret);
4843}
4844
4845/**
4846 * xmlXPathNewBoolean:
4847 * @val: the boolean value
4848 *
4849 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4850 *
4851 * Returns the newly created object.
4852 */
4853xmlXPathObjectPtr
4854xmlXPathNewBoolean(int val) {
4855 xmlXPathObjectPtr ret;
4856
4857 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4858 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004859 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004860 return(NULL);
4861 }
4862 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4863 ret->type = XPATH_BOOLEAN;
4864 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004865#ifdef XP_DEBUG_OBJ_USAGE
4866 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
4867#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004868 return(ret);
4869}
4870
4871/**
4872 * xmlXPathNewString:
4873 * @val: the xmlChar * value
4874 *
4875 * Create a new xmlXPathObjectPtr of type string and of value @val
4876 *
4877 * Returns the newly created object.
4878 */
4879xmlXPathObjectPtr
4880xmlXPathNewString(const xmlChar *val) {
4881 xmlXPathObjectPtr ret;
4882
4883 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4884 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004885 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004886 return(NULL);
4887 }
4888 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4889 ret->type = XPATH_STRING;
4890 if (val != NULL)
4891 ret->stringval = xmlStrdup(val);
4892 else
4893 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004894#ifdef XP_DEBUG_OBJ_USAGE
4895 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4896#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004897 return(ret);
4898}
4899
4900/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004901 * xmlXPathWrapString:
4902 * @val: the xmlChar * value
4903 *
4904 * Wraps the @val string into an XPath object.
4905 *
4906 * Returns the newly created object.
4907 */
4908xmlXPathObjectPtr
4909xmlXPathWrapString (xmlChar *val) {
4910 xmlXPathObjectPtr ret;
4911
4912 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4913 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004914 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004915 return(NULL);
4916 }
4917 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4918 ret->type = XPATH_STRING;
4919 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004920#ifdef XP_DEBUG_OBJ_USAGE
4921 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4922#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004923 return(ret);
4924}
4925
4926/**
Owen Taylor3473f882001-02-23 17:55:21 +00004927 * xmlXPathNewCString:
4928 * @val: the char * value
4929 *
4930 * Create a new xmlXPathObjectPtr of type string and of value @val
4931 *
4932 * Returns the newly created object.
4933 */
4934xmlXPathObjectPtr
4935xmlXPathNewCString(const char *val) {
4936 xmlXPathObjectPtr ret;
4937
4938 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4939 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004940 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004941 return(NULL);
4942 }
4943 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4944 ret->type = XPATH_STRING;
4945 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004946#ifdef XP_DEBUG_OBJ_USAGE
4947 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4948#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004949 return(ret);
4950}
4951
4952/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004953 * xmlXPathWrapCString:
4954 * @val: the char * value
4955 *
4956 * Wraps a string into an XPath object.
4957 *
4958 * Returns the newly created object.
4959 */
4960xmlXPathObjectPtr
4961xmlXPathWrapCString (char * val) {
4962 return(xmlXPathWrapString((xmlChar *)(val)));
4963}
4964
4965/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004966 * xmlXPathWrapExternal:
4967 * @val: the user data
4968 *
4969 * Wraps the @val data into an XPath object.
4970 *
4971 * Returns the newly created object.
4972 */
4973xmlXPathObjectPtr
4974xmlXPathWrapExternal (void *val) {
4975 xmlXPathObjectPtr ret;
4976
4977 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4978 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004979 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004980 return(NULL);
4981 }
4982 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4983 ret->type = XPATH_USERS;
4984 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004985#ifdef XP_DEBUG_OBJ_USAGE
4986 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
4987#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004988 return(ret);
4989}
4990
4991/**
Owen Taylor3473f882001-02-23 17:55:21 +00004992 * xmlXPathObjectCopy:
4993 * @val: the original object
4994 *
4995 * allocate a new copy of a given object
4996 *
4997 * Returns the newly created object.
4998 */
4999xmlXPathObjectPtr
5000xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5001 xmlXPathObjectPtr ret;
5002
5003 if (val == NULL)
5004 return(NULL);
5005
5006 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5007 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005008 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005009 return(NULL);
5010 }
5011 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005012#ifdef XP_DEBUG_OBJ_USAGE
5013 xmlXPathDebugObjUsageRequested(NULL, val->type);
5014#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005015 switch (val->type) {
5016 case XPATH_BOOLEAN:
5017 case XPATH_NUMBER:
5018 case XPATH_POINT:
5019 case XPATH_RANGE:
5020 break;
5021 case XPATH_STRING:
5022 ret->stringval = xmlStrdup(val->stringval);
5023 break;
5024 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005025#if 0
5026/*
5027 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5028 this previous handling is no longer correct, and can cause some serious
5029 problems (ref. bug 145547)
5030*/
Owen Taylor3473f882001-02-23 17:55:21 +00005031 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005032 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005033 xmlNodePtr cur, tmp;
5034 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005035
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005036 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005037 top = xmlNewDoc(NULL);
5038 top->name = (char *)
5039 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005040 ret->user = top;
5041 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005042 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005043 cur = val->nodesetval->nodeTab[0]->children;
5044 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005045 tmp = xmlDocCopyNode(cur, top, 1);
5046 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005047 cur = cur->next;
5048 }
5049 }
William M. Bracke9449c52004-07-11 14:41:20 +00005050
Daniel Veillard9adc0462003-03-24 18:39:54 +00005051 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005052 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005053 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005054 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005055 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005056#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005057 case XPATH_NODESET:
5058 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005059 /* Do not deallocate the copied tree value */
5060 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005061 break;
5062 case XPATH_LOCATIONSET:
5063#ifdef LIBXML_XPTR_ENABLED
5064 {
5065 xmlLocationSetPtr loc = val->user;
5066 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5067 break;
5068 }
5069#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005070 case XPATH_USERS:
5071 ret->user = val->user;
5072 break;
5073 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005074 xmlGenericError(xmlGenericErrorContext,
5075 "xmlXPathObjectCopy: unsupported type %d\n",
5076 val->type);
5077 break;
5078 }
5079 return(ret);
5080}
5081
5082/**
5083 * xmlXPathFreeObject:
5084 * @obj: the object to free
5085 *
5086 * Free up an xmlXPathObjectPtr object.
5087 */
5088void
5089xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5090 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005091 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005092 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005093#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005094 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005095 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005096 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005097 } else
5098#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005099 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005100 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005101 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005102 } else {
5103 if (obj->nodesetval != NULL)
5104 xmlXPathFreeNodeSet(obj->nodesetval);
5105 }
Owen Taylor3473f882001-02-23 17:55:21 +00005106#ifdef LIBXML_XPTR_ENABLED
5107 } else if (obj->type == XPATH_LOCATIONSET) {
5108 if (obj->user != NULL)
5109 xmlXPtrFreeLocationSet(obj->user);
5110#endif
5111 } else if (obj->type == XPATH_STRING) {
5112 if (obj->stringval != NULL)
5113 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005114 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005115#ifdef XP_DEBUG_OBJ_USAGE
5116 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5117#endif
5118 xmlFree(obj);
5119}
Owen Taylor3473f882001-02-23 17:55:21 +00005120
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005121/**
5122 * xmlXPathReleaseObject:
5123 * @obj: the xmlXPathObjectPtr to free or to cache
5124 *
5125 * Depending on the state of the cache this frees the given
5126 * XPath object or stores it in the cache.
5127 */
5128static void
5129xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5130{
5131#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5132 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5133 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5134
5135#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5136
5137 if (obj == NULL)
5138 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005139 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005140 xmlXPathFreeObject(obj);
5141 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005142 xmlXPathContextCachePtr cache =
5143 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005144
5145 switch (obj->type) {
5146 case XPATH_NODESET:
5147 case XPATH_XSLT_TREE:
5148 if (obj->nodesetval != NULL) {
5149 if (obj->boolval) {
5150 /*
5151 * It looks like the @boolval is used for
5152 * evaluation if this an XSLT Result Tree Fragment.
5153 * TODO: Check if this assumption is correct.
5154 */
5155 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5156 xmlXPathFreeValueTree(obj->nodesetval);
5157 obj->nodesetval = NULL;
5158 } else if ((obj->nodesetval->nodeMax <= 40) &&
5159 (XP_CACHE_WANTS(cache->nodesetObjs,
5160 cache->maxNodeset)))
5161 {
5162 XP_CACHE_ADD(cache->nodesetObjs, obj);
5163 goto obj_cached;
5164 } else {
5165 xmlXPathFreeNodeSet(obj->nodesetval);
5166 obj->nodesetval = NULL;
5167 }
5168 }
5169 break;
5170 case XPATH_STRING:
5171 if (obj->stringval != NULL)
5172 xmlFree(obj->stringval);
5173
5174 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5175 XP_CACHE_ADD(cache->stringObjs, obj);
5176 goto obj_cached;
5177 }
5178 break;
5179 case XPATH_BOOLEAN:
5180 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5181 XP_CACHE_ADD(cache->booleanObjs, obj);
5182 goto obj_cached;
5183 }
5184 break;
5185 case XPATH_NUMBER:
5186 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5187 XP_CACHE_ADD(cache->numberObjs, obj);
5188 goto obj_cached;
5189 }
5190 break;
5191#ifdef LIBXML_XPTR_ENABLED
5192 case XPATH_LOCATIONSET:
5193 if (obj->user != NULL) {
5194 xmlXPtrFreeLocationSet(obj->user);
5195 }
5196 goto free_obj;
5197#endif
5198 default:
5199 goto free_obj;
5200 }
5201
5202 /*
5203 * Fallback to adding to the misc-objects slot.
5204 */
5205 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5206 XP_CACHE_ADD(cache->miscObjs, obj);
5207 } else
5208 goto free_obj;
5209
5210obj_cached:
5211
5212#ifdef XP_DEBUG_OBJ_USAGE
5213 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5214#endif
5215
5216 if (obj->nodesetval != NULL) {
5217 xmlNodeSetPtr tmpset = obj->nodesetval;
5218
5219 /*
5220 * TODO: Due to those nasty ns-nodes, we need to traverse
5221 * the list and free the ns-nodes.
5222 * URGENT TODO: Check if it's actually slowing things down.
5223 * Maybe we shouldn't try to preserve the list.
5224 */
5225 if (tmpset->nodeNr > 1) {
5226 int i;
5227 xmlNodePtr node;
5228
5229 for (i = 0; i < tmpset->nodeNr; i++) {
5230 node = tmpset->nodeTab[i];
5231 if ((node != NULL) &&
5232 (node->type == XML_NAMESPACE_DECL))
5233 {
5234 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5235 }
5236 }
5237 } else if (tmpset->nodeNr == 1) {
5238 if ((tmpset->nodeTab[0] != NULL) &&
5239 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5240 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5241 }
5242 tmpset->nodeNr = 0;
5243 memset(obj, 0, sizeof(xmlXPathObject));
5244 obj->nodesetval = tmpset;
5245 } else
5246 memset(obj, 0, sizeof(xmlXPathObject));
5247
5248 return;
5249
5250free_obj:
5251 /*
5252 * Cache is full; free the object.
5253 */
5254 if (obj->nodesetval != NULL)
5255 xmlXPathFreeNodeSet(obj->nodesetval);
5256#ifdef XP_DEBUG_OBJ_USAGE
5257 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5258#endif
5259 xmlFree(obj);
5260 }
5261 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005262}
5263
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005264
5265/************************************************************************
5266 * *
5267 * Type Casting Routines *
5268 * *
5269 ************************************************************************/
5270
5271/**
5272 * xmlXPathCastBooleanToString:
5273 * @val: a boolean
5274 *
5275 * Converts a boolean to its string value.
5276 *
5277 * Returns a newly allocated string.
5278 */
5279xmlChar *
5280xmlXPathCastBooleanToString (int val) {
5281 xmlChar *ret;
5282 if (val)
5283 ret = xmlStrdup((const xmlChar *) "true");
5284 else
5285 ret = xmlStrdup((const xmlChar *) "false");
5286 return(ret);
5287}
5288
5289/**
5290 * xmlXPathCastNumberToString:
5291 * @val: a number
5292 *
5293 * Converts a number to its string value.
5294 *
5295 * Returns a newly allocated string.
5296 */
5297xmlChar *
5298xmlXPathCastNumberToString (double val) {
5299 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005300 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005301 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005302 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005303 break;
5304 case -1:
5305 ret = xmlStrdup((const xmlChar *) "-Infinity");
5306 break;
5307 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005308 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005309 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005310 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5311 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005312 } else {
5313 /* could be improved */
5314 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005315 xmlXPathFormatNumber(val, buf, 99);
5316 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005317 ret = xmlStrdup((const xmlChar *) buf);
5318 }
5319 }
5320 return(ret);
5321}
5322
5323/**
5324 * xmlXPathCastNodeToString:
5325 * @node: a node
5326 *
5327 * Converts a node to its string value.
5328 *
5329 * Returns a newly allocated string.
5330 */
5331xmlChar *
5332xmlXPathCastNodeToString (xmlNodePtr node) {
5333 return(xmlNodeGetContent(node));
5334}
5335
5336/**
5337 * xmlXPathCastNodeSetToString:
5338 * @ns: a node-set
5339 *
5340 * Converts a node-set to its string value.
5341 *
5342 * Returns a newly allocated string.
5343 */
5344xmlChar *
5345xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5346 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5347 return(xmlStrdup((const xmlChar *) ""));
5348
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005349 if (ns->nodeNr > 1)
5350 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005351 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5352}
5353
5354/**
5355 * xmlXPathCastToString:
5356 * @val: an XPath object
5357 *
5358 * Converts an existing object to its string() equivalent
5359 *
5360 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005361 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005362 * string object).
5363 */
5364xmlChar *
5365xmlXPathCastToString(xmlXPathObjectPtr val) {
5366 xmlChar *ret = NULL;
5367
5368 if (val == NULL)
5369 return(xmlStrdup((const xmlChar *) ""));
5370 switch (val->type) {
5371 case XPATH_UNDEFINED:
5372#ifdef DEBUG_EXPR
5373 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5374#endif
5375 ret = xmlStrdup((const xmlChar *) "");
5376 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005377 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005378 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005379 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5380 break;
5381 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005382 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005383 case XPATH_BOOLEAN:
5384 ret = xmlXPathCastBooleanToString(val->boolval);
5385 break;
5386 case XPATH_NUMBER: {
5387 ret = xmlXPathCastNumberToString(val->floatval);
5388 break;
5389 }
5390 case XPATH_USERS:
5391 case XPATH_POINT:
5392 case XPATH_RANGE:
5393 case XPATH_LOCATIONSET:
5394 TODO
5395 ret = xmlStrdup((const xmlChar *) "");
5396 break;
5397 }
5398 return(ret);
5399}
5400
5401/**
5402 * xmlXPathConvertString:
5403 * @val: an XPath object
5404 *
5405 * Converts an existing object to its string() equivalent
5406 *
5407 * Returns the new object, the old one is freed (or the operation
5408 * is done directly on @val)
5409 */
5410xmlXPathObjectPtr
5411xmlXPathConvertString(xmlXPathObjectPtr val) {
5412 xmlChar *res = NULL;
5413
5414 if (val == NULL)
5415 return(xmlXPathNewCString(""));
5416
5417 switch (val->type) {
5418 case XPATH_UNDEFINED:
5419#ifdef DEBUG_EXPR
5420 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5421#endif
5422 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005423 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005424 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005425 res = xmlXPathCastNodeSetToString(val->nodesetval);
5426 break;
5427 case XPATH_STRING:
5428 return(val);
5429 case XPATH_BOOLEAN:
5430 res = xmlXPathCastBooleanToString(val->boolval);
5431 break;
5432 case XPATH_NUMBER:
5433 res = xmlXPathCastNumberToString(val->floatval);
5434 break;
5435 case XPATH_USERS:
5436 case XPATH_POINT:
5437 case XPATH_RANGE:
5438 case XPATH_LOCATIONSET:
5439 TODO;
5440 break;
5441 }
5442 xmlXPathFreeObject(val);
5443 if (res == NULL)
5444 return(xmlXPathNewCString(""));
5445 return(xmlXPathWrapString(res));
5446}
5447
5448/**
5449 * xmlXPathCastBooleanToNumber:
5450 * @val: a boolean
5451 *
5452 * Converts a boolean to its number value
5453 *
5454 * Returns the number value
5455 */
5456double
5457xmlXPathCastBooleanToNumber(int val) {
5458 if (val)
5459 return(1.0);
5460 return(0.0);
5461}
5462
5463/**
5464 * xmlXPathCastStringToNumber:
5465 * @val: a string
5466 *
5467 * Converts a string to its number value
5468 *
5469 * Returns the number value
5470 */
5471double
5472xmlXPathCastStringToNumber(const xmlChar * val) {
5473 return(xmlXPathStringEvalNumber(val));
5474}
5475
5476/**
5477 * xmlXPathCastNodeToNumber:
5478 * @node: a node
5479 *
5480 * Converts a node to its number value
5481 *
5482 * Returns the number value
5483 */
5484double
5485xmlXPathCastNodeToNumber (xmlNodePtr node) {
5486 xmlChar *strval;
5487 double ret;
5488
5489 if (node == NULL)
5490 return(xmlXPathNAN);
5491 strval = xmlXPathCastNodeToString(node);
5492 if (strval == NULL)
5493 return(xmlXPathNAN);
5494 ret = xmlXPathCastStringToNumber(strval);
5495 xmlFree(strval);
5496
5497 return(ret);
5498}
5499
5500/**
5501 * xmlXPathCastNodeSetToNumber:
5502 * @ns: a node-set
5503 *
5504 * Converts a node-set to its number value
5505 *
5506 * Returns the number value
5507 */
5508double
5509xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5510 xmlChar *str;
5511 double ret;
5512
5513 if (ns == NULL)
5514 return(xmlXPathNAN);
5515 str = xmlXPathCastNodeSetToString(ns);
5516 ret = xmlXPathCastStringToNumber(str);
5517 xmlFree(str);
5518 return(ret);
5519}
5520
5521/**
5522 * xmlXPathCastToNumber:
5523 * @val: an XPath object
5524 *
5525 * Converts an XPath object to its number value
5526 *
5527 * Returns the number value
5528 */
5529double
5530xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5531 double ret = 0.0;
5532
5533 if (val == NULL)
5534 return(xmlXPathNAN);
5535 switch (val->type) {
5536 case XPATH_UNDEFINED:
5537#ifdef DEGUB_EXPR
5538 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5539#endif
5540 ret = xmlXPathNAN;
5541 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005542 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005543 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005544 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5545 break;
5546 case XPATH_STRING:
5547 ret = xmlXPathCastStringToNumber(val->stringval);
5548 break;
5549 case XPATH_NUMBER:
5550 ret = val->floatval;
5551 break;
5552 case XPATH_BOOLEAN:
5553 ret = xmlXPathCastBooleanToNumber(val->boolval);
5554 break;
5555 case XPATH_USERS:
5556 case XPATH_POINT:
5557 case XPATH_RANGE:
5558 case XPATH_LOCATIONSET:
5559 TODO;
5560 ret = xmlXPathNAN;
5561 break;
5562 }
5563 return(ret);
5564}
5565
5566/**
5567 * xmlXPathConvertNumber:
5568 * @val: an XPath object
5569 *
5570 * Converts an existing object to its number() equivalent
5571 *
5572 * Returns the new object, the old one is freed (or the operation
5573 * is done directly on @val)
5574 */
5575xmlXPathObjectPtr
5576xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5577 xmlXPathObjectPtr ret;
5578
5579 if (val == NULL)
5580 return(xmlXPathNewFloat(0.0));
5581 if (val->type == XPATH_NUMBER)
5582 return(val);
5583 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5584 xmlXPathFreeObject(val);
5585 return(ret);
5586}
5587
5588/**
5589 * xmlXPathCastNumberToBoolean:
5590 * @val: a number
5591 *
5592 * Converts a number to its boolean value
5593 *
5594 * Returns the boolean value
5595 */
5596int
5597xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005598 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005599 return(0);
5600 return(1);
5601}
5602
5603/**
5604 * xmlXPathCastStringToBoolean:
5605 * @val: a string
5606 *
5607 * Converts a string to its boolean value
5608 *
5609 * Returns the boolean value
5610 */
5611int
5612xmlXPathCastStringToBoolean (const xmlChar *val) {
5613 if ((val == NULL) || (xmlStrlen(val) == 0))
5614 return(0);
5615 return(1);
5616}
5617
5618/**
5619 * xmlXPathCastNodeSetToBoolean:
5620 * @ns: a node-set
5621 *
5622 * Converts a node-set to its boolean value
5623 *
5624 * Returns the boolean value
5625 */
5626int
5627xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5628 if ((ns == NULL) || (ns->nodeNr == 0))
5629 return(0);
5630 return(1);
5631}
5632
5633/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005634 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005635 * @val: an XPath object
5636 *
5637 * Converts an XPath object to its boolean value
5638 *
5639 * Returns the boolean value
5640 */
5641int
5642xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5643 int ret = 0;
5644
5645 if (val == NULL)
5646 return(0);
5647 switch (val->type) {
5648 case XPATH_UNDEFINED:
5649#ifdef DEBUG_EXPR
5650 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5651#endif
5652 ret = 0;
5653 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005654 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005655 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005656 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5657 break;
5658 case XPATH_STRING:
5659 ret = xmlXPathCastStringToBoolean(val->stringval);
5660 break;
5661 case XPATH_NUMBER:
5662 ret = xmlXPathCastNumberToBoolean(val->floatval);
5663 break;
5664 case XPATH_BOOLEAN:
5665 ret = val->boolval;
5666 break;
5667 case XPATH_USERS:
5668 case XPATH_POINT:
5669 case XPATH_RANGE:
5670 case XPATH_LOCATIONSET:
5671 TODO;
5672 ret = 0;
5673 break;
5674 }
5675 return(ret);
5676}
5677
5678
5679/**
5680 * xmlXPathConvertBoolean:
5681 * @val: an XPath object
5682 *
5683 * Converts an existing object to its boolean() equivalent
5684 *
5685 * Returns the new object, the old one is freed (or the operation
5686 * is done directly on @val)
5687 */
5688xmlXPathObjectPtr
5689xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5690 xmlXPathObjectPtr ret;
5691
5692 if (val == NULL)
5693 return(xmlXPathNewBoolean(0));
5694 if (val->type == XPATH_BOOLEAN)
5695 return(val);
5696 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5697 xmlXPathFreeObject(val);
5698 return(ret);
5699}
5700
Owen Taylor3473f882001-02-23 17:55:21 +00005701/************************************************************************
5702 * *
5703 * Routines to handle XPath contexts *
5704 * *
5705 ************************************************************************/
5706
5707/**
5708 * xmlXPathNewContext:
5709 * @doc: the XML document
5710 *
5711 * Create a new xmlXPathContext
5712 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005713 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005714 */
5715xmlXPathContextPtr
5716xmlXPathNewContext(xmlDocPtr doc) {
5717 xmlXPathContextPtr ret;
5718
5719 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5720 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005721 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005722 return(NULL);
5723 }
5724 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5725 ret->doc = doc;
5726 ret->node = NULL;
5727
5728 ret->varHash = NULL;
5729
5730 ret->nb_types = 0;
5731 ret->max_types = 0;
5732 ret->types = NULL;
5733
5734 ret->funcHash = xmlHashCreate(0);
5735
5736 ret->nb_axis = 0;
5737 ret->max_axis = 0;
5738 ret->axis = NULL;
5739
5740 ret->nsHash = NULL;
5741 ret->user = NULL;
5742
5743 ret->contextSize = -1;
5744 ret->proximityPosition = -1;
5745
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005746#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005747 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005748 xmlXPathFreeContext(ret);
5749 return(NULL);
5750 }
5751#endif
5752
5753 xmlXPathRegisterAllFunctions(ret);
5754
Owen Taylor3473f882001-02-23 17:55:21 +00005755 return(ret);
5756}
5757
5758/**
5759 * xmlXPathFreeContext:
5760 * @ctxt: the context to free
5761 *
5762 * Free up an xmlXPathContext
5763 */
5764void
5765xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005766 if (ctxt == NULL) return;
5767
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005768 if (ctxt->cache != NULL)
5769 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00005770 xmlXPathRegisteredNsCleanup(ctxt);
5771 xmlXPathRegisteredFuncsCleanup(ctxt);
5772 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005773 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00005774 xmlFree(ctxt);
5775}
5776
5777/************************************************************************
5778 * *
5779 * Routines to handle XPath parser contexts *
5780 * *
5781 ************************************************************************/
5782
5783#define CHECK_CTXT(ctxt) \
5784 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00005785 __xmlRaiseError(NULL, NULL, NULL, \
5786 NULL, NULL, XML_FROM_XPATH, \
5787 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5788 __FILE__, __LINE__, \
5789 NULL, NULL, NULL, 0, 0, \
5790 "NULL context pointer\n"); \
5791 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00005792 } \
5793
5794
5795#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00005796 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
5797 (ctxt->doc->children == NULL)) { \
5798 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00005799 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00005800 }
Owen Taylor3473f882001-02-23 17:55:21 +00005801
5802
5803/**
5804 * xmlXPathNewParserContext:
5805 * @str: the XPath expression
5806 * @ctxt: the XPath context
5807 *
5808 * Create a new xmlXPathParserContext
5809 *
5810 * Returns the xmlXPathParserContext just allocated.
5811 */
5812xmlXPathParserContextPtr
5813xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5814 xmlXPathParserContextPtr ret;
5815
5816 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5817 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005818 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005819 return(NULL);
5820 }
5821 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5822 ret->cur = ret->base = str;
5823 ret->context = ctxt;
5824
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005825 ret->comp = xmlXPathNewCompExpr();
5826 if (ret->comp == NULL) {
5827 xmlFree(ret->valueTab);
5828 xmlFree(ret);
5829 return(NULL);
5830 }
Daniel Veillard4773df22004-01-23 13:15:13 +00005831 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5832 ret->comp->dict = ctxt->dict;
5833 xmlDictReference(ret->comp->dict);
5834 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005835
5836 return(ret);
5837}
5838
5839/**
5840 * xmlXPathCompParserContext:
5841 * @comp: the XPath compiled expression
5842 * @ctxt: the XPath context
5843 *
5844 * Create a new xmlXPathParserContext when processing a compiled expression
5845 *
5846 * Returns the xmlXPathParserContext just allocated.
5847 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005848static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005849xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5850 xmlXPathParserContextPtr ret;
5851
5852 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5853 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005854 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005855 return(NULL);
5856 }
5857 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5858
Owen Taylor3473f882001-02-23 17:55:21 +00005859 /* Allocate the value stack */
5860 ret->valueTab = (xmlXPathObjectPtr *)
5861 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005862 if (ret->valueTab == NULL) {
5863 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005864 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005865 return(NULL);
5866 }
Owen Taylor3473f882001-02-23 17:55:21 +00005867 ret->valueNr = 0;
5868 ret->valueMax = 10;
5869 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005870
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005871 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005872 ret->comp = comp;
5873
Owen Taylor3473f882001-02-23 17:55:21 +00005874 return(ret);
5875}
5876
5877/**
5878 * xmlXPathFreeParserContext:
5879 * @ctxt: the context to free
5880 *
5881 * Free up an xmlXPathParserContext
5882 */
5883void
5884xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5885 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005886 xmlFree(ctxt->valueTab);
5887 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00005888 if (ctxt->comp != NULL) {
5889#ifdef XPATH_STREAMING
5890 if (ctxt->comp->stream != NULL) {
5891 xmlFreePatternList(ctxt->comp->stream);
5892 ctxt->comp->stream = NULL;
5893 }
5894#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005895 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00005896 }
Owen Taylor3473f882001-02-23 17:55:21 +00005897 xmlFree(ctxt);
5898}
5899
5900/************************************************************************
5901 * *
5902 * The implicit core function library *
5903 * *
5904 ************************************************************************/
5905
Owen Taylor3473f882001-02-23 17:55:21 +00005906/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005907 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00005908 * @node: a node pointer
5909 *
5910 * Function computing the beginning of the string value of the node,
5911 * used to speed up comparisons
5912 *
5913 * Returns an int usable as a hash
5914 */
5915static unsigned int
5916xmlXPathNodeValHash(xmlNodePtr node) {
5917 int len = 2;
5918 const xmlChar * string = NULL;
5919 xmlNodePtr tmp = NULL;
5920 unsigned int ret = 0;
5921
5922 if (node == NULL)
5923 return(0);
5924
Daniel Veillard9adc0462003-03-24 18:39:54 +00005925 if (node->type == XML_DOCUMENT_NODE) {
5926 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5927 if (tmp == NULL)
5928 node = node->children;
5929 else
5930 node = tmp;
5931
5932 if (node == NULL)
5933 return(0);
5934 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005935
5936 switch (node->type) {
5937 case XML_COMMENT_NODE:
5938 case XML_PI_NODE:
5939 case XML_CDATA_SECTION_NODE:
5940 case XML_TEXT_NODE:
5941 string = node->content;
5942 if (string == NULL)
5943 return(0);
5944 if (string[0] == 0)
5945 return(0);
5946 return(((unsigned int) string[0]) +
5947 (((unsigned int) string[1]) << 8));
5948 case XML_NAMESPACE_DECL:
5949 string = ((xmlNsPtr)node)->href;
5950 if (string == NULL)
5951 return(0);
5952 if (string[0] == 0)
5953 return(0);
5954 return(((unsigned int) string[0]) +
5955 (((unsigned int) string[1]) << 8));
5956 case XML_ATTRIBUTE_NODE:
5957 tmp = ((xmlAttrPtr) node)->children;
5958 break;
5959 case XML_ELEMENT_NODE:
5960 tmp = node->children;
5961 break;
5962 default:
5963 return(0);
5964 }
5965 while (tmp != NULL) {
5966 switch (tmp->type) {
5967 case XML_COMMENT_NODE:
5968 case XML_PI_NODE:
5969 case XML_CDATA_SECTION_NODE:
5970 case XML_TEXT_NODE:
5971 string = tmp->content;
5972 break;
5973 case XML_NAMESPACE_DECL:
5974 string = ((xmlNsPtr)tmp)->href;
5975 break;
5976 default:
5977 break;
5978 }
5979 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005980 if (len == 1) {
5981 return(ret + (((unsigned int) string[0]) << 8));
5982 }
5983 if (string[1] == 0) {
5984 len = 1;
5985 ret = (unsigned int) string[0];
5986 } else {
5987 return(((unsigned int) string[0]) +
5988 (((unsigned int) string[1]) << 8));
5989 }
5990 }
5991 /*
5992 * Skip to next node
5993 */
5994 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
5995 if (tmp->children->type != XML_ENTITY_DECL) {
5996 tmp = tmp->children;
5997 continue;
5998 }
5999 }
6000 if (tmp == node)
6001 break;
6002
6003 if (tmp->next != NULL) {
6004 tmp = tmp->next;
6005 continue;
6006 }
6007
6008 do {
6009 tmp = tmp->parent;
6010 if (tmp == NULL)
6011 break;
6012 if (tmp == node) {
6013 tmp = NULL;
6014 break;
6015 }
6016 if (tmp->next != NULL) {
6017 tmp = tmp->next;
6018 break;
6019 }
6020 } while (tmp != NULL);
6021 }
6022 return(ret);
6023}
6024
6025/**
6026 * xmlXPathStringHash:
6027 * @string: a string
6028 *
6029 * Function computing the beginning of the string value of the node,
6030 * used to speed up comparisons
6031 *
6032 * Returns an int usable as a hash
6033 */
6034static unsigned int
6035xmlXPathStringHash(const xmlChar * string) {
6036 if (string == NULL)
6037 return((unsigned int) 0);
6038 if (string[0] == 0)
6039 return(0);
6040 return(((unsigned int) string[0]) +
6041 (((unsigned int) string[1]) << 8));
6042}
6043
6044/**
Owen Taylor3473f882001-02-23 17:55:21 +00006045 * xmlXPathCompareNodeSetFloat:
6046 * @ctxt: the XPath Parser context
6047 * @inf: less than (1) or greater than (0)
6048 * @strict: is the comparison strict
6049 * @arg: the node set
6050 * @f: the value
6051 *
6052 * Implement the compare operation between a nodeset and a number
6053 * @ns < @val (1, 1, ...
6054 * @ns <= @val (1, 0, ...
6055 * @ns > @val (0, 1, ...
6056 * @ns >= @val (0, 0, ...
6057 *
6058 * If one object to be compared is a node-set and the other is a number,
6059 * then the comparison will be true if and only if there is a node in the
6060 * node-set such that the result of performing the comparison on the number
6061 * to be compared and on the result of converting the string-value of that
6062 * node to a number using the number function is true.
6063 *
6064 * Returns 0 or 1 depending on the results of the test.
6065 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006066static int
Owen Taylor3473f882001-02-23 17:55:21 +00006067xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6068 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6069 int i, ret = 0;
6070 xmlNodeSetPtr ns;
6071 xmlChar *str2;
6072
6073 if ((f == NULL) || (arg == NULL) ||
6074 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006075 xmlXPathReleaseObject(ctxt->context, arg);
6076 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006077 return(0);
6078 }
6079 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006080 if (ns != NULL) {
6081 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006082 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006083 if (str2 != NULL) {
6084 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006085 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006086 xmlFree(str2);
6087 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006088 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006089 ret = xmlXPathCompareValues(ctxt, inf, strict);
6090 if (ret)
6091 break;
6092 }
6093 }
Owen Taylor3473f882001-02-23 17:55:21 +00006094 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006095 xmlXPathReleaseObject(ctxt->context, arg);
6096 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006097 return(ret);
6098}
6099
6100/**
6101 * xmlXPathCompareNodeSetString:
6102 * @ctxt: the XPath Parser context
6103 * @inf: less than (1) or greater than (0)
6104 * @strict: is the comparison strict
6105 * @arg: the node set
6106 * @s: the value
6107 *
6108 * Implement the compare operation between a nodeset and a string
6109 * @ns < @val (1, 1, ...
6110 * @ns <= @val (1, 0, ...
6111 * @ns > @val (0, 1, ...
6112 * @ns >= @val (0, 0, ...
6113 *
6114 * If one object to be compared is a node-set and the other is a string,
6115 * then the comparison will be true if and only if there is a node in
6116 * the node-set such that the result of performing the comparison on the
6117 * string-value of the node and the other string is true.
6118 *
6119 * Returns 0 or 1 depending on the results of the test.
6120 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006121static int
Owen Taylor3473f882001-02-23 17:55:21 +00006122xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6123 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6124 int i, ret = 0;
6125 xmlNodeSetPtr ns;
6126 xmlChar *str2;
6127
6128 if ((s == NULL) || (arg == NULL) ||
6129 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006130 xmlXPathReleaseObject(ctxt->context, arg);
6131 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006132 return(0);
6133 }
6134 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006135 if (ns != NULL) {
6136 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006137 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006138 if (str2 != NULL) {
6139 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006140 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006141 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006142 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006143 ret = xmlXPathCompareValues(ctxt, inf, strict);
6144 if (ret)
6145 break;
6146 }
6147 }
Owen Taylor3473f882001-02-23 17:55:21 +00006148 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006149 xmlXPathReleaseObject(ctxt->context, arg);
6150 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006151 return(ret);
6152}
6153
6154/**
6155 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006156 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006157 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006158 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006159 * @arg2: the second node set object
6160 *
6161 * Implement the compare operation on nodesets:
6162 *
6163 * If both objects to be compared are node-sets, then the comparison
6164 * will be true if and only if there is a node in the first node-set
6165 * and a node in the second node-set such that the result of performing
6166 * the comparison on the string-values of the two nodes is true.
6167 * ....
6168 * When neither object to be compared is a node-set and the operator
6169 * is <=, <, >= or >, then the objects are compared by converting both
6170 * objects to numbers and comparing the numbers according to IEEE 754.
6171 * ....
6172 * The number function converts its argument to a number as follows:
6173 * - a string that consists of optional whitespace followed by an
6174 * optional minus sign followed by a Number followed by whitespace
6175 * is converted to the IEEE 754 number that is nearest (according
6176 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6177 * represented by the string; any other string is converted to NaN
6178 *
6179 * Conclusion all nodes need to be converted first to their string value
6180 * and then the comparison must be done when possible
6181 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006182static int
6183xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006184 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6185 int i, j, init = 0;
6186 double val1;
6187 double *values2;
6188 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006189 xmlNodeSetPtr ns1;
6190 xmlNodeSetPtr ns2;
6191
6192 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006193 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6194 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006195 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006196 }
Owen Taylor3473f882001-02-23 17:55:21 +00006197 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006198 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6199 xmlXPathFreeObject(arg1);
6200 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006201 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006202 }
Owen Taylor3473f882001-02-23 17:55:21 +00006203
6204 ns1 = arg1->nodesetval;
6205 ns2 = arg2->nodesetval;
6206
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006207 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006208 xmlXPathFreeObject(arg1);
6209 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006210 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006211 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006212 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006213 xmlXPathFreeObject(arg1);
6214 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006215 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006216 }
Owen Taylor3473f882001-02-23 17:55:21 +00006217
6218 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6219 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006220 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006221 xmlXPathFreeObject(arg1);
6222 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006223 return(0);
6224 }
6225 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006226 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006227 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006228 continue;
6229 for (j = 0;j < ns2->nodeNr;j++) {
6230 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006231 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006232 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006233 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006234 continue;
6235 if (inf && strict)
6236 ret = (val1 < values2[j]);
6237 else if (inf && !strict)
6238 ret = (val1 <= values2[j]);
6239 else if (!inf && strict)
6240 ret = (val1 > values2[j]);
6241 else if (!inf && !strict)
6242 ret = (val1 >= values2[j]);
6243 if (ret)
6244 break;
6245 }
6246 if (ret)
6247 break;
6248 init = 1;
6249 }
6250 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006251 xmlXPathFreeObject(arg1);
6252 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006253 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006254}
6255
6256/**
6257 * xmlXPathCompareNodeSetValue:
6258 * @ctxt: the XPath Parser context
6259 * @inf: less than (1) or greater than (0)
6260 * @strict: is the comparison strict
6261 * @arg: the node set
6262 * @val: the value
6263 *
6264 * Implement the compare operation between a nodeset and a value
6265 * @ns < @val (1, 1, ...
6266 * @ns <= @val (1, 0, ...
6267 * @ns > @val (0, 1, ...
6268 * @ns >= @val (0, 0, ...
6269 *
6270 * If one object to be compared is a node-set and the other is a boolean,
6271 * then the comparison will be true if and only if the result of performing
6272 * the comparison on the boolean and on the result of converting
6273 * the node-set to a boolean using the boolean function is true.
6274 *
6275 * Returns 0 or 1 depending on the results of the test.
6276 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006277static int
Owen Taylor3473f882001-02-23 17:55:21 +00006278xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6279 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6280 if ((val == NULL) || (arg == NULL) ||
6281 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6282 return(0);
6283
6284 switch(val->type) {
6285 case XPATH_NUMBER:
6286 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6287 case XPATH_NODESET:
6288 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006289 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006290 case XPATH_STRING:
6291 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6292 case XPATH_BOOLEAN:
6293 valuePush(ctxt, arg);
6294 xmlXPathBooleanFunction(ctxt, 1);
6295 valuePush(ctxt, val);
6296 return(xmlXPathCompareValues(ctxt, inf, strict));
6297 default:
6298 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006299 }
6300 return(0);
6301}
6302
6303/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006304 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006305 * @arg: the nodeset object argument
6306 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006307 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006308 *
6309 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6310 * If one object to be compared is a node-set and the other is a string,
6311 * then the comparison will be true if and only if there is a node in
6312 * the node-set such that the result of performing the comparison on the
6313 * string-value of the node and the other string is true.
6314 *
6315 * Returns 0 or 1 depending on the results of the test.
6316 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006317static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006318xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006319{
Owen Taylor3473f882001-02-23 17:55:21 +00006320 int i;
6321 xmlNodeSetPtr ns;
6322 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006323 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006324
6325 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006326 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6327 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006328 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006329 /*
6330 * A NULL nodeset compared with a string is always false
6331 * (since there is no node equal, and no node not equal)
6332 */
6333 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006334 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006335 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006336 for (i = 0; i < ns->nodeNr; i++) {
6337 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6338 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6339 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6340 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006341 if (neq)
6342 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006343 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006344 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6345 if (neq)
6346 continue;
6347 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006348 } else if (neq) {
6349 if (str2 != NULL)
6350 xmlFree(str2);
6351 return (1);
6352 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006353 if (str2 != NULL)
6354 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006355 } else if (neq)
6356 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006357 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006358 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006359}
6360
6361/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006362 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006363 * @arg: the nodeset object argument
6364 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006365 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006366 *
6367 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6368 * If one object to be compared is a node-set and the other is a number,
6369 * then the comparison will be true if and only if there is a node in
6370 * the node-set such that the result of performing the comparison on the
6371 * number to be compared and on the result of converting the string-value
6372 * of that node to a number using the number function is true.
6373 *
6374 * Returns 0 or 1 depending on the results of the test.
6375 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006376static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006377xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6378 xmlXPathObjectPtr arg, double f, int neq) {
6379 int i, ret=0;
6380 xmlNodeSetPtr ns;
6381 xmlChar *str2;
6382 xmlXPathObjectPtr val;
6383 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006384
6385 if ((arg == NULL) ||
6386 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6387 return(0);
6388
William M. Brack0c022ad2002-07-12 00:56:01 +00006389 ns = arg->nodesetval;
6390 if (ns != NULL) {
6391 for (i=0;i<ns->nodeNr;i++) {
6392 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6393 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006394 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006395 xmlFree(str2);
6396 xmlXPathNumberFunction(ctxt, 1);
6397 val = valuePop(ctxt);
6398 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006399 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006400 if (!xmlXPathIsNaN(v)) {
6401 if ((!neq) && (v==f)) {
6402 ret = 1;
6403 break;
6404 } else if ((neq) && (v!=f)) {
6405 ret = 1;
6406 break;
6407 }
William M. Brack32f0f712005-07-14 07:00:33 +00006408 } else { /* NaN is unequal to any value */
6409 if (neq)
6410 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006411 }
6412 }
6413 }
6414 }
6415
6416 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006417}
6418
6419
6420/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006421 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006422 * @arg1: first nodeset object argument
6423 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006424 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006425 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006426 * Implement the equal / not equal operation on XPath nodesets:
6427 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006428 * If both objects to be compared are node-sets, then the comparison
6429 * will be true if and only if there is a node in the first node-set and
6430 * a node in the second node-set such that the result of performing the
6431 * comparison on the string-values of the two nodes is true.
6432 *
6433 * (needless to say, this is a costly operation)
6434 *
6435 * Returns 0 or 1 depending on the results of the test.
6436 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006437static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006438xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006439 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006440 unsigned int *hashs1;
6441 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006442 xmlChar **values1;
6443 xmlChar **values2;
6444 int ret = 0;
6445 xmlNodeSetPtr ns1;
6446 xmlNodeSetPtr ns2;
6447
6448 if ((arg1 == NULL) ||
6449 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6450 return(0);
6451 if ((arg2 == NULL) ||
6452 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6453 return(0);
6454
6455 ns1 = arg1->nodesetval;
6456 ns2 = arg2->nodesetval;
6457
Daniel Veillard911f49a2001-04-07 15:39:35 +00006458 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006459 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006460 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006461 return(0);
6462
6463 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006464 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006465 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006466 if (neq == 0)
6467 for (i = 0;i < ns1->nodeNr;i++)
6468 for (j = 0;j < ns2->nodeNr;j++)
6469 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6470 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006471
6472 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006473 if (values1 == NULL) {
6474 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006475 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006476 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006477 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6478 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006479 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006480 xmlFree(values1);
6481 return(0);
6482 }
Owen Taylor3473f882001-02-23 17:55:21 +00006483 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6484 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6485 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006486 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006487 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006488 xmlFree(values1);
6489 return(0);
6490 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006491 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6492 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006493 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006494 xmlFree(hashs1);
6495 xmlFree(values1);
6496 xmlFree(values2);
6497 return(0);
6498 }
Owen Taylor3473f882001-02-23 17:55:21 +00006499 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6500 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006501 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006502 for (j = 0;j < ns2->nodeNr;j++) {
6503 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006504 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006505 if (hashs1[i] != hashs2[j]) {
6506 if (neq) {
6507 ret = 1;
6508 break;
6509 }
6510 }
6511 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006512 if (values1[i] == NULL)
6513 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6514 if (values2[j] == NULL)
6515 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006516 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006517 if (ret)
6518 break;
6519 }
Owen Taylor3473f882001-02-23 17:55:21 +00006520 }
6521 if (ret)
6522 break;
6523 }
6524 for (i = 0;i < ns1->nodeNr;i++)
6525 if (values1[i] != NULL)
6526 xmlFree(values1[i]);
6527 for (j = 0;j < ns2->nodeNr;j++)
6528 if (values2[j] != NULL)
6529 xmlFree(values2[j]);
6530 xmlFree(values1);
6531 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006532 xmlFree(hashs1);
6533 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006534 return(ret);
6535}
6536
William M. Brack0c022ad2002-07-12 00:56:01 +00006537static int
6538xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6539 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006540 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006541 /*
6542 *At this point we are assured neither arg1 nor arg2
6543 *is a nodeset, so we can just pick the appropriate routine.
6544 */
Owen Taylor3473f882001-02-23 17:55:21 +00006545 switch (arg1->type) {
6546 case XPATH_UNDEFINED:
6547#ifdef DEBUG_EXPR
6548 xmlGenericError(xmlGenericErrorContext,
6549 "Equal: undefined\n");
6550#endif
6551 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006552 case XPATH_BOOLEAN:
6553 switch (arg2->type) {
6554 case XPATH_UNDEFINED:
6555#ifdef DEBUG_EXPR
6556 xmlGenericError(xmlGenericErrorContext,
6557 "Equal: undefined\n");
6558#endif
6559 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006560 case XPATH_BOOLEAN:
6561#ifdef DEBUG_EXPR
6562 xmlGenericError(xmlGenericErrorContext,
6563 "Equal: %d boolean %d \n",
6564 arg1->boolval, arg2->boolval);
6565#endif
6566 ret = (arg1->boolval == arg2->boolval);
6567 break;
6568 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006569 ret = (arg1->boolval ==
6570 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006571 break;
6572 case XPATH_STRING:
6573 if ((arg2->stringval == NULL) ||
6574 (arg2->stringval[0] == 0)) ret = 0;
6575 else
6576 ret = 1;
6577 ret = (arg1->boolval == ret);
6578 break;
6579 case XPATH_USERS:
6580 case XPATH_POINT:
6581 case XPATH_RANGE:
6582 case XPATH_LOCATIONSET:
6583 TODO
6584 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006585 case XPATH_NODESET:
6586 case XPATH_XSLT_TREE:
6587 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006588 }
6589 break;
6590 case XPATH_NUMBER:
6591 switch (arg2->type) {
6592 case XPATH_UNDEFINED:
6593#ifdef DEBUG_EXPR
6594 xmlGenericError(xmlGenericErrorContext,
6595 "Equal: undefined\n");
6596#endif
6597 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006598 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006599 ret = (arg2->boolval==
6600 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006601 break;
6602 case XPATH_STRING:
6603 valuePush(ctxt, arg2);
6604 xmlXPathNumberFunction(ctxt, 1);
6605 arg2 = valuePop(ctxt);
6606 /* no break on purpose */
6607 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006608 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006609 if (xmlXPathIsNaN(arg1->floatval) ||
6610 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006611 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006612 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6613 if (xmlXPathIsInf(arg2->floatval) == 1)
6614 ret = 1;
6615 else
6616 ret = 0;
6617 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6618 if (xmlXPathIsInf(arg2->floatval) == -1)
6619 ret = 1;
6620 else
6621 ret = 0;
6622 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6623 if (xmlXPathIsInf(arg1->floatval) == 1)
6624 ret = 1;
6625 else
6626 ret = 0;
6627 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6628 if (xmlXPathIsInf(arg1->floatval) == -1)
6629 ret = 1;
6630 else
6631 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006632 } else {
6633 ret = (arg1->floatval == arg2->floatval);
6634 }
Owen Taylor3473f882001-02-23 17:55:21 +00006635 break;
6636 case XPATH_USERS:
6637 case XPATH_POINT:
6638 case XPATH_RANGE:
6639 case XPATH_LOCATIONSET:
6640 TODO
6641 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006642 case XPATH_NODESET:
6643 case XPATH_XSLT_TREE:
6644 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006645 }
6646 break;
6647 case XPATH_STRING:
6648 switch (arg2->type) {
6649 case XPATH_UNDEFINED:
6650#ifdef DEBUG_EXPR
6651 xmlGenericError(xmlGenericErrorContext,
6652 "Equal: undefined\n");
6653#endif
6654 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006655 case XPATH_BOOLEAN:
6656 if ((arg1->stringval == NULL) ||
6657 (arg1->stringval[0] == 0)) ret = 0;
6658 else
6659 ret = 1;
6660 ret = (arg2->boolval == ret);
6661 break;
6662 case XPATH_STRING:
6663 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6664 break;
6665 case XPATH_NUMBER:
6666 valuePush(ctxt, arg1);
6667 xmlXPathNumberFunction(ctxt, 1);
6668 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006669 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006670 if (xmlXPathIsNaN(arg1->floatval) ||
6671 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006672 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006673 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6674 if (xmlXPathIsInf(arg2->floatval) == 1)
6675 ret = 1;
6676 else
6677 ret = 0;
6678 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6679 if (xmlXPathIsInf(arg2->floatval) == -1)
6680 ret = 1;
6681 else
6682 ret = 0;
6683 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6684 if (xmlXPathIsInf(arg1->floatval) == 1)
6685 ret = 1;
6686 else
6687 ret = 0;
6688 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6689 if (xmlXPathIsInf(arg1->floatval) == -1)
6690 ret = 1;
6691 else
6692 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006693 } else {
6694 ret = (arg1->floatval == arg2->floatval);
6695 }
Owen Taylor3473f882001-02-23 17:55:21 +00006696 break;
6697 case XPATH_USERS:
6698 case XPATH_POINT:
6699 case XPATH_RANGE:
6700 case XPATH_LOCATIONSET:
6701 TODO
6702 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006703 case XPATH_NODESET:
6704 case XPATH_XSLT_TREE:
6705 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006706 }
6707 break;
6708 case XPATH_USERS:
6709 case XPATH_POINT:
6710 case XPATH_RANGE:
6711 case XPATH_LOCATIONSET:
6712 TODO
6713 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006714 case XPATH_NODESET:
6715 case XPATH_XSLT_TREE:
6716 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006717 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006718 xmlXPathReleaseObject(ctxt->context, arg1);
6719 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006720 return(ret);
6721}
6722
William M. Brack0c022ad2002-07-12 00:56:01 +00006723/**
6724 * xmlXPathEqualValues:
6725 * @ctxt: the XPath Parser context
6726 *
6727 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6728 *
6729 * Returns 0 or 1 depending on the results of the test.
6730 */
6731int
6732xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6733 xmlXPathObjectPtr arg1, arg2, argtmp;
6734 int ret = 0;
6735
Daniel Veillard6128c012004-11-08 17:16:15 +00006736 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006737 arg2 = valuePop(ctxt);
6738 arg1 = valuePop(ctxt);
6739 if ((arg1 == NULL) || (arg2 == NULL)) {
6740 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006741 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006742 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006743 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006744 XP_ERROR0(XPATH_INVALID_OPERAND);
6745 }
6746
6747 if (arg1 == arg2) {
6748#ifdef DEBUG_EXPR
6749 xmlGenericError(xmlGenericErrorContext,
6750 "Equal: by pointer\n");
6751#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00006752 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006753 return(1);
6754 }
6755
6756 /*
6757 *If either argument is a nodeset, it's a 'special case'
6758 */
6759 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6760 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6761 /*
6762 *Hack it to assure arg1 is the nodeset
6763 */
6764 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6765 argtmp = arg2;
6766 arg2 = arg1;
6767 arg1 = argtmp;
6768 }
6769 switch (arg2->type) {
6770 case XPATH_UNDEFINED:
6771#ifdef DEBUG_EXPR
6772 xmlGenericError(xmlGenericErrorContext,
6773 "Equal: undefined\n");
6774#endif
6775 break;
6776 case XPATH_NODESET:
6777 case XPATH_XSLT_TREE:
6778 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6779 break;
6780 case XPATH_BOOLEAN:
6781 if ((arg1->nodesetval == NULL) ||
6782 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6783 else
6784 ret = 1;
6785 ret = (ret == arg2->boolval);
6786 break;
6787 case XPATH_NUMBER:
6788 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6789 break;
6790 case XPATH_STRING:
6791 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6792 break;
6793 case XPATH_USERS:
6794 case XPATH_POINT:
6795 case XPATH_RANGE:
6796 case XPATH_LOCATIONSET:
6797 TODO
6798 break;
6799 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006800 xmlXPathReleaseObject(ctxt->context, arg1);
6801 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006802 return(ret);
6803 }
6804
6805 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6806}
6807
6808/**
6809 * xmlXPathNotEqualValues:
6810 * @ctxt: the XPath Parser context
6811 *
6812 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6813 *
6814 * Returns 0 or 1 depending on the results of the test.
6815 */
6816int
6817xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6818 xmlXPathObjectPtr arg1, arg2, argtmp;
6819 int ret = 0;
6820
Daniel Veillard6128c012004-11-08 17:16:15 +00006821 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006822 arg2 = valuePop(ctxt);
6823 arg1 = valuePop(ctxt);
6824 if ((arg1 == NULL) || (arg2 == NULL)) {
6825 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006826 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006827 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006828 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006829 XP_ERROR0(XPATH_INVALID_OPERAND);
6830 }
6831
6832 if (arg1 == arg2) {
6833#ifdef DEBUG_EXPR
6834 xmlGenericError(xmlGenericErrorContext,
6835 "NotEqual: by pointer\n");
6836#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006837 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006838 return(0);
6839 }
6840
6841 /*
6842 *If either argument is a nodeset, it's a 'special case'
6843 */
6844 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6845 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6846 /*
6847 *Hack it to assure arg1 is the nodeset
6848 */
6849 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6850 argtmp = arg2;
6851 arg2 = arg1;
6852 arg1 = argtmp;
6853 }
6854 switch (arg2->type) {
6855 case XPATH_UNDEFINED:
6856#ifdef DEBUG_EXPR
6857 xmlGenericError(xmlGenericErrorContext,
6858 "NotEqual: undefined\n");
6859#endif
6860 break;
6861 case XPATH_NODESET:
6862 case XPATH_XSLT_TREE:
6863 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6864 break;
6865 case XPATH_BOOLEAN:
6866 if ((arg1->nodesetval == NULL) ||
6867 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6868 else
6869 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00006870 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00006871 break;
6872 case XPATH_NUMBER:
6873 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6874 break;
6875 case XPATH_STRING:
6876 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6877 break;
6878 case XPATH_USERS:
6879 case XPATH_POINT:
6880 case XPATH_RANGE:
6881 case XPATH_LOCATIONSET:
6882 TODO
6883 break;
6884 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006885 xmlXPathReleaseObject(ctxt->context, arg1);
6886 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006887 return(ret);
6888 }
6889
6890 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6891}
Owen Taylor3473f882001-02-23 17:55:21 +00006892
6893/**
6894 * xmlXPathCompareValues:
6895 * @ctxt: the XPath Parser context
6896 * @inf: less than (1) or greater than (0)
6897 * @strict: is the comparison strict
6898 *
6899 * Implement the compare operation on XPath objects:
6900 * @arg1 < @arg2 (1, 1, ...
6901 * @arg1 <= @arg2 (1, 0, ...
6902 * @arg1 > @arg2 (0, 1, ...
6903 * @arg1 >= @arg2 (0, 0, ...
6904 *
6905 * When neither object to be compared is a node-set and the operator is
6906 * <=, <, >=, >, then the objects are compared by converted both objects
6907 * to numbers and comparing the numbers according to IEEE 754. The <
6908 * comparison will be true if and only if the first number is less than the
6909 * second number. The <= comparison will be true if and only if the first
6910 * number is less than or equal to the second number. The > comparison
6911 * will be true if and only if the first number is greater than the second
6912 * number. The >= comparison will be true if and only if the first number
6913 * is greater than or equal to the second number.
6914 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006915 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00006916 */
6917int
6918xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006919 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006920 xmlXPathObjectPtr arg1, arg2;
6921
Daniel Veillard6128c012004-11-08 17:16:15 +00006922 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006923 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006924 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00006925 if ((arg1 == NULL) || (arg2 == NULL)) {
6926 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006927 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006928 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006929 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006930 XP_ERROR0(XPATH_INVALID_OPERAND);
6931 }
6932
William M. Brack0c022ad2002-07-12 00:56:01 +00006933 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6934 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00006935 /*
6936 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6937 * are not freed from within this routine; they will be freed from the
6938 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6939 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006940 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6941 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006942 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006943 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00006944 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006945 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6946 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006947 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006948 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6949 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00006950 }
6951 }
6952 return(ret);
6953 }
6954
6955 if (arg1->type != XPATH_NUMBER) {
6956 valuePush(ctxt, arg1);
6957 xmlXPathNumberFunction(ctxt, 1);
6958 arg1 = valuePop(ctxt);
6959 }
6960 if (arg1->type != XPATH_NUMBER) {
6961 xmlXPathFreeObject(arg1);
6962 xmlXPathFreeObject(arg2);
6963 XP_ERROR0(XPATH_INVALID_OPERAND);
6964 }
6965 if (arg2->type != XPATH_NUMBER) {
6966 valuePush(ctxt, arg2);
6967 xmlXPathNumberFunction(ctxt, 1);
6968 arg2 = valuePop(ctxt);
6969 }
6970 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006971 xmlXPathReleaseObject(ctxt->context, arg1);
6972 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006973 XP_ERROR0(XPATH_INVALID_OPERAND);
6974 }
6975 /*
6976 * Add tests for infinity and nan
6977 * => feedback on 3.4 for Inf and NaN
6978 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006979 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00006980 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006981 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006982 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006983 arg1i=xmlXPathIsInf(arg1->floatval);
6984 arg2i=xmlXPathIsInf(arg2->floatval);
6985 if (inf && strict) {
6986 if ((arg1i == -1 && arg2i != -1) ||
6987 (arg2i == 1 && arg1i != 1)) {
6988 ret = 1;
6989 } else if (arg1i == 0 && arg2i == 0) {
6990 ret = (arg1->floatval < arg2->floatval);
6991 } else {
6992 ret = 0;
6993 }
6994 }
6995 else if (inf && !strict) {
6996 if (arg1i == -1 || arg2i == 1) {
6997 ret = 1;
6998 } else if (arg1i == 0 && arg2i == 0) {
6999 ret = (arg1->floatval <= arg2->floatval);
7000 } else {
7001 ret = 0;
7002 }
7003 }
7004 else if (!inf && strict) {
7005 if ((arg1i == 1 && arg2i != 1) ||
7006 (arg2i == -1 && arg1i != -1)) {
7007 ret = 1;
7008 } else if (arg1i == 0 && arg2i == 0) {
7009 ret = (arg1->floatval > arg2->floatval);
7010 } else {
7011 ret = 0;
7012 }
7013 }
7014 else if (!inf && !strict) {
7015 if (arg1i == 1 || arg2i == -1) {
7016 ret = 1;
7017 } else if (arg1i == 0 && arg2i == 0) {
7018 ret = (arg1->floatval >= arg2->floatval);
7019 } else {
7020 ret = 0;
7021 }
7022 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007023 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007024 xmlXPathReleaseObject(ctxt->context, arg1);
7025 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007026 return(ret);
7027}
7028
7029/**
7030 * xmlXPathValueFlipSign:
7031 * @ctxt: the XPath Parser context
7032 *
7033 * Implement the unary - operation on an XPath object
7034 * The numeric operators convert their operands to numbers as if
7035 * by calling the number function.
7036 */
7037void
7038xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007039 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007040 CAST_TO_NUMBER;
7041 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007042 if (xmlXPathIsNaN(ctxt->value->floatval))
7043 ctxt->value->floatval=xmlXPathNAN;
7044 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7045 ctxt->value->floatval=xmlXPathNINF;
7046 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7047 ctxt->value->floatval=xmlXPathPINF;
7048 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007049 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7050 ctxt->value->floatval = xmlXPathNZERO;
7051 else
7052 ctxt->value->floatval = 0;
7053 }
7054 else
7055 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007056}
7057
7058/**
7059 * xmlXPathAddValues:
7060 * @ctxt: the XPath Parser context
7061 *
7062 * Implement the add operation on XPath objects:
7063 * The numeric operators convert their operands to numbers as if
7064 * by calling the number function.
7065 */
7066void
7067xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7068 xmlXPathObjectPtr arg;
7069 double val;
7070
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007071 arg = valuePop(ctxt);
7072 if (arg == NULL)
7073 XP_ERROR(XPATH_INVALID_OPERAND);
7074 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007075 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007076 CAST_TO_NUMBER;
7077 CHECK_TYPE(XPATH_NUMBER);
7078 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007079}
7080
7081/**
7082 * xmlXPathSubValues:
7083 * @ctxt: the XPath Parser context
7084 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007085 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007086 * The numeric operators convert their operands to numbers as if
7087 * by calling the number function.
7088 */
7089void
7090xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7091 xmlXPathObjectPtr arg;
7092 double val;
7093
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007094 arg = valuePop(ctxt);
7095 if (arg == NULL)
7096 XP_ERROR(XPATH_INVALID_OPERAND);
7097 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007098 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007099 CAST_TO_NUMBER;
7100 CHECK_TYPE(XPATH_NUMBER);
7101 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007102}
7103
7104/**
7105 * xmlXPathMultValues:
7106 * @ctxt: the XPath Parser context
7107 *
7108 * Implement the multiply operation on XPath objects:
7109 * The numeric operators convert their operands to numbers as if
7110 * by calling the number function.
7111 */
7112void
7113xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7114 xmlXPathObjectPtr arg;
7115 double val;
7116
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007117 arg = valuePop(ctxt);
7118 if (arg == NULL)
7119 XP_ERROR(XPATH_INVALID_OPERAND);
7120 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007121 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007122 CAST_TO_NUMBER;
7123 CHECK_TYPE(XPATH_NUMBER);
7124 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007125}
7126
7127/**
7128 * xmlXPathDivValues:
7129 * @ctxt: the XPath Parser context
7130 *
7131 * Implement the div operation on XPath objects @arg1 / @arg2:
7132 * The numeric operators convert their operands to numbers as if
7133 * by calling the number function.
7134 */
7135void
7136xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7137 xmlXPathObjectPtr arg;
7138 double val;
7139
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007140 arg = valuePop(ctxt);
7141 if (arg == NULL)
7142 XP_ERROR(XPATH_INVALID_OPERAND);
7143 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007144 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007145 CAST_TO_NUMBER;
7146 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007147 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7148 ctxt->value->floatval = xmlXPathNAN;
7149 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007150 if (ctxt->value->floatval == 0)
7151 ctxt->value->floatval = xmlXPathNAN;
7152 else if (ctxt->value->floatval > 0)
7153 ctxt->value->floatval = xmlXPathNINF;
7154 else if (ctxt->value->floatval < 0)
7155 ctxt->value->floatval = xmlXPathPINF;
7156 }
7157 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007158 if (ctxt->value->floatval == 0)
7159 ctxt->value->floatval = xmlXPathNAN;
7160 else if (ctxt->value->floatval > 0)
7161 ctxt->value->floatval = xmlXPathPINF;
7162 else if (ctxt->value->floatval < 0)
7163 ctxt->value->floatval = xmlXPathNINF;
7164 } else
7165 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007166}
7167
7168/**
7169 * xmlXPathModValues:
7170 * @ctxt: the XPath Parser context
7171 *
7172 * Implement the mod operation on XPath objects: @arg1 / @arg2
7173 * The numeric operators convert their operands to numbers as if
7174 * by calling the number function.
7175 */
7176void
7177xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7178 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007179 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007180
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007181 arg = valuePop(ctxt);
7182 if (arg == NULL)
7183 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007184 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007185 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007186 CAST_TO_NUMBER;
7187 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007188 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007189 if (arg2 == 0)
7190 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007191 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007192 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007193 }
Owen Taylor3473f882001-02-23 17:55:21 +00007194}
7195
7196/************************************************************************
7197 * *
7198 * The traversal functions *
7199 * *
7200 ************************************************************************/
7201
Owen Taylor3473f882001-02-23 17:55:21 +00007202/*
7203 * A traversal function enumerates nodes along an axis.
7204 * Initially it must be called with NULL, and it indicates
7205 * termination on the axis by returning NULL.
7206 */
7207typedef xmlNodePtr (*xmlXPathTraversalFunction)
7208 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7209
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007210/*
7211 * xmlXPathTraversalFunctionExt:
7212 * A traversal function enumerates nodes along an axis.
7213 * Initially it must be called with NULL, and it indicates
7214 * termination on the axis by returning NULL.
7215 * The context node of the traversal is specified via @contextNode.
7216 */
7217typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7218 (xmlNodePtr cur, xmlNodePtr contextNode);
7219
7220
Owen Taylor3473f882001-02-23 17:55:21 +00007221/**
7222 * xmlXPathNextSelf:
7223 * @ctxt: the XPath Parser context
7224 * @cur: the current node in the traversal
7225 *
7226 * Traversal function for the "self" direction
7227 * The self axis contains just the context node itself
7228 *
7229 * Returns the next element following that axis
7230 */
7231xmlNodePtr
7232xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007233 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007234 if (cur == NULL)
7235 return(ctxt->context->node);
7236 return(NULL);
7237}
7238
7239/**
7240 * xmlXPathNextChild:
7241 * @ctxt: the XPath Parser context
7242 * @cur: the current node in the traversal
7243 *
7244 * Traversal function for the "child" direction
7245 * The child axis contains the children of the context node in document order.
7246 *
7247 * Returns the next element following that axis
7248 */
7249xmlNodePtr
7250xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007251 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007252 if (cur == NULL) {
7253 if (ctxt->context->node == NULL) return(NULL);
7254 switch (ctxt->context->node->type) {
7255 case XML_ELEMENT_NODE:
7256 case XML_TEXT_NODE:
7257 case XML_CDATA_SECTION_NODE:
7258 case XML_ENTITY_REF_NODE:
7259 case XML_ENTITY_NODE:
7260 case XML_PI_NODE:
7261 case XML_COMMENT_NODE:
7262 case XML_NOTATION_NODE:
7263 case XML_DTD_NODE:
7264 return(ctxt->context->node->children);
7265 case XML_DOCUMENT_NODE:
7266 case XML_DOCUMENT_TYPE_NODE:
7267 case XML_DOCUMENT_FRAG_NODE:
7268 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007269#ifdef LIBXML_DOCB_ENABLED
7270 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007271#endif
7272 return(((xmlDocPtr) ctxt->context->node)->children);
7273 case XML_ELEMENT_DECL:
7274 case XML_ATTRIBUTE_DECL:
7275 case XML_ENTITY_DECL:
7276 case XML_ATTRIBUTE_NODE:
7277 case XML_NAMESPACE_DECL:
7278 case XML_XINCLUDE_START:
7279 case XML_XINCLUDE_END:
7280 return(NULL);
7281 }
7282 return(NULL);
7283 }
7284 if ((cur->type == XML_DOCUMENT_NODE) ||
7285 (cur->type == XML_HTML_DOCUMENT_NODE))
7286 return(NULL);
7287 return(cur->next);
7288}
7289
7290/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007291 * xmlXPathNextChildElement:
7292 * @ctxt: the XPath Parser context
7293 * @cur: the current node in the traversal
7294 *
7295 * Traversal function for the "child" direction and nodes of type element.
7296 * The child axis contains the children of the context node in document order.
7297 *
7298 * Returns the next element following that axis
7299 */
7300static xmlNodePtr
7301xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7302 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7303 if (cur == NULL) {
7304 cur = ctxt->context->node;
7305 if (cur == NULL) return(NULL);
7306 /*
7307 * Get the first element child.
7308 */
7309 switch (cur->type) {
7310 case XML_ELEMENT_NODE:
7311 case XML_DOCUMENT_FRAG_NODE:
7312 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7313 case XML_ENTITY_NODE:
7314 cur = cur->children;
7315 if (cur != NULL) {
7316 if (cur->type == XML_ELEMENT_NODE)
7317 return(cur);
7318 do {
7319 cur = cur->next;
7320 } while ((cur != NULL) &&
7321 (cur->type != XML_ELEMENT_NODE));
7322 return(cur);
7323 }
7324 return(NULL);
7325 case XML_DOCUMENT_NODE:
7326 case XML_HTML_DOCUMENT_NODE:
7327#ifdef LIBXML_DOCB_ENABLED
7328 case XML_DOCB_DOCUMENT_NODE:
7329#endif
7330 return(xmlDocGetRootElement((xmlDocPtr) cur));
7331 default:
7332 return(NULL);
7333 }
7334 return(NULL);
7335 }
7336 /*
7337 * Get the next sibling element node.
7338 */
7339 switch (cur->type) {
7340 case XML_ELEMENT_NODE:
7341 case XML_TEXT_NODE:
7342 case XML_ENTITY_REF_NODE:
7343 case XML_ENTITY_NODE:
7344 case XML_CDATA_SECTION_NODE:
7345 case XML_PI_NODE:
7346 case XML_COMMENT_NODE:
7347 case XML_XINCLUDE_END:
7348 break;
7349 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7350 default:
7351 return(NULL);
7352 }
7353 if (cur->next != NULL) {
7354 if (cur->next->type == XML_ELEMENT_NODE)
7355 return(cur->next);
7356 cur = cur->next;
7357 do {
7358 cur = cur->next;
7359 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7360 return(cur);
7361 }
7362 return(NULL);
7363}
7364
7365/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007366 * xmlXPathNextDescendantOrSelfElemParent:
7367 * @ctxt: the XPath Parser context
7368 * @cur: the current node in the traversal
7369 *
7370 * Traversal function for the "descendant-or-self" axis.
7371 * Additionally it returns only nodes which can be parents of
7372 * element nodes.
7373 *
7374 *
7375 * Returns the next element following that axis
7376 */
7377static xmlNodePtr
7378xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7379 xmlNodePtr contextNode)
7380{
7381 if (cur == NULL) {
7382 if (contextNode == NULL)
7383 return(NULL);
7384 switch (contextNode->type) {
7385 case XML_ELEMENT_NODE:
7386 case XML_XINCLUDE_START:
7387 case XML_DOCUMENT_FRAG_NODE:
7388 case XML_DOCUMENT_NODE:
7389#ifdef LIBXML_DOCB_ENABLED
7390 case XML_DOCB_DOCUMENT_NODE:
7391#endif
7392 case XML_HTML_DOCUMENT_NODE:
7393 return(contextNode);
7394 default:
7395 return(NULL);
7396 }
7397 return(NULL);
7398 } else {
7399 xmlNodePtr start = cur;
7400
7401 while (cur != NULL) {
7402 switch (cur->type) {
7403 case XML_ELEMENT_NODE:
7404 /* TODO: OK to have XInclude here? */
7405 case XML_XINCLUDE_START:
7406 case XML_DOCUMENT_FRAG_NODE:
7407 if (cur != start)
7408 return(cur);
7409 if (cur->children != NULL) {
7410 cur = cur->children;
7411 continue;
7412 }
7413 break;
7414#ifdef LIBXML_DOCB_ENABLED
7415 /* Not sure if we need those here. */
7416 case XML_DOCUMENT_NODE:
7417 case XML_DOCB_DOCUMENT_NODE:
7418#endif
7419 case XML_HTML_DOCUMENT_NODE:
7420 if (cur != start)
7421 return(cur);
7422 return(xmlDocGetRootElement((xmlDocPtr) cur));
7423 default:
7424 break;
7425 }
7426
7427next_sibling:
7428 if ((cur == NULL) || (cur == contextNode))
7429 return(NULL);
7430 if (cur->next != NULL) {
7431 cur = cur->next;
7432 } else {
7433 cur = cur->parent;
7434 goto next_sibling;
7435 }
7436 }
7437 }
7438 return(NULL);
7439}
7440
7441/**
Owen Taylor3473f882001-02-23 17:55:21 +00007442 * xmlXPathNextDescendant:
7443 * @ctxt: the XPath Parser context
7444 * @cur: the current node in the traversal
7445 *
7446 * Traversal function for the "descendant" direction
7447 * the descendant axis contains the descendants of the context node in document
7448 * order; a descendant is a child or a child of a child and so on.
7449 *
7450 * Returns the next element following that axis
7451 */
7452xmlNodePtr
7453xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007454 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007455 if (cur == NULL) {
7456 if (ctxt->context->node == NULL)
7457 return(NULL);
7458 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7459 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7460 return(NULL);
7461
7462 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7463 return(ctxt->context->doc->children);
7464 return(ctxt->context->node->children);
7465 }
7466
Daniel Veillard567e1b42001-08-01 15:53:47 +00007467 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007468 /*
7469 * Do not descend on entities declarations
7470 */
7471 if (cur->children->type != XML_ENTITY_DECL) {
7472 cur = cur->children;
7473 /*
7474 * Skip DTDs
7475 */
7476 if (cur->type != XML_DTD_NODE)
7477 return(cur);
7478 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007479 }
7480
7481 if (cur == ctxt->context->node) return(NULL);
7482
Daniel Veillard68e9e742002-11-16 15:35:11 +00007483 while (cur->next != NULL) {
7484 cur = cur->next;
7485 if ((cur->type != XML_ENTITY_DECL) &&
7486 (cur->type != XML_DTD_NODE))
7487 return(cur);
7488 }
Owen Taylor3473f882001-02-23 17:55:21 +00007489
7490 do {
7491 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007492 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007493 if (cur == ctxt->context->node) return(NULL);
7494 if (cur->next != NULL) {
7495 cur = cur->next;
7496 return(cur);
7497 }
7498 } while (cur != NULL);
7499 return(cur);
7500}
7501
7502/**
7503 * xmlXPathNextDescendantOrSelf:
7504 * @ctxt: the XPath Parser context
7505 * @cur: the current node in the traversal
7506 *
7507 * Traversal function for the "descendant-or-self" direction
7508 * the descendant-or-self axis contains the context node and the descendants
7509 * of the context node in document order; thus the context node is the first
7510 * node on the axis, and the first child of the context node is the second node
7511 * on the axis
7512 *
7513 * Returns the next element following that axis
7514 */
7515xmlNodePtr
7516xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007517 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007518 if (cur == NULL) {
7519 if (ctxt->context->node == NULL)
7520 return(NULL);
7521 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7522 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7523 return(NULL);
7524 return(ctxt->context->node);
7525 }
7526
7527 return(xmlXPathNextDescendant(ctxt, cur));
7528}
7529
7530/**
7531 * xmlXPathNextParent:
7532 * @ctxt: the XPath Parser context
7533 * @cur: the current node in the traversal
7534 *
7535 * Traversal function for the "parent" direction
7536 * The parent axis contains the parent of the context node, if there is one.
7537 *
7538 * Returns the next element following that axis
7539 */
7540xmlNodePtr
7541xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007542 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007543 /*
7544 * the parent of an attribute or namespace node is the element
7545 * to which the attribute or namespace node is attached
7546 * Namespace handling !!!
7547 */
7548 if (cur == NULL) {
7549 if (ctxt->context->node == NULL) return(NULL);
7550 switch (ctxt->context->node->type) {
7551 case XML_ELEMENT_NODE:
7552 case XML_TEXT_NODE:
7553 case XML_CDATA_SECTION_NODE:
7554 case XML_ENTITY_REF_NODE:
7555 case XML_ENTITY_NODE:
7556 case XML_PI_NODE:
7557 case XML_COMMENT_NODE:
7558 case XML_NOTATION_NODE:
7559 case XML_DTD_NODE:
7560 case XML_ELEMENT_DECL:
7561 case XML_ATTRIBUTE_DECL:
7562 case XML_XINCLUDE_START:
7563 case XML_XINCLUDE_END:
7564 case XML_ENTITY_DECL:
7565 if (ctxt->context->node->parent == NULL)
7566 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007567 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007568 ((ctxt->context->node->parent->name[0] == ' ') ||
7569 (xmlStrEqual(ctxt->context->node->parent->name,
7570 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007571 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007572 return(ctxt->context->node->parent);
7573 case XML_ATTRIBUTE_NODE: {
7574 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7575
7576 return(att->parent);
7577 }
7578 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);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007586 case XML_NAMESPACE_DECL: {
7587 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7588
7589 if ((ns->next != NULL) &&
7590 (ns->next->type != XML_NAMESPACE_DECL))
7591 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007592 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007593 }
Owen Taylor3473f882001-02-23 17:55:21 +00007594 }
7595 }
7596 return(NULL);
7597}
7598
7599/**
7600 * xmlXPathNextAncestor:
7601 * @ctxt: the XPath Parser context
7602 * @cur: the current node in the traversal
7603 *
7604 * Traversal function for the "ancestor" direction
7605 * the ancestor axis contains the ancestors of the context node; the ancestors
7606 * of the context node consist of the parent of context node and the parent's
7607 * parent and so on; the nodes are ordered in reverse document order; thus the
7608 * parent is the first node on the axis, and the parent's parent is the second
7609 * node on the axis
7610 *
7611 * Returns the next element following that axis
7612 */
7613xmlNodePtr
7614xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007615 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007616 /*
7617 * the parent of an attribute or namespace node is the element
7618 * to which the attribute or namespace node is attached
7619 * !!!!!!!!!!!!!
7620 */
7621 if (cur == NULL) {
7622 if (ctxt->context->node == NULL) return(NULL);
7623 switch (ctxt->context->node->type) {
7624 case XML_ELEMENT_NODE:
7625 case XML_TEXT_NODE:
7626 case XML_CDATA_SECTION_NODE:
7627 case XML_ENTITY_REF_NODE:
7628 case XML_ENTITY_NODE:
7629 case XML_PI_NODE:
7630 case XML_COMMENT_NODE:
7631 case XML_DTD_NODE:
7632 case XML_ELEMENT_DECL:
7633 case XML_ATTRIBUTE_DECL:
7634 case XML_ENTITY_DECL:
7635 case XML_NOTATION_NODE:
7636 case XML_XINCLUDE_START:
7637 case XML_XINCLUDE_END:
7638 if (ctxt->context->node->parent == NULL)
7639 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007640 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007641 ((ctxt->context->node->parent->name[0] == ' ') ||
7642 (xmlStrEqual(ctxt->context->node->parent->name,
7643 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007644 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007645 return(ctxt->context->node->parent);
7646 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007647 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007648
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007649 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007650 }
7651 case XML_DOCUMENT_NODE:
7652 case XML_DOCUMENT_TYPE_NODE:
7653 case XML_DOCUMENT_FRAG_NODE:
7654 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007655#ifdef LIBXML_DOCB_ENABLED
7656 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007657#endif
7658 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007659 case XML_NAMESPACE_DECL: {
7660 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7661
7662 if ((ns->next != NULL) &&
7663 (ns->next->type != XML_NAMESPACE_DECL))
7664 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007665 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007666 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007667 }
Owen Taylor3473f882001-02-23 17:55:21 +00007668 }
7669 return(NULL);
7670 }
7671 if (cur == ctxt->context->doc->children)
7672 return((xmlNodePtr) ctxt->context->doc);
7673 if (cur == (xmlNodePtr) ctxt->context->doc)
7674 return(NULL);
7675 switch (cur->type) {
7676 case XML_ELEMENT_NODE:
7677 case XML_TEXT_NODE:
7678 case XML_CDATA_SECTION_NODE:
7679 case XML_ENTITY_REF_NODE:
7680 case XML_ENTITY_NODE:
7681 case XML_PI_NODE:
7682 case XML_COMMENT_NODE:
7683 case XML_NOTATION_NODE:
7684 case XML_DTD_NODE:
7685 case XML_ELEMENT_DECL:
7686 case XML_ATTRIBUTE_DECL:
7687 case XML_ENTITY_DECL:
7688 case XML_XINCLUDE_START:
7689 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007690 if (cur->parent == NULL)
7691 return(NULL);
7692 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007693 ((cur->parent->name[0] == ' ') ||
7694 (xmlStrEqual(cur->parent->name,
7695 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007696 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007697 return(cur->parent);
7698 case XML_ATTRIBUTE_NODE: {
7699 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7700
7701 return(att->parent);
7702 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007703 case XML_NAMESPACE_DECL: {
7704 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7705
7706 if ((ns->next != NULL) &&
7707 (ns->next->type != XML_NAMESPACE_DECL))
7708 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007709 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007710 return(NULL);
7711 }
Owen Taylor3473f882001-02-23 17:55:21 +00007712 case XML_DOCUMENT_NODE:
7713 case XML_DOCUMENT_TYPE_NODE:
7714 case XML_DOCUMENT_FRAG_NODE:
7715 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007716#ifdef LIBXML_DOCB_ENABLED
7717 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007718#endif
7719 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007720 }
7721 return(NULL);
7722}
7723
7724/**
7725 * xmlXPathNextAncestorOrSelf:
7726 * @ctxt: the XPath Parser context
7727 * @cur: the current node in the traversal
7728 *
7729 * Traversal function for the "ancestor-or-self" direction
7730 * he ancestor-or-self axis contains the context node and ancestors of
7731 * the context node in reverse document order; thus the context node is
7732 * the first node on the axis, and the context node's parent the second;
7733 * parent here is defined the same as with the parent axis.
7734 *
7735 * Returns the next element following that axis
7736 */
7737xmlNodePtr
7738xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007739 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007740 if (cur == NULL)
7741 return(ctxt->context->node);
7742 return(xmlXPathNextAncestor(ctxt, cur));
7743}
7744
7745/**
7746 * xmlXPathNextFollowingSibling:
7747 * @ctxt: the XPath Parser context
7748 * @cur: the current node in the traversal
7749 *
7750 * Traversal function for the "following-sibling" direction
7751 * The following-sibling axis contains the following siblings of the context
7752 * node in document order.
7753 *
7754 * Returns the next element following that axis
7755 */
7756xmlNodePtr
7757xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007758 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007759 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7760 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7761 return(NULL);
7762 if (cur == (xmlNodePtr) ctxt->context->doc)
7763 return(NULL);
7764 if (cur == NULL)
7765 return(ctxt->context->node->next);
7766 return(cur->next);
7767}
7768
7769/**
7770 * xmlXPathNextPrecedingSibling:
7771 * @ctxt: the XPath Parser context
7772 * @cur: the current node in the traversal
7773 *
7774 * Traversal function for the "preceding-sibling" direction
7775 * The preceding-sibling axis contains the preceding siblings of the context
7776 * node in reverse document order; the first preceding sibling is first on the
7777 * axis; the sibling preceding that node is the second on the axis and so on.
7778 *
7779 * Returns the next element following that axis
7780 */
7781xmlNodePtr
7782xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007783 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007784 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7785 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7786 return(NULL);
7787 if (cur == (xmlNodePtr) ctxt->context->doc)
7788 return(NULL);
7789 if (cur == NULL)
7790 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007791 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7792 cur = cur->prev;
7793 if (cur == NULL)
7794 return(ctxt->context->node->prev);
7795 }
Owen Taylor3473f882001-02-23 17:55:21 +00007796 return(cur->prev);
7797}
7798
7799/**
7800 * xmlXPathNextFollowing:
7801 * @ctxt: the XPath Parser context
7802 * @cur: the current node in the traversal
7803 *
7804 * Traversal function for the "following" direction
7805 * The following axis contains all nodes in the same document as the context
7806 * node that are after the context node in document order, excluding any
7807 * descendants and excluding attribute nodes and namespace nodes; the nodes
7808 * are ordered in document order
7809 *
7810 * Returns the next element following that axis
7811 */
7812xmlNodePtr
7813xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007814 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007815 if (cur != NULL && cur->children != NULL)
7816 return cur->children ;
7817 if (cur == NULL) cur = ctxt->context->node;
7818 if (cur == NULL) return(NULL) ; /* ERROR */
7819 if (cur->next != NULL) return(cur->next) ;
7820 do {
7821 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007822 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007823 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7824 if (cur->next != NULL) return(cur->next);
7825 } while (cur != NULL);
7826 return(cur);
7827}
7828
7829/*
7830 * xmlXPathIsAncestor:
7831 * @ancestor: the ancestor node
7832 * @node: the current node
7833 *
7834 * Check that @ancestor is a @node's ancestor
7835 *
7836 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7837 */
7838static int
7839xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7840 if ((ancestor == NULL) || (node == NULL)) return(0);
7841 /* nodes need to be in the same document */
7842 if (ancestor->doc != node->doc) return(0);
7843 /* avoid searching if ancestor or node is the root node */
7844 if (ancestor == (xmlNodePtr) node->doc) return(1);
7845 if (node == (xmlNodePtr) ancestor->doc) return(0);
7846 while (node->parent != NULL) {
7847 if (node->parent == ancestor)
7848 return(1);
7849 node = node->parent;
7850 }
7851 return(0);
7852}
7853
7854/**
7855 * xmlXPathNextPreceding:
7856 * @ctxt: the XPath Parser context
7857 * @cur: the current node in the traversal
7858 *
7859 * Traversal function for the "preceding" direction
7860 * the preceding axis contains all nodes in the same document as the context
7861 * node that are before the context node in document order, excluding any
7862 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7863 * ordered in reverse document order
7864 *
7865 * Returns the next element following that axis
7866 */
7867xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00007868xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7869{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007870 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007871 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007872 cur = ctxt->context->node;
7873 if (cur == NULL)
7874 return (NULL);
7875 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7876 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00007877 do {
7878 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007879 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7880 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007881 }
7882
7883 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007884 if (cur == NULL)
7885 return (NULL);
7886 if (cur == ctxt->context->doc->children)
7887 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007888 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007889 return (cur);
7890}
7891
7892/**
7893 * xmlXPathNextPrecedingInternal:
7894 * @ctxt: the XPath Parser context
7895 * @cur: the current node in the traversal
7896 *
7897 * Traversal function for the "preceding" direction
7898 * the preceding axis contains all nodes in the same document as the context
7899 * node that are before the context node in document order, excluding any
7900 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7901 * ordered in reverse document order
7902 * This is a faster implementation but internal only since it requires a
7903 * state kept in the parser context: ctxt->ancestor.
7904 *
7905 * Returns the next element following that axis
7906 */
7907static xmlNodePtr
7908xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7909 xmlNodePtr cur)
7910{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007911 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007912 if (cur == NULL) {
7913 cur = ctxt->context->node;
7914 if (cur == NULL)
7915 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00007916 if (cur->type == XML_NAMESPACE_DECL)
7917 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007918 ctxt->ancestor = cur->parent;
7919 }
7920 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7921 cur = cur->prev;
7922 while (cur->prev == NULL) {
7923 cur = cur->parent;
7924 if (cur == NULL)
7925 return (NULL);
7926 if (cur == ctxt->context->doc->children)
7927 return (NULL);
7928 if (cur != ctxt->ancestor)
7929 return (cur);
7930 ctxt->ancestor = cur->parent;
7931 }
7932 cur = cur->prev;
7933 while (cur->last != NULL)
7934 cur = cur->last;
7935 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007936}
7937
7938/**
7939 * xmlXPathNextNamespace:
7940 * @ctxt: the XPath Parser context
7941 * @cur: the current attribute in the traversal
7942 *
7943 * Traversal function for the "namespace" direction
7944 * the namespace axis contains the namespace nodes of the context node;
7945 * the order of nodes on this axis is implementation-defined; the axis will
7946 * be empty unless the context node is an element
7947 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007948 * We keep the XML namespace node at the end of the list.
7949 *
Owen Taylor3473f882001-02-23 17:55:21 +00007950 * Returns the next element following that axis
7951 */
7952xmlNodePtr
7953xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007954 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007955 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00007956 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007957 if (ctxt->context->tmpNsList != NULL)
7958 xmlFree(ctxt->context->tmpNsList);
7959 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00007960 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007961 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007962 if (ctxt->context->tmpNsList != NULL) {
7963 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7964 ctxt->context->tmpNsNr++;
7965 }
7966 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007967 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007968 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00007969 if (ctxt->context->tmpNsNr > 0) {
7970 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7971 } else {
7972 if (ctxt->context->tmpNsList != NULL)
7973 xmlFree(ctxt->context->tmpNsList);
7974 ctxt->context->tmpNsList = NULL;
7975 return(NULL);
7976 }
Owen Taylor3473f882001-02-23 17:55:21 +00007977}
7978
7979/**
7980 * xmlXPathNextAttribute:
7981 * @ctxt: the XPath Parser context
7982 * @cur: the current attribute in the traversal
7983 *
7984 * Traversal function for the "attribute" direction
7985 * TODO: support DTD inherited default attributes
7986 *
7987 * Returns the next element following that axis
7988 */
7989xmlNodePtr
7990xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007991 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00007992 if (ctxt->context->node == NULL)
7993 return(NULL);
7994 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7995 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007996 if (cur == NULL) {
7997 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7998 return(NULL);
7999 return((xmlNodePtr)ctxt->context->node->properties);
8000 }
8001 return((xmlNodePtr)cur->next);
8002}
8003
8004/************************************************************************
8005 * *
8006 * NodeTest Functions *
8007 * *
8008 ************************************************************************/
8009
Owen Taylor3473f882001-02-23 17:55:21 +00008010#define IS_FUNCTION 200
8011
Owen Taylor3473f882001-02-23 17:55:21 +00008012
8013/************************************************************************
8014 * *
8015 * Implicit tree core function library *
8016 * *
8017 ************************************************************************/
8018
8019/**
8020 * xmlXPathRoot:
8021 * @ctxt: the XPath Parser context
8022 *
8023 * Initialize the context to the root of the document
8024 */
8025void
8026xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008027 if ((ctxt == NULL) || (ctxt->context == NULL))
8028 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008029 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008030 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8031 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008032}
8033
8034/************************************************************************
8035 * *
8036 * The explicit core function library *
8037 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8038 * *
8039 ************************************************************************/
8040
8041
8042/**
8043 * xmlXPathLastFunction:
8044 * @ctxt: the XPath Parser context
8045 * @nargs: the number of arguments
8046 *
8047 * Implement the last() XPath function
8048 * number last()
8049 * The last function returns the number of nodes in the context node list.
8050 */
8051void
8052xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8053 CHECK_ARITY(0);
8054 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008055 valuePush(ctxt,
8056 xmlXPathCacheNewFloat(ctxt->context,
8057 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008058#ifdef DEBUG_EXPR
8059 xmlGenericError(xmlGenericErrorContext,
8060 "last() : %d\n", ctxt->context->contextSize);
8061#endif
8062 } else {
8063 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8064 }
8065}
8066
8067/**
8068 * xmlXPathPositionFunction:
8069 * @ctxt: the XPath Parser context
8070 * @nargs: the number of arguments
8071 *
8072 * Implement the position() XPath function
8073 * number position()
8074 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008075 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008076 * will be equal to last().
8077 */
8078void
8079xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8080 CHECK_ARITY(0);
8081 if (ctxt->context->proximityPosition >= 0) {
8082 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008083 xmlXPathCacheNewFloat(ctxt->context,
8084 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008085#ifdef DEBUG_EXPR
8086 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8087 ctxt->context->proximityPosition);
8088#endif
8089 } else {
8090 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8091 }
8092}
8093
8094/**
8095 * xmlXPathCountFunction:
8096 * @ctxt: the XPath Parser context
8097 * @nargs: the number of arguments
8098 *
8099 * Implement the count() XPath function
8100 * number count(node-set)
8101 */
8102void
8103xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8104 xmlXPathObjectPtr cur;
8105
8106 CHECK_ARITY(1);
8107 if ((ctxt->value == NULL) ||
8108 ((ctxt->value->type != XPATH_NODESET) &&
8109 (ctxt->value->type != XPATH_XSLT_TREE)))
8110 XP_ERROR(XPATH_INVALID_TYPE);
8111 cur = valuePop(ctxt);
8112
Daniel Veillard911f49a2001-04-07 15:39:35 +00008113 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008114 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008115 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008116 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8117 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008118 } else {
8119 if ((cur->nodesetval->nodeNr != 1) ||
8120 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008121 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008122 } else {
8123 xmlNodePtr tmp;
8124 int i = 0;
8125
8126 tmp = cur->nodesetval->nodeTab[0];
8127 if (tmp != NULL) {
8128 tmp = tmp->children;
8129 while (tmp != NULL) {
8130 tmp = tmp->next;
8131 i++;
8132 }
8133 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008134 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008135 }
8136 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008137 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008138}
8139
8140/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008141 * xmlXPathGetElementsByIds:
8142 * @doc: the document
8143 * @ids: a whitespace separated list of IDs
8144 *
8145 * Selects elements by their unique ID.
8146 *
8147 * Returns a node-set of selected elements.
8148 */
8149static xmlNodeSetPtr
8150xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8151 xmlNodeSetPtr ret;
8152 const xmlChar *cur = ids;
8153 xmlChar *ID;
8154 xmlAttrPtr attr;
8155 xmlNodePtr elem = NULL;
8156
Daniel Veillard7a985a12003-07-06 17:57:42 +00008157 if (ids == NULL) return(NULL);
8158
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008159 ret = xmlXPathNodeSetCreate(NULL);
8160
William M. Brack76e95df2003-10-18 16:20:14 +00008161 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008162 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008163 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008164 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008165
8166 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008167 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008168 /*
8169 * We used to check the fact that the value passed
8170 * was an NCName, but this generated much troubles for
8171 * me and Aleksey Sanin, people blatantly violated that
8172 * constaint, like Visa3D spec.
8173 * if (xmlValidateNCName(ID, 1) == 0)
8174 */
8175 attr = xmlGetID(doc, ID);
8176 if (attr != NULL) {
8177 if (attr->type == XML_ATTRIBUTE_NODE)
8178 elem = attr->parent;
8179 else if (attr->type == XML_ELEMENT_NODE)
8180 elem = (xmlNodePtr) attr;
8181 else
8182 elem = NULL;
8183 if (elem != NULL)
8184 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008185 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008186 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008187 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008188
William M. Brack76e95df2003-10-18 16:20:14 +00008189 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008190 ids = cur;
8191 }
8192 return(ret);
8193}
8194
8195/**
Owen Taylor3473f882001-02-23 17:55:21 +00008196 * xmlXPathIdFunction:
8197 * @ctxt: the XPath Parser context
8198 * @nargs: the number of arguments
8199 *
8200 * Implement the id() XPath function
8201 * node-set id(object)
8202 * The id function selects elements by their unique ID
8203 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8204 * then the result is the union of the result of applying id to the
8205 * string value of each of the nodes in the argument node-set. When the
8206 * argument to id is of any other type, the argument is converted to a
8207 * string as if by a call to the string function; the string is split
8208 * into a whitespace-separated list of tokens (whitespace is any sequence
8209 * of characters matching the production S); the result is a node-set
8210 * containing the elements in the same document as the context node that
8211 * have a unique ID equal to any of the tokens in the list.
8212 */
8213void
8214xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008215 xmlChar *tokens;
8216 xmlNodeSetPtr ret;
8217 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008218
8219 CHECK_ARITY(1);
8220 obj = valuePop(ctxt);
8221 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008222 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008223 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008224 int i;
8225
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008226 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008227
Daniel Veillard911f49a2001-04-07 15:39:35 +00008228 if (obj->nodesetval != NULL) {
8229 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008230 tokens =
8231 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8232 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8233 ret = xmlXPathNodeSetMerge(ret, ns);
8234 xmlXPathFreeNodeSet(ns);
8235 if (tokens != NULL)
8236 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008237 }
Owen Taylor3473f882001-02-23 17:55:21 +00008238 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008239 xmlXPathReleaseObject(ctxt->context, obj);
8240 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008241 return;
8242 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008243 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008244 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008245 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8246 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008247 return;
8248}
8249
8250/**
8251 * xmlXPathLocalNameFunction:
8252 * @ctxt: the XPath Parser context
8253 * @nargs: the number of arguments
8254 *
8255 * Implement the local-name() XPath function
8256 * string local-name(node-set?)
8257 * The local-name function returns a string containing the local part
8258 * of the name of the node in the argument node-set that is first in
8259 * document order. If the node-set is empty or the first node has no
8260 * name, an empty string is returned. If the argument is omitted it
8261 * defaults to the context node.
8262 */
8263void
8264xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8265 xmlXPathObjectPtr cur;
8266
Daniel Veillarda82b1822004-11-08 16:24:57 +00008267 if (ctxt == NULL) return;
8268
Owen Taylor3473f882001-02-23 17:55:21 +00008269 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008270 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8271 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008272 nargs = 1;
8273 }
8274
8275 CHECK_ARITY(1);
8276 if ((ctxt->value == NULL) ||
8277 ((ctxt->value->type != XPATH_NODESET) &&
8278 (ctxt->value->type != XPATH_XSLT_TREE)))
8279 XP_ERROR(XPATH_INVALID_TYPE);
8280 cur = valuePop(ctxt);
8281
Daniel Veillard911f49a2001-04-07 15:39:35 +00008282 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008283 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008284 } else {
8285 int i = 0; /* Should be first in document order !!!!! */
8286 switch (cur->nodesetval->nodeTab[i]->type) {
8287 case XML_ELEMENT_NODE:
8288 case XML_ATTRIBUTE_NODE:
8289 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008290 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008291 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008292 else
8293 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008294 xmlXPathCacheNewString(ctxt->context,
8295 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008296 break;
8297 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008298 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008299 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8300 break;
8301 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008302 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008303 }
8304 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008305 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008306}
8307
8308/**
8309 * xmlXPathNamespaceURIFunction:
8310 * @ctxt: the XPath Parser context
8311 * @nargs: the number of arguments
8312 *
8313 * Implement the namespace-uri() XPath function
8314 * string namespace-uri(node-set?)
8315 * The namespace-uri function returns a string containing the
8316 * namespace URI of the expanded name of the node in the argument
8317 * node-set that is first in document order. If the node-set is empty,
8318 * the first node has no name, or the expanded name has no namespace
8319 * URI, an empty string is returned. If the argument is omitted it
8320 * defaults to the context node.
8321 */
8322void
8323xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8324 xmlXPathObjectPtr cur;
8325
Daniel Veillarda82b1822004-11-08 16:24:57 +00008326 if (ctxt == NULL) return;
8327
Owen Taylor3473f882001-02-23 17:55:21 +00008328 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008329 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8330 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008331 nargs = 1;
8332 }
8333 CHECK_ARITY(1);
8334 if ((ctxt->value == NULL) ||
8335 ((ctxt->value->type != XPATH_NODESET) &&
8336 (ctxt->value->type != XPATH_XSLT_TREE)))
8337 XP_ERROR(XPATH_INVALID_TYPE);
8338 cur = valuePop(ctxt);
8339
Daniel Veillard911f49a2001-04-07 15:39:35 +00008340 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008341 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008342 } else {
8343 int i = 0; /* Should be first in document order !!!!! */
8344 switch (cur->nodesetval->nodeTab[i]->type) {
8345 case XML_ELEMENT_NODE:
8346 case XML_ATTRIBUTE_NODE:
8347 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008348 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008349 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008350 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008351 cur->nodesetval->nodeTab[i]->ns->href));
8352 break;
8353 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008354 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008355 }
8356 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008357 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008358}
8359
8360/**
8361 * xmlXPathNameFunction:
8362 * @ctxt: the XPath Parser context
8363 * @nargs: the number of arguments
8364 *
8365 * Implement the name() XPath function
8366 * string name(node-set?)
8367 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008368 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008369 * order. The QName must represent the name with respect to the namespace
8370 * declarations in effect on the node whose name is being represented.
8371 * Typically, this will be the form in which the name occurred in the XML
8372 * source. This need not be the case if there are namespace declarations
8373 * in effect on the node that associate multiple prefixes with the same
8374 * namespace. However, an implementation may include information about
8375 * the original prefix in its representation of nodes; in this case, an
8376 * implementation can ensure that the returned string is always the same
8377 * as the QName used in the XML source. If the argument it omitted it
8378 * defaults to the context node.
8379 * Libxml keep the original prefix so the "real qualified name" used is
8380 * returned.
8381 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008382static void
Daniel Veillard04383752001-07-08 14:27:15 +00008383xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8384{
Owen Taylor3473f882001-02-23 17:55:21 +00008385 xmlXPathObjectPtr cur;
8386
8387 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008388 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8389 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008390 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008391 }
8392
8393 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008394 if ((ctxt->value == NULL) ||
8395 ((ctxt->value->type != XPATH_NODESET) &&
8396 (ctxt->value->type != XPATH_XSLT_TREE)))
8397 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008398 cur = valuePop(ctxt);
8399
Daniel Veillard911f49a2001-04-07 15:39:35 +00008400 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008401 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008402 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008403 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008404
Daniel Veillard04383752001-07-08 14:27:15 +00008405 switch (cur->nodesetval->nodeTab[i]->type) {
8406 case XML_ELEMENT_NODE:
8407 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008408 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008409 valuePush(ctxt,
8410 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008411 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8412 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008413 valuePush(ctxt,
8414 xmlXPathCacheNewString(ctxt->context,
8415 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008416 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008417 xmlChar *fullname;
8418
8419 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8420 cur->nodesetval->nodeTab[i]->ns->prefix,
8421 NULL, 0);
8422 if (fullname == cur->nodesetval->nodeTab[i]->name)
8423 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8424 if (fullname == NULL) {
8425 XP_ERROR(XPATH_MEMORY_ERROR);
8426 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008427 valuePush(ctxt, xmlXPathCacheWrapString(
8428 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008429 }
8430 break;
8431 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008432 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8433 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008434 xmlXPathLocalNameFunction(ctxt, 1);
8435 }
Owen Taylor3473f882001-02-23 17:55:21 +00008436 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008437 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008438}
8439
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008440
8441/**
Owen Taylor3473f882001-02-23 17:55:21 +00008442 * xmlXPathStringFunction:
8443 * @ctxt: the XPath Parser context
8444 * @nargs: the number of arguments
8445 *
8446 * Implement the string() XPath function
8447 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008448 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008449 * - A node-set is converted to a string by returning the value of
8450 * the node in the node-set that is first in document order.
8451 * If the node-set is empty, an empty string is returned.
8452 * - A number is converted to a string as follows
8453 * + NaN is converted to the string NaN
8454 * + positive zero is converted to the string 0
8455 * + negative zero is converted to the string 0
8456 * + positive infinity is converted to the string Infinity
8457 * + negative infinity is converted to the string -Infinity
8458 * + if the number is an integer, the number is represented in
8459 * decimal form as a Number with no decimal point and no leading
8460 * zeros, preceded by a minus sign (-) if the number is negative
8461 * + otherwise, the number is represented in decimal form as a
8462 * Number including a decimal point with at least one digit
8463 * before the decimal point and at least one digit after the
8464 * decimal point, preceded by a minus sign (-) if the number
8465 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008466 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008467 * before the decimal point; beyond the one required digit
8468 * after the decimal point there must be as many, but only as
8469 * many, more digits as are needed to uniquely distinguish the
8470 * number from all other IEEE 754 numeric values.
8471 * - The boolean false value is converted to the string false.
8472 * The boolean true value is converted to the string true.
8473 *
8474 * If the argument is omitted, it defaults to a node-set with the
8475 * context node as its only member.
8476 */
8477void
8478xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8479 xmlXPathObjectPtr cur;
8480
Daniel Veillarda82b1822004-11-08 16:24:57 +00008481 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008482 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008483 valuePush(ctxt,
8484 xmlXPathCacheWrapString(ctxt->context,
8485 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008486 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008487 }
8488
8489 CHECK_ARITY(1);
8490 cur = valuePop(ctxt);
8491 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008492 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008493}
8494
8495/**
8496 * xmlXPathStringLengthFunction:
8497 * @ctxt: the XPath Parser context
8498 * @nargs: the number of arguments
8499 *
8500 * Implement the string-length() XPath function
8501 * number string-length(string?)
8502 * The string-length returns the number of characters in the string
8503 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8504 * the context node converted to a string, in other words the value
8505 * of the context node.
8506 */
8507void
8508xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8509 xmlXPathObjectPtr cur;
8510
8511 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008512 if ((ctxt == NULL) || (ctxt->context == NULL))
8513 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008514 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008515 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008516 } else {
8517 xmlChar *content;
8518
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008519 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008520 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8521 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008522 xmlFree(content);
8523 }
8524 return;
8525 }
8526 CHECK_ARITY(1);
8527 CAST_TO_STRING;
8528 CHECK_TYPE(XPATH_STRING);
8529 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008530 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8531 xmlUTF8Strlen(cur->stringval)));
8532 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008533}
8534
8535/**
8536 * xmlXPathConcatFunction:
8537 * @ctxt: the XPath Parser context
8538 * @nargs: the number of arguments
8539 *
8540 * Implement the concat() XPath function
8541 * string concat(string, string, string*)
8542 * The concat function returns the concatenation of its arguments.
8543 */
8544void
8545xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546 xmlXPathObjectPtr cur, newobj;
8547 xmlChar *tmp;
8548
Daniel Veillarda82b1822004-11-08 16:24:57 +00008549 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008550 if (nargs < 2) {
8551 CHECK_ARITY(2);
8552 }
8553
8554 CAST_TO_STRING;
8555 cur = valuePop(ctxt);
8556 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008557 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008558 return;
8559 }
8560 nargs--;
8561
8562 while (nargs > 0) {
8563 CAST_TO_STRING;
8564 newobj = valuePop(ctxt);
8565 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008566 xmlXPathReleaseObject(ctxt->context, newobj);
8567 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008568 XP_ERROR(XPATH_INVALID_TYPE);
8569 }
8570 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8571 newobj->stringval = cur->stringval;
8572 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008573 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008574 nargs--;
8575 }
8576 valuePush(ctxt, cur);
8577}
8578
8579/**
8580 * xmlXPathContainsFunction:
8581 * @ctxt: the XPath Parser context
8582 * @nargs: the number of arguments
8583 *
8584 * Implement the contains() XPath function
8585 * boolean contains(string, string)
8586 * The contains function returns true if the first argument string
8587 * contains the second argument string, and otherwise returns false.
8588 */
8589void
8590xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8591 xmlXPathObjectPtr hay, needle;
8592
8593 CHECK_ARITY(2);
8594 CAST_TO_STRING;
8595 CHECK_TYPE(XPATH_STRING);
8596 needle = valuePop(ctxt);
8597 CAST_TO_STRING;
8598 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008599
Owen Taylor3473f882001-02-23 17:55:21 +00008600 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008601 xmlXPathReleaseObject(ctxt->context, hay);
8602 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008603 XP_ERROR(XPATH_INVALID_TYPE);
8604 }
8605 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008606 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008607 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008608 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8609 xmlXPathReleaseObject(ctxt->context, hay);
8610 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008611}
8612
8613/**
8614 * xmlXPathStartsWithFunction:
8615 * @ctxt: the XPath Parser context
8616 * @nargs: the number of arguments
8617 *
8618 * Implement the starts-with() XPath function
8619 * boolean starts-with(string, string)
8620 * The starts-with function returns true if the first argument string
8621 * starts with the second argument string, and otherwise returns false.
8622 */
8623void
8624xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8625 xmlXPathObjectPtr hay, needle;
8626 int n;
8627
8628 CHECK_ARITY(2);
8629 CAST_TO_STRING;
8630 CHECK_TYPE(XPATH_STRING);
8631 needle = valuePop(ctxt);
8632 CAST_TO_STRING;
8633 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008634
Owen Taylor3473f882001-02-23 17:55:21 +00008635 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008636 xmlXPathReleaseObject(ctxt->context, hay);
8637 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008638 XP_ERROR(XPATH_INVALID_TYPE);
8639 }
8640 n = xmlStrlen(needle->stringval);
8641 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008642 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008643 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008644 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8645 xmlXPathReleaseObject(ctxt->context, hay);
8646 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008647}
8648
8649/**
8650 * xmlXPathSubstringFunction:
8651 * @ctxt: the XPath Parser context
8652 * @nargs: the number of arguments
8653 *
8654 * Implement the substring() XPath function
8655 * string substring(string, number, number?)
8656 * The substring function returns the substring of the first argument
8657 * starting at the position specified in the second argument with
8658 * length specified in the third argument. For example,
8659 * substring("12345",2,3) returns "234". If the third argument is not
8660 * specified, it returns the substring starting at the position specified
8661 * in the second argument and continuing to the end of the string. For
8662 * example, substring("12345",2) returns "2345". More precisely, each
8663 * character in the string (see [3.6 Strings]) is considered to have a
8664 * numeric position: the position of the first character is 1, the position
8665 * of the second character is 2 and so on. The returned substring contains
8666 * those characters for which the position of the character is greater than
8667 * or equal to the second argument and, if the third argument is specified,
8668 * less than the sum of the second and third arguments; the comparisons
8669 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8670 * - substring("12345", 1.5, 2.6) returns "234"
8671 * - substring("12345", 0, 3) returns "12"
8672 * - substring("12345", 0 div 0, 3) returns ""
8673 * - substring("12345", 1, 0 div 0) returns ""
8674 * - substring("12345", -42, 1 div 0) returns "12345"
8675 * - substring("12345", -1 div 0, 1 div 0) returns ""
8676 */
8677void
8678xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8679 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008680 double le=0, in;
8681 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008682 xmlChar *ret;
8683
Owen Taylor3473f882001-02-23 17:55:21 +00008684 if (nargs < 2) {
8685 CHECK_ARITY(2);
8686 }
8687 if (nargs > 3) {
8688 CHECK_ARITY(3);
8689 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008690 /*
8691 * take care of possible last (position) argument
8692 */
Owen Taylor3473f882001-02-23 17:55:21 +00008693 if (nargs == 3) {
8694 CAST_TO_NUMBER;
8695 CHECK_TYPE(XPATH_NUMBER);
8696 len = valuePop(ctxt);
8697 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008698 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008699 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008700
Owen Taylor3473f882001-02-23 17:55:21 +00008701 CAST_TO_NUMBER;
8702 CHECK_TYPE(XPATH_NUMBER);
8703 start = valuePop(ctxt);
8704 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008705 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008706 CAST_TO_STRING;
8707 CHECK_TYPE(XPATH_STRING);
8708 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008709 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008710
Daniel Veillard97ac1312001-05-30 19:14:17 +00008711 /*
8712 * If last pos not present, calculate last position
8713 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008714 if (nargs != 3) {
8715 le = (double)m;
8716 if (in < 1.0)
8717 in = 1.0;
8718 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008719
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008720 /* Need to check for the special cases where either
8721 * the index is NaN, the length is NaN, or both
8722 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008723 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008724 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008725 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008726 * To meet the requirements of the spec, the arguments
8727 * must be converted to integer format before
8728 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008729 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008730 * First we go to integer form, rounding up
8731 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008732 */
8733 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008734 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008735
Daniel Veillard9e412302002-06-10 15:59:44 +00008736 if (xmlXPathIsInf(le) == 1) {
8737 l = m;
8738 if (i < 1)
8739 i = 1;
8740 }
8741 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8742 l = 0;
8743 else {
8744 l = (int) le;
8745 if (((double)l)+0.5 <= le) l++;
8746 }
8747
8748 /* Now we normalize inidices */
8749 i -= 1;
8750 l += i;
8751 if (i < 0)
8752 i = 0;
8753 if (l > m)
8754 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00008755
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008756 /* number of chars to copy */
8757 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00008758
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008759 ret = xmlUTF8Strsub(str->stringval, i, l);
8760 }
8761 else {
8762 ret = NULL;
8763 }
Owen Taylor3473f882001-02-23 17:55:21 +00008764 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008765 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008766 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008767 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008768 xmlFree(ret);
8769 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008770 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00008771}
8772
8773/**
8774 * xmlXPathSubstringBeforeFunction:
8775 * @ctxt: the XPath Parser context
8776 * @nargs: the number of arguments
8777 *
8778 * Implement the substring-before() XPath function
8779 * string substring-before(string, string)
8780 * The substring-before function returns the substring of the first
8781 * argument string that precedes the first occurrence of the second
8782 * argument string in the first argument string, or the empty string
8783 * if the first argument string does not contain the second argument
8784 * string. For example, substring-before("1999/04/01","/") returns 1999.
8785 */
8786void
8787xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8788 xmlXPathObjectPtr str;
8789 xmlXPathObjectPtr find;
8790 xmlBufferPtr target;
8791 const xmlChar *point;
8792 int offset;
8793
8794 CHECK_ARITY(2);
8795 CAST_TO_STRING;
8796 find = valuePop(ctxt);
8797 CAST_TO_STRING;
8798 str = valuePop(ctxt);
8799
8800 target = xmlBufferCreate();
8801 if (target) {
8802 point = xmlStrstr(str->stringval, find->stringval);
8803 if (point) {
8804 offset = (int)(point - str->stringval);
8805 xmlBufferAdd(target, str->stringval, offset);
8806 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008807 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8808 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008809 xmlBufferFree(target);
8810 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008811 xmlXPathReleaseObject(ctxt->context, str);
8812 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008813}
8814
8815/**
8816 * xmlXPathSubstringAfterFunction:
8817 * @ctxt: the XPath Parser context
8818 * @nargs: the number of arguments
8819 *
8820 * Implement the substring-after() XPath function
8821 * string substring-after(string, string)
8822 * The substring-after function returns the substring of the first
8823 * argument string that follows the first occurrence of the second
8824 * argument string in the first argument string, or the empty stringi
8825 * if the first argument string does not contain the second argument
8826 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8827 * and substring-after("1999/04/01","19") returns 99/04/01.
8828 */
8829void
8830xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8831 xmlXPathObjectPtr str;
8832 xmlXPathObjectPtr find;
8833 xmlBufferPtr target;
8834 const xmlChar *point;
8835 int offset;
8836
8837 CHECK_ARITY(2);
8838 CAST_TO_STRING;
8839 find = valuePop(ctxt);
8840 CAST_TO_STRING;
8841 str = valuePop(ctxt);
8842
8843 target = xmlBufferCreate();
8844 if (target) {
8845 point = xmlStrstr(str->stringval, find->stringval);
8846 if (point) {
8847 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
8848 xmlBufferAdd(target, &str->stringval[offset],
8849 xmlStrlen(str->stringval) - offset);
8850 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008851 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8852 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008853 xmlBufferFree(target);
8854 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008855 xmlXPathReleaseObject(ctxt->context, str);
8856 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008857}
8858
8859/**
8860 * xmlXPathNormalizeFunction:
8861 * @ctxt: the XPath Parser context
8862 * @nargs: the number of arguments
8863 *
8864 * Implement the normalize-space() XPath function
8865 * string normalize-space(string?)
8866 * The normalize-space function returns the argument string with white
8867 * space normalized by stripping leading and trailing whitespace
8868 * and replacing sequences of whitespace characters by a single
8869 * space. Whitespace characters are the same allowed by the S production
8870 * in XML. If the argument is omitted, it defaults to the context
8871 * node converted to a string, in other words the value of the context node.
8872 */
8873void
8874xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8875 xmlXPathObjectPtr obj = NULL;
8876 xmlChar *source = NULL;
8877 xmlBufferPtr target;
8878 xmlChar blank;
8879
Daniel Veillarda82b1822004-11-08 16:24:57 +00008880 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008881 if (nargs == 0) {
8882 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008883 valuePush(ctxt,
8884 xmlXPathCacheWrapString(ctxt->context,
8885 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00008886 nargs = 1;
8887 }
8888
8889 CHECK_ARITY(1);
8890 CAST_TO_STRING;
8891 CHECK_TYPE(XPATH_STRING);
8892 obj = valuePop(ctxt);
8893 source = obj->stringval;
8894
8895 target = xmlBufferCreate();
8896 if (target && source) {
8897
8898 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00008899 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00008900 source++;
8901
8902 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8903 blank = 0;
8904 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00008905 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008906 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00008907 } else {
8908 if (blank) {
8909 xmlBufferAdd(target, &blank, 1);
8910 blank = 0;
8911 }
8912 xmlBufferAdd(target, source, 1);
8913 }
8914 source++;
8915 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008916 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8917 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008918 xmlBufferFree(target);
8919 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008920 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008921}
8922
8923/**
8924 * xmlXPathTranslateFunction:
8925 * @ctxt: the XPath Parser context
8926 * @nargs: the number of arguments
8927 *
8928 * Implement the translate() XPath function
8929 * string translate(string, string, string)
8930 * The translate function returns the first argument string with
8931 * occurrences of characters in the second argument string replaced
8932 * by the character at the corresponding position in the third argument
8933 * string. For example, translate("bar","abc","ABC") returns the string
8934 * BAr. If there is a character in the second argument string with no
8935 * character at a corresponding position in the third argument string
8936 * (because the second argument string is longer than the third argument
8937 * string), then occurrences of that character in the first argument
8938 * string are removed. For example, translate("--aaa--","abc-","ABC")
8939 * returns "AAA". If a character occurs more than once in second
8940 * argument string, then the first occurrence determines the replacement
8941 * character. If the third argument string is longer than the second
8942 * argument string, then excess characters are ignored.
8943 */
8944void
8945xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00008946 xmlXPathObjectPtr str;
8947 xmlXPathObjectPtr from;
8948 xmlXPathObjectPtr to;
8949 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008950 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008951 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00008952 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008953 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00008954
Daniel Veillarde043ee12001-04-16 14:08:07 +00008955 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00008956
Daniel Veillarde043ee12001-04-16 14:08:07 +00008957 CAST_TO_STRING;
8958 to = valuePop(ctxt);
8959 CAST_TO_STRING;
8960 from = valuePop(ctxt);
8961 CAST_TO_STRING;
8962 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008963
Daniel Veillarde043ee12001-04-16 14:08:07 +00008964 target = xmlBufferCreate();
8965 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008966 max = xmlUTF8Strlen(to->stringval);
8967 for (cptr = str->stringval; (ch=*cptr); ) {
8968 offset = xmlUTF8Strloc(from->stringval, cptr);
8969 if (offset >= 0) {
8970 if (offset < max) {
8971 point = xmlUTF8Strpos(to->stringval, offset);
8972 if (point)
8973 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
8974 }
8975 } else
8976 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8977
8978 /* Step to next character in input */
8979 cptr++;
8980 if ( ch & 0x80 ) {
8981 /* if not simple ascii, verify proper format */
8982 if ( (ch & 0xc0) != 0xc0 ) {
8983 xmlGenericError(xmlGenericErrorContext,
8984 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8985 break;
8986 }
8987 /* then skip over remaining bytes for this char */
8988 while ( (ch <<= 1) & 0x80 )
8989 if ( (*cptr++ & 0xc0) != 0x80 ) {
8990 xmlGenericError(xmlGenericErrorContext,
8991 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8992 break;
8993 }
8994 if (ch & 0x80) /* must have had error encountered */
8995 break;
8996 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00008997 }
Owen Taylor3473f882001-02-23 17:55:21 +00008998 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008999 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9000 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009001 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009002 xmlXPathReleaseObject(ctxt->context, str);
9003 xmlXPathReleaseObject(ctxt->context, from);
9004 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009005}
9006
9007/**
9008 * xmlXPathBooleanFunction:
9009 * @ctxt: the XPath Parser context
9010 * @nargs: the number of arguments
9011 *
9012 * Implement the boolean() XPath function
9013 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009014 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009015 * - a number is true if and only if it is neither positive or
9016 * negative zero nor NaN
9017 * - a node-set is true if and only if it is non-empty
9018 * - a string is true if and only if its length is non-zero
9019 */
9020void
9021xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9022 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009023
9024 CHECK_ARITY(1);
9025 cur = valuePop(ctxt);
9026 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009027 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009028 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009029}
9030
9031/**
9032 * xmlXPathNotFunction:
9033 * @ctxt: the XPath Parser context
9034 * @nargs: the number of arguments
9035 *
9036 * Implement the not() XPath function
9037 * boolean not(boolean)
9038 * The not function returns true if its argument is false,
9039 * and false otherwise.
9040 */
9041void
9042xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9043 CHECK_ARITY(1);
9044 CAST_TO_BOOLEAN;
9045 CHECK_TYPE(XPATH_BOOLEAN);
9046 ctxt->value->boolval = ! ctxt->value->boolval;
9047}
9048
9049/**
9050 * xmlXPathTrueFunction:
9051 * @ctxt: the XPath Parser context
9052 * @nargs: the number of arguments
9053 *
9054 * Implement the true() XPath function
9055 * boolean true()
9056 */
9057void
9058xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9059 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009060 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009061}
9062
9063/**
9064 * xmlXPathFalseFunction:
9065 * @ctxt: the XPath Parser context
9066 * @nargs: the number of arguments
9067 *
9068 * Implement the false() XPath function
9069 * boolean false()
9070 */
9071void
9072xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9073 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009074 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009075}
9076
9077/**
9078 * xmlXPathLangFunction:
9079 * @ctxt: the XPath Parser context
9080 * @nargs: the number of arguments
9081 *
9082 * Implement the lang() XPath function
9083 * boolean lang(string)
9084 * The lang function returns true or false depending on whether the
9085 * language of the context node as specified by xml:lang attributes
9086 * is the same as or is a sublanguage of the language specified by
9087 * the argument string. The language of the context node is determined
9088 * by the value of the xml:lang attribute on the context node, or, if
9089 * the context node has no xml:lang attribute, by the value of the
9090 * xml:lang attribute on the nearest ancestor of the context node that
9091 * has an xml:lang attribute. If there is no such attribute, then lang
9092 * returns false. If there is such an attribute, then lang returns
9093 * true if the attribute value is equal to the argument ignoring case,
9094 * or if there is some suffix starting with - such that the attribute
9095 * value is equal to the argument ignoring that suffix of the attribute
9096 * value and ignoring case.
9097 */
9098void
9099xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009100 xmlXPathObjectPtr val = NULL;
9101 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009102 const xmlChar *lang;
9103 int ret = 0;
9104 int i;
9105
9106 CHECK_ARITY(1);
9107 CAST_TO_STRING;
9108 CHECK_TYPE(XPATH_STRING);
9109 val = valuePop(ctxt);
9110 lang = val->stringval;
9111 theLang = xmlNodeGetLang(ctxt->context->node);
9112 if ((theLang != NULL) && (lang != NULL)) {
9113 for (i = 0;lang[i] != 0;i++)
9114 if (toupper(lang[i]) != toupper(theLang[i]))
9115 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009116 if ((theLang[i] == 0) || (theLang[i] == '-'))
9117 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009118 }
9119not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009120 if (theLang != NULL)
9121 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009122
9123 xmlXPathReleaseObject(ctxt->context, val);
9124 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009125}
9126
9127/**
9128 * xmlXPathNumberFunction:
9129 * @ctxt: the XPath Parser context
9130 * @nargs: the number of arguments
9131 *
9132 * Implement the number() XPath function
9133 * number number(object?)
9134 */
9135void
9136xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9137 xmlXPathObjectPtr cur;
9138 double res;
9139
Daniel Veillarda82b1822004-11-08 16:24:57 +00009140 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009141 if (nargs == 0) {
9142 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009143 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009144 } else {
9145 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9146
9147 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009148 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009149 xmlFree(content);
9150 }
9151 return;
9152 }
9153
9154 CHECK_ARITY(1);
9155 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009156 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009157}
9158
9159/**
9160 * xmlXPathSumFunction:
9161 * @ctxt: the XPath Parser context
9162 * @nargs: the number of arguments
9163 *
9164 * Implement the sum() XPath function
9165 * number sum(node-set)
9166 * The sum function returns the sum of the values of the nodes in
9167 * the argument node-set.
9168 */
9169void
9170xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9171 xmlXPathObjectPtr cur;
9172 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009173 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009174
9175 CHECK_ARITY(1);
9176 if ((ctxt->value == NULL) ||
9177 ((ctxt->value->type != XPATH_NODESET) &&
9178 (ctxt->value->type != XPATH_XSLT_TREE)))
9179 XP_ERROR(XPATH_INVALID_TYPE);
9180 cur = valuePop(ctxt);
9181
William M. Brack08171912003-12-29 02:52:11 +00009182 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009183 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9184 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009185 }
9186 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009187 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9188 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009189}
9190
William M. Brack3d426662005-04-19 14:40:28 +00009191/*
9192 * To assure working code on multiple platforms, we want to only depend
9193 * upon the characteristic truncation of converting a floating point value
9194 * to an integer. Unfortunately, because of the different storage sizes
9195 * of our internal floating point value (double) and integer (int), we
9196 * can't directly convert (see bug 301162). This macro is a messy
9197 * 'workaround'
9198 */
9199#define XTRUNC(f, v) \
9200 f = fmod((v), INT_MAX); \
9201 f = (v) - (f) + (double)((int)(f));
9202
Owen Taylor3473f882001-02-23 17:55:21 +00009203/**
9204 * xmlXPathFloorFunction:
9205 * @ctxt: the XPath Parser context
9206 * @nargs: the number of arguments
9207 *
9208 * Implement the floor() XPath function
9209 * number floor(number)
9210 * The floor function returns the largest (closest to positive infinity)
9211 * number that is not greater than the argument and that is an integer.
9212 */
9213void
9214xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009215 double f;
9216
Owen Taylor3473f882001-02-23 17:55:21 +00009217 CHECK_ARITY(1);
9218 CAST_TO_NUMBER;
9219 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009220
William M. Brack3d426662005-04-19 14:40:28 +00009221 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009222 if (f != ctxt->value->floatval) {
9223 if (ctxt->value->floatval > 0)
9224 ctxt->value->floatval = f;
9225 else
9226 ctxt->value->floatval = f - 1;
9227 }
Owen Taylor3473f882001-02-23 17:55:21 +00009228}
9229
9230/**
9231 * xmlXPathCeilingFunction:
9232 * @ctxt: the XPath Parser context
9233 * @nargs: the number of arguments
9234 *
9235 * Implement the ceiling() XPath function
9236 * number ceiling(number)
9237 * The ceiling function returns the smallest (closest to negative infinity)
9238 * number that is not less than the argument and that is an integer.
9239 */
9240void
9241xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9242 double f;
9243
9244 CHECK_ARITY(1);
9245 CAST_TO_NUMBER;
9246 CHECK_TYPE(XPATH_NUMBER);
9247
9248#if 0
9249 ctxt->value->floatval = ceil(ctxt->value->floatval);
9250#else
William M. Brack3d426662005-04-19 14:40:28 +00009251 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009252 if (f != ctxt->value->floatval) {
9253 if (ctxt->value->floatval > 0)
9254 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009255 else {
9256 if (ctxt->value->floatval < 0 && f == 0)
9257 ctxt->value->floatval = xmlXPathNZERO;
9258 else
9259 ctxt->value->floatval = f;
9260 }
9261
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009262 }
Owen Taylor3473f882001-02-23 17:55:21 +00009263#endif
9264}
9265
9266/**
9267 * xmlXPathRoundFunction:
9268 * @ctxt: the XPath Parser context
9269 * @nargs: the number of arguments
9270 *
9271 * Implement the round() XPath function
9272 * number round(number)
9273 * The round function returns the number that is closest to the
9274 * argument and that is an integer. If there are two such numbers,
9275 * then the one that is even is returned.
9276 */
9277void
9278xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9279 double f;
9280
9281 CHECK_ARITY(1);
9282 CAST_TO_NUMBER;
9283 CHECK_TYPE(XPATH_NUMBER);
9284
Daniel Veillardcda96922001-08-21 10:56:31 +00009285 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9286 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9287 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009288 (ctxt->value->floatval == 0.0))
9289 return;
9290
William M. Brack3d426662005-04-19 14:40:28 +00009291 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009292 if (ctxt->value->floatval < 0) {
9293 if (ctxt->value->floatval < f - 0.5)
9294 ctxt->value->floatval = f - 1;
9295 else
9296 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009297 if (ctxt->value->floatval == 0)
9298 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009299 } else {
9300 if (ctxt->value->floatval < f + 0.5)
9301 ctxt->value->floatval = f;
9302 else
9303 ctxt->value->floatval = f + 1;
9304 }
Owen Taylor3473f882001-02-23 17:55:21 +00009305}
9306
9307/************************************************************************
9308 * *
9309 * The Parser *
9310 * *
9311 ************************************************************************/
9312
9313/*
William M. Brack08171912003-12-29 02:52:11 +00009314 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009315 * implementation.
9316 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009317static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009318static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009319static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009320static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009321static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9322 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009323
9324/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009325 * xmlXPathCurrentChar:
9326 * @ctxt: the XPath parser context
9327 * @cur: pointer to the beginning of the char
9328 * @len: pointer to the length of the char read
9329 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009330 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009331 * bytes in the input buffer.
9332 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009333 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009334 */
9335
9336static int
9337xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9338 unsigned char c;
9339 unsigned int val;
9340 const xmlChar *cur;
9341
9342 if (ctxt == NULL)
9343 return(0);
9344 cur = ctxt->cur;
9345
9346 /*
9347 * We are supposed to handle UTF8, check it's valid
9348 * From rfc2044: encoding of the Unicode values on UTF-8:
9349 *
9350 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9351 * 0000 0000-0000 007F 0xxxxxxx
9352 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9353 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9354 *
9355 * Check for the 0x110000 limit too
9356 */
9357 c = *cur;
9358 if (c & 0x80) {
9359 if ((cur[1] & 0xc0) != 0x80)
9360 goto encoding_error;
9361 if ((c & 0xe0) == 0xe0) {
9362
9363 if ((cur[2] & 0xc0) != 0x80)
9364 goto encoding_error;
9365 if ((c & 0xf0) == 0xf0) {
9366 if (((c & 0xf8) != 0xf0) ||
9367 ((cur[3] & 0xc0) != 0x80))
9368 goto encoding_error;
9369 /* 4-byte code */
9370 *len = 4;
9371 val = (cur[0] & 0x7) << 18;
9372 val |= (cur[1] & 0x3f) << 12;
9373 val |= (cur[2] & 0x3f) << 6;
9374 val |= cur[3] & 0x3f;
9375 } else {
9376 /* 3-byte code */
9377 *len = 3;
9378 val = (cur[0] & 0xf) << 12;
9379 val |= (cur[1] & 0x3f) << 6;
9380 val |= cur[2] & 0x3f;
9381 }
9382 } else {
9383 /* 2-byte code */
9384 *len = 2;
9385 val = (cur[0] & 0x1f) << 6;
9386 val |= cur[1] & 0x3f;
9387 }
9388 if (!IS_CHAR(val)) {
9389 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9390 }
9391 return(val);
9392 } else {
9393 /* 1-byte code */
9394 *len = 1;
9395 return((int) *cur);
9396 }
9397encoding_error:
9398 /*
William M. Brack08171912003-12-29 02:52:11 +00009399 * If we detect an UTF8 error that probably means that the
9400 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009401 * declaration header. Report the error and switch the encoding
9402 * to ISO-Latin-1 (if you don't like this policy, just declare the
9403 * encoding !)
9404 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009405 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009406 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009407}
9408
9409/**
Owen Taylor3473f882001-02-23 17:55:21 +00009410 * xmlXPathParseNCName:
9411 * @ctxt: the XPath Parser context
9412 *
9413 * parse an XML namespace non qualified name.
9414 *
9415 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9416 *
9417 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9418 * CombiningChar | Extender
9419 *
9420 * Returns the namespace name or NULL
9421 */
9422
9423xmlChar *
9424xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009425 const xmlChar *in;
9426 xmlChar *ret;
9427 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009428
Daniel Veillarda82b1822004-11-08 16:24:57 +00009429 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009430 /*
9431 * Accelerator for simple ASCII names
9432 */
9433 in = ctxt->cur;
9434 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9435 ((*in >= 0x41) && (*in <= 0x5A)) ||
9436 (*in == '_')) {
9437 in++;
9438 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9439 ((*in >= 0x41) && (*in <= 0x5A)) ||
9440 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009441 (*in == '_') || (*in == '.') ||
9442 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009443 in++;
9444 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9445 (*in == '[') || (*in == ']') || (*in == ':') ||
9446 (*in == '@') || (*in == '*')) {
9447 count = in - ctxt->cur;
9448 if (count == 0)
9449 return(NULL);
9450 ret = xmlStrndup(ctxt->cur, count);
9451 ctxt->cur = in;
9452 return(ret);
9453 }
9454 }
9455 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009456}
9457
Daniel Veillard2156a562001-04-28 12:24:34 +00009458
Owen Taylor3473f882001-02-23 17:55:21 +00009459/**
9460 * xmlXPathParseQName:
9461 * @ctxt: the XPath Parser context
9462 * @prefix: a xmlChar **
9463 *
9464 * parse an XML qualified name
9465 *
9466 * [NS 5] QName ::= (Prefix ':')? LocalPart
9467 *
9468 * [NS 6] Prefix ::= NCName
9469 *
9470 * [NS 7] LocalPart ::= NCName
9471 *
9472 * Returns the function returns the local part, and prefix is updated
9473 * to get the Prefix if any.
9474 */
9475
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009476static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009477xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9478 xmlChar *ret = NULL;
9479
9480 *prefix = NULL;
9481 ret = xmlXPathParseNCName(ctxt);
9482 if (CUR == ':') {
9483 *prefix = ret;
9484 NEXT;
9485 ret = xmlXPathParseNCName(ctxt);
9486 }
9487 return(ret);
9488}
9489
9490/**
9491 * xmlXPathParseName:
9492 * @ctxt: the XPath Parser context
9493 *
9494 * parse an XML name
9495 *
9496 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9497 * CombiningChar | Extender
9498 *
9499 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9500 *
9501 * Returns the namespace name or NULL
9502 */
9503
9504xmlChar *
9505xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009506 const xmlChar *in;
9507 xmlChar *ret;
9508 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009509
Daniel Veillarda82b1822004-11-08 16:24:57 +00009510 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009511 /*
9512 * Accelerator for simple ASCII names
9513 */
9514 in = ctxt->cur;
9515 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9516 ((*in >= 0x41) && (*in <= 0x5A)) ||
9517 (*in == '_') || (*in == ':')) {
9518 in++;
9519 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9520 ((*in >= 0x41) && (*in <= 0x5A)) ||
9521 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009522 (*in == '_') || (*in == '-') ||
9523 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009524 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009525 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009526 count = in - ctxt->cur;
9527 ret = xmlStrndup(ctxt->cur, count);
9528 ctxt->cur = in;
9529 return(ret);
9530 }
9531 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009532 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009533}
9534
Daniel Veillard61d80a22001-04-27 17:13:01 +00009535static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009536xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009537 xmlChar buf[XML_MAX_NAMELEN + 5];
9538 int len = 0, l;
9539 int c;
9540
9541 /*
9542 * Handler for more complex cases
9543 */
9544 c = CUR_CHAR(l);
9545 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009546 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9547 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009548 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009549 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009550 return(NULL);
9551 }
9552
9553 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9554 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9555 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009556 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009557 (IS_COMBINING(c)) ||
9558 (IS_EXTENDER(c)))) {
9559 COPY_BUF(l,buf,len,c);
9560 NEXTL(l);
9561 c = CUR_CHAR(l);
9562 if (len >= XML_MAX_NAMELEN) {
9563 /*
9564 * Okay someone managed to make a huge name, so he's ready to pay
9565 * for the processing speed.
9566 */
9567 xmlChar *buffer;
9568 int max = len * 2;
9569
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009570 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009571 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009572 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009573 }
9574 memcpy(buffer, buf, len);
9575 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9576 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009577 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009578 (IS_COMBINING(c)) ||
9579 (IS_EXTENDER(c))) {
9580 if (len + 10 > max) {
9581 max *= 2;
9582 buffer = (xmlChar *) xmlRealloc(buffer,
9583 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009584 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009585 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009586 }
9587 }
9588 COPY_BUF(l,buffer,len,c);
9589 NEXTL(l);
9590 c = CUR_CHAR(l);
9591 }
9592 buffer[len] = 0;
9593 return(buffer);
9594 }
9595 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009596 if (len == 0)
9597 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009598 return(xmlStrndup(buf, len));
9599}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009600
9601#define MAX_FRAC 20
9602
William M. Brack372a4452004-02-17 13:09:23 +00009603/*
9604 * These are used as divisors for the fractional part of a number.
9605 * Since the table includes 1.0 (representing '0' fractional digits),
9606 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9607 */
9608static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009609 1.0, 10.0, 100.0, 1000.0, 10000.0,
9610 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9611 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9612 100000000000000.0,
9613 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009614 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009615};
9616
Owen Taylor3473f882001-02-23 17:55:21 +00009617/**
9618 * xmlXPathStringEvalNumber:
9619 * @str: A string to scan
9620 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009621 * [30a] Float ::= Number ('e' Digits?)?
9622 *
Owen Taylor3473f882001-02-23 17:55:21 +00009623 * [30] Number ::= Digits ('.' Digits?)?
9624 * | '.' Digits
9625 * [31] Digits ::= [0-9]+
9626 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009627 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009628 * In complement of the Number expression, this function also handles
9629 * negative values : '-' Number.
9630 *
9631 * Returns the double value.
9632 */
9633double
9634xmlXPathStringEvalNumber(const xmlChar *str) {
9635 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009636 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009637 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009638 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009639 int exponent = 0;
9640 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009641#ifdef __GNUC__
9642 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009643 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009644#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009645 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009646 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009647 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9648 return(xmlXPathNAN);
9649 }
9650 if (*cur == '-') {
9651 isneg = 1;
9652 cur++;
9653 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009654
9655#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009656 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009657 * tmp/temp is a workaround against a gcc compiler bug
9658 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009659 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009660 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009661 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009662 ret = ret * 10;
9663 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009664 ok = 1;
9665 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009666 temp = (double) tmp;
9667 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009668 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009669#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009670 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009671 while ((*cur >= '0') && (*cur <= '9')) {
9672 ret = ret * 10 + (*cur - '0');
9673 ok = 1;
9674 cur++;
9675 }
9676#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009677
Owen Taylor3473f882001-02-23 17:55:21 +00009678 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009679 int v, frac = 0;
9680 double fraction = 0;
9681
Owen Taylor3473f882001-02-23 17:55:21 +00009682 cur++;
9683 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9684 return(xmlXPathNAN);
9685 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009686 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9687 v = (*cur - '0');
9688 fraction = fraction * 10 + v;
9689 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009690 cur++;
9691 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009692 fraction /= my_pow10[frac];
9693 ret = ret + fraction;
9694 while ((*cur >= '0') && (*cur <= '9'))
9695 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009696 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009697 if ((*cur == 'e') || (*cur == 'E')) {
9698 cur++;
9699 if (*cur == '-') {
9700 is_exponent_negative = 1;
9701 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009702 } else if (*cur == '+') {
9703 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009704 }
9705 while ((*cur >= '0') && (*cur <= '9')) {
9706 exponent = exponent * 10 + (*cur - '0');
9707 cur++;
9708 }
9709 }
William M. Brack76e95df2003-10-18 16:20:14 +00009710 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009711 if (*cur != 0) return(xmlXPathNAN);
9712 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009713 if (is_exponent_negative) exponent = -exponent;
9714 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009715 return(ret);
9716}
9717
9718/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009719 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009720 * @ctxt: the XPath Parser context
9721 *
9722 * [30] Number ::= Digits ('.' Digits?)?
9723 * | '.' Digits
9724 * [31] Digits ::= [0-9]+
9725 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009726 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009727 *
9728 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009729static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009730xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9731{
Owen Taylor3473f882001-02-23 17:55:21 +00009732 double ret = 0.0;
9733 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009734 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009735 int exponent = 0;
9736 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009737#ifdef __GNUC__
9738 unsigned long tmp = 0;
9739 double temp;
9740#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009741
9742 CHECK_ERROR;
9743 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9744 XP_ERROR(XPATH_NUMBER_ERROR);
9745 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009746#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009747 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009748 * tmp/temp is a workaround against a gcc compiler bug
9749 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009750 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009751 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009752 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009753 ret = ret * 10;
9754 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009755 ok = 1;
9756 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00009757 temp = (double) tmp;
9758 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009759 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009760#else
9761 ret = 0;
9762 while ((CUR >= '0') && (CUR <= '9')) {
9763 ret = ret * 10 + (CUR - '0');
9764 ok = 1;
9765 NEXT;
9766 }
9767#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009768 if (CUR == '.') {
9769 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009770 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9771 XP_ERROR(XPATH_NUMBER_ERROR);
9772 }
9773 while ((CUR >= '0') && (CUR <= '9')) {
9774 mult /= 10;
9775 ret = ret + (CUR - '0') * mult;
9776 NEXT;
9777 }
Owen Taylor3473f882001-02-23 17:55:21 +00009778 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009779 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009780 NEXT;
9781 if (CUR == '-') {
9782 is_exponent_negative = 1;
9783 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00009784 } else if (CUR == '+') {
9785 NEXT;
9786 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009787 while ((CUR >= '0') && (CUR <= '9')) {
9788 exponent = exponent * 10 + (CUR - '0');
9789 NEXT;
9790 }
9791 if (is_exponent_negative)
9792 exponent = -exponent;
9793 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00009794 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009795 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009796 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009797}
9798
9799/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009800 * xmlXPathParseLiteral:
9801 * @ctxt: the XPath Parser context
9802 *
9803 * Parse a Literal
9804 *
9805 * [29] Literal ::= '"' [^"]* '"'
9806 * | "'" [^']* "'"
9807 *
9808 * Returns the value found or NULL in case of error
9809 */
9810static xmlChar *
9811xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9812 const xmlChar *q;
9813 xmlChar *ret = NULL;
9814
9815 if (CUR == '"') {
9816 NEXT;
9817 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009818 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009819 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009820 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009821 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009822 } else {
9823 ret = xmlStrndup(q, CUR_PTR - q);
9824 NEXT;
9825 }
9826 } else if (CUR == '\'') {
9827 NEXT;
9828 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009829 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009830 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009831 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009832 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009833 } else {
9834 ret = xmlStrndup(q, CUR_PTR - q);
9835 NEXT;
9836 }
9837 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00009838 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009839 }
9840 return(ret);
9841}
9842
9843/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009844 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00009845 * @ctxt: the XPath Parser context
9846 *
9847 * Parse a Literal and push it on the stack.
9848 *
9849 * [29] Literal ::= '"' [^"]* '"'
9850 * | "'" [^']* "'"
9851 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009852 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00009853 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009854static void
9855xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009856 const xmlChar *q;
9857 xmlChar *ret = NULL;
9858
9859 if (CUR == '"') {
9860 NEXT;
9861 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009862 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00009863 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009864 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009865 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9866 } else {
9867 ret = xmlStrndup(q, CUR_PTR - q);
9868 NEXT;
9869 }
9870 } else if (CUR == '\'') {
9871 NEXT;
9872 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009873 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00009874 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009875 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009876 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9877 } else {
9878 ret = xmlStrndup(q, CUR_PTR - q);
9879 NEXT;
9880 }
9881 } else {
9882 XP_ERROR(XPATH_START_LITERAL_ERROR);
9883 }
9884 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009885 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009886 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009887 xmlFree(ret);
9888}
9889
9890/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009891 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00009892 * @ctxt: the XPath Parser context
9893 *
9894 * Parse a VariableReference, evaluate it and push it on the stack.
9895 *
9896 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00009897 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00009898 * of any of the types that are possible for the value of an expression,
9899 * and may also be of additional types not specified here.
9900 *
9901 * Early evaluation is possible since:
9902 * The variable bindings [...] used to evaluate a subexpression are
9903 * always the same as those used to evaluate the containing expression.
9904 *
9905 * [36] VariableReference ::= '$' QName
9906 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009907static void
9908xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009909 xmlChar *name;
9910 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009911
9912 SKIP_BLANKS;
9913 if (CUR != '$') {
9914 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9915 }
9916 NEXT;
9917 name = xmlXPathParseQName(ctxt, &prefix);
9918 if (name == NULL) {
9919 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9920 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009921 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009922 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
9923 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00009924 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00009925 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9926 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
9927 }
Owen Taylor3473f882001-02-23 17:55:21 +00009928}
9929
9930/**
9931 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00009932 * @name: a name string
9933 *
9934 * Is the name given a NodeType one.
9935 *
9936 * [38] NodeType ::= 'comment'
9937 * | 'text'
9938 * | 'processing-instruction'
9939 * | 'node'
9940 *
9941 * Returns 1 if true 0 otherwise
9942 */
9943int
9944xmlXPathIsNodeType(const xmlChar *name) {
9945 if (name == NULL)
9946 return(0);
9947
Daniel Veillard1971ee22002-01-31 20:29:19 +00009948 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00009949 return(1);
9950 if (xmlStrEqual(name, BAD_CAST "text"))
9951 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009952 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00009953 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009954 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00009955 return(1);
9956 return(0);
9957}
9958
9959/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009960 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00009961 * @ctxt: the XPath Parser context
9962 *
9963 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9964 * [17] Argument ::= Expr
9965 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009966 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00009967 * pushed on the stack
9968 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009969static void
9970xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009971 xmlChar *name;
9972 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009973 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009974 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009975
9976 name = xmlXPathParseQName(ctxt, &prefix);
9977 if (name == NULL) {
9978 XP_ERROR(XPATH_EXPR_ERROR);
9979 }
9980 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009981#ifdef DEBUG_EXPR
9982 if (prefix == NULL)
9983 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
9984 name);
9985 else
9986 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
9987 prefix, name);
9988#endif
9989
Owen Taylor3473f882001-02-23 17:55:21 +00009990 if (CUR != '(') {
9991 XP_ERROR(XPATH_EXPR_ERROR);
9992 }
9993 NEXT;
9994 SKIP_BLANKS;
9995
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009996 /*
9997 * Optimization for count(): we don't need the node-set to be sorted.
9998 */
9999 if ((prefix == NULL) && (name[0] == 'c') &&
10000 xmlStrEqual(name, BAD_CAST "count"))
10001 {
10002 sort = 0;
10003 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010004 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010005 if (CUR != ')') {
10006 while (CUR != 0) {
10007 int op1 = ctxt->comp->last;
10008 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010009 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010010 CHECK_ERROR;
10011 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10012 nbargs++;
10013 if (CUR == ')') break;
10014 if (CUR != ',') {
10015 XP_ERROR(XPATH_EXPR_ERROR);
10016 }
10017 NEXT;
10018 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010019 }
Owen Taylor3473f882001-02-23 17:55:21 +000010020 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010021 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10022 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010023 NEXT;
10024 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010025}
10026
10027/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010028 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010029 * @ctxt: the XPath Parser context
10030 *
10031 * [15] PrimaryExpr ::= VariableReference
10032 * | '(' Expr ')'
10033 * | Literal
10034 * | Number
10035 * | FunctionCall
10036 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010037 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010038 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010039static void
10040xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010041 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010042 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010043 else if (CUR == '(') {
10044 NEXT;
10045 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010046 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010047 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010048 if (CUR != ')') {
10049 XP_ERROR(XPATH_EXPR_ERROR);
10050 }
10051 NEXT;
10052 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010053 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010054 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010055 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010056 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010057 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010058 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010059 }
10060 SKIP_BLANKS;
10061}
10062
10063/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010064 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010065 * @ctxt: the XPath Parser context
10066 *
10067 * [20] FilterExpr ::= PrimaryExpr
10068 * | FilterExpr Predicate
10069 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010070 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010071 * Square brackets are used to filter expressions in the same way that
10072 * they are used in location paths. It is an error if the expression to
10073 * be filtered does not evaluate to a node-set. The context node list
10074 * used for evaluating the expression in square brackets is the node-set
10075 * to be filtered listed in document order.
10076 */
10077
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010078static void
10079xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10080 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010081 CHECK_ERROR;
10082 SKIP_BLANKS;
10083
10084 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010085 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010086 SKIP_BLANKS;
10087 }
10088
10089
10090}
10091
10092/**
10093 * xmlXPathScanName:
10094 * @ctxt: the XPath Parser context
10095 *
10096 * Trickery: parse an XML name but without consuming the input flow
10097 * Needed to avoid insanity in the parser state.
10098 *
10099 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10100 * CombiningChar | Extender
10101 *
10102 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10103 *
10104 * [6] Names ::= Name (S Name)*
10105 *
10106 * Returns the Name parsed or NULL
10107 */
10108
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010109static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010110xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010111 int len = 0, l;
10112 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010113 const xmlChar *cur;
10114 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010115
Daniel Veillard03226812004-11-01 14:55:21 +000010116 cur = ctxt->cur;
10117
10118 c = CUR_CHAR(l);
10119 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10120 (!IS_LETTER(c) && (c != '_') &&
10121 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010122 return(NULL);
10123 }
10124
Daniel Veillard03226812004-11-01 14:55:21 +000010125 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10126 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10127 (c == '.') || (c == '-') ||
10128 (c == '_') || (c == ':') ||
10129 (IS_COMBINING(c)) ||
10130 (IS_EXTENDER(c)))) {
10131 len += l;
10132 NEXTL(l);
10133 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010134 }
Daniel Veillard03226812004-11-01 14:55:21 +000010135 ret = xmlStrndup(cur, ctxt->cur - cur);
10136 ctxt->cur = cur;
10137 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010138}
10139
10140/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010141 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010142 * @ctxt: the XPath Parser context
10143 *
10144 * [19] PathExpr ::= LocationPath
10145 * | FilterExpr
10146 * | FilterExpr '/' RelativeLocationPath
10147 * | FilterExpr '//' RelativeLocationPath
10148 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010149 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010150 * The / operator and // operators combine an arbitrary expression
10151 * and a relative location path. It is an error if the expression
10152 * does not evaluate to a node-set.
10153 * The / operator does composition in the same way as when / is
10154 * used in a location path. As in location paths, // is short for
10155 * /descendant-or-self::node()/.
10156 */
10157
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010158static void
10159xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010160 int lc = 1; /* Should we branch to LocationPath ? */
10161 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10162
10163 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010164 if ((CUR == '$') || (CUR == '(') ||
10165 (IS_ASCII_DIGIT(CUR)) ||
10166 (CUR == '\'') || (CUR == '"') ||
10167 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010168 lc = 0;
10169 } else if (CUR == '*') {
10170 /* relative or absolute location path */
10171 lc = 1;
10172 } else if (CUR == '/') {
10173 /* relative or absolute location path */
10174 lc = 1;
10175 } else if (CUR == '@') {
10176 /* relative abbreviated attribute location path */
10177 lc = 1;
10178 } else if (CUR == '.') {
10179 /* relative abbreviated attribute location path */
10180 lc = 1;
10181 } else {
10182 /*
10183 * Problem is finding if we have a name here whether it's:
10184 * - a nodetype
10185 * - a function call in which case it's followed by '('
10186 * - an axis in which case it's followed by ':'
10187 * - a element name
10188 * We do an a priori analysis here rather than having to
10189 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010190 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010191 * read/write/debug.
10192 */
10193 SKIP_BLANKS;
10194 name = xmlXPathScanName(ctxt);
10195 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10196#ifdef DEBUG_STEP
10197 xmlGenericError(xmlGenericErrorContext,
10198 "PathExpr: Axis\n");
10199#endif
10200 lc = 1;
10201 xmlFree(name);
10202 } else if (name != NULL) {
10203 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010204
10205
10206 while (NXT(len) != 0) {
10207 if (NXT(len) == '/') {
10208 /* element name */
10209#ifdef DEBUG_STEP
10210 xmlGenericError(xmlGenericErrorContext,
10211 "PathExpr: AbbrRelLocation\n");
10212#endif
10213 lc = 1;
10214 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010215 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010216 /* ignore blanks */
10217 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010218 } else if (NXT(len) == ':') {
10219#ifdef DEBUG_STEP
10220 xmlGenericError(xmlGenericErrorContext,
10221 "PathExpr: AbbrRelLocation\n");
10222#endif
10223 lc = 1;
10224 break;
10225 } else if ((NXT(len) == '(')) {
10226 /* Note Type or Function */
10227 if (xmlXPathIsNodeType(name)) {
10228#ifdef DEBUG_STEP
10229 xmlGenericError(xmlGenericErrorContext,
10230 "PathExpr: Type search\n");
10231#endif
10232 lc = 1;
10233 } else {
10234#ifdef DEBUG_STEP
10235 xmlGenericError(xmlGenericErrorContext,
10236 "PathExpr: function call\n");
10237#endif
10238 lc = 0;
10239 }
10240 break;
10241 } else if ((NXT(len) == '[')) {
10242 /* element name */
10243#ifdef DEBUG_STEP
10244 xmlGenericError(xmlGenericErrorContext,
10245 "PathExpr: AbbrRelLocation\n");
10246#endif
10247 lc = 1;
10248 break;
10249 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10250 (NXT(len) == '=')) {
10251 lc = 1;
10252 break;
10253 } else {
10254 lc = 1;
10255 break;
10256 }
10257 len++;
10258 }
10259 if (NXT(len) == 0) {
10260#ifdef DEBUG_STEP
10261 xmlGenericError(xmlGenericErrorContext,
10262 "PathExpr: AbbrRelLocation\n");
10263#endif
10264 /* element name */
10265 lc = 1;
10266 }
10267 xmlFree(name);
10268 } else {
William M. Brack08171912003-12-29 02:52:11 +000010269 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010270 XP_ERROR(XPATH_EXPR_ERROR);
10271 }
10272 }
10273
10274 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010275 if (CUR == '/') {
10276 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10277 } else {
10278 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010279 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010280 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010281 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010282 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010283 CHECK_ERROR;
10284 if ((CUR == '/') && (NXT(1) == '/')) {
10285 SKIP(2);
10286 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010287
10288 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10289 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10290 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10291
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010292 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010293 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010294 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010295 }
10296 }
10297 SKIP_BLANKS;
10298}
10299
10300/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010301 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010302 * @ctxt: the XPath Parser context
10303 *
10304 * [18] UnionExpr ::= PathExpr
10305 * | UnionExpr '|' PathExpr
10306 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010307 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010308 */
10309
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010310static void
10311xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10312 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010313 CHECK_ERROR;
10314 SKIP_BLANKS;
10315 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010316 int op1 = ctxt->comp->last;
10317 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010318
10319 NEXT;
10320 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010321 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010322
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010323 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10324
Owen Taylor3473f882001-02-23 17:55:21 +000010325 SKIP_BLANKS;
10326 }
Owen Taylor3473f882001-02-23 17:55:21 +000010327}
10328
10329/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010330 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010331 * @ctxt: the XPath Parser context
10332 *
10333 * [27] UnaryExpr ::= UnionExpr
10334 * | '-' UnaryExpr
10335 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010336 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010337 */
10338
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010339static void
10340xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010341 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010342 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010343
10344 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010345 while (CUR == '-') {
10346 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010347 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010348 NEXT;
10349 SKIP_BLANKS;
10350 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010351
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010352 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010353 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010354 if (found) {
10355 if (minus)
10356 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10357 else
10358 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010359 }
10360}
10361
10362/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010363 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010364 * @ctxt: the XPath Parser context
10365 *
10366 * [26] MultiplicativeExpr ::= UnaryExpr
10367 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10368 * | MultiplicativeExpr 'div' UnaryExpr
10369 * | MultiplicativeExpr 'mod' UnaryExpr
10370 * [34] MultiplyOperator ::= '*'
10371 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010372 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010373 */
10374
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010375static void
10376xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10377 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010378 CHECK_ERROR;
10379 SKIP_BLANKS;
10380 while ((CUR == '*') ||
10381 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10382 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10383 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010384 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010385
10386 if (CUR == '*') {
10387 op = 0;
10388 NEXT;
10389 } else if (CUR == 'd') {
10390 op = 1;
10391 SKIP(3);
10392 } else if (CUR == 'm') {
10393 op = 2;
10394 SKIP(3);
10395 }
10396 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010397 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010398 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010399 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010400 SKIP_BLANKS;
10401 }
10402}
10403
10404/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010405 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010406 * @ctxt: the XPath Parser context
10407 *
10408 * [25] AdditiveExpr ::= MultiplicativeExpr
10409 * | AdditiveExpr '+' MultiplicativeExpr
10410 * | AdditiveExpr '-' MultiplicativeExpr
10411 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010412 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010413 */
10414
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010415static void
10416xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010417
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010418 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010419 CHECK_ERROR;
10420 SKIP_BLANKS;
10421 while ((CUR == '+') || (CUR == '-')) {
10422 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010423 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010424
10425 if (CUR == '+') plus = 1;
10426 else plus = 0;
10427 NEXT;
10428 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010429 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010430 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010431 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010432 SKIP_BLANKS;
10433 }
10434}
10435
10436/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010437 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010438 * @ctxt: the XPath Parser context
10439 *
10440 * [24] RelationalExpr ::= AdditiveExpr
10441 * | RelationalExpr '<' AdditiveExpr
10442 * | RelationalExpr '>' AdditiveExpr
10443 * | RelationalExpr '<=' AdditiveExpr
10444 * | RelationalExpr '>=' AdditiveExpr
10445 *
10446 * A <= B > C is allowed ? Answer from James, yes with
10447 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10448 * which is basically what got implemented.
10449 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010450 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010451 * on the stack
10452 */
10453
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010454static void
10455xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10456 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010457 CHECK_ERROR;
10458 SKIP_BLANKS;
10459 while ((CUR == '<') ||
10460 (CUR == '>') ||
10461 ((CUR == '<') && (NXT(1) == '=')) ||
10462 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010463 int inf, strict;
10464 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010465
10466 if (CUR == '<') inf = 1;
10467 else inf = 0;
10468 if (NXT(1) == '=') strict = 0;
10469 else strict = 1;
10470 NEXT;
10471 if (!strict) NEXT;
10472 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010473 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010474 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010475 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010476 SKIP_BLANKS;
10477 }
10478}
10479
10480/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010481 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010482 * @ctxt: the XPath Parser context
10483 *
10484 * [23] EqualityExpr ::= RelationalExpr
10485 * | EqualityExpr '=' RelationalExpr
10486 * | EqualityExpr '!=' RelationalExpr
10487 *
10488 * A != B != C is allowed ? Answer from James, yes with
10489 * (RelationalExpr = RelationalExpr) = RelationalExpr
10490 * (RelationalExpr != RelationalExpr) != RelationalExpr
10491 * which is basically what got implemented.
10492 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010493 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010494 *
10495 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010496static void
10497xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10498 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010499 CHECK_ERROR;
10500 SKIP_BLANKS;
10501 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010502 int eq;
10503 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010504
10505 if (CUR == '=') eq = 1;
10506 else eq = 0;
10507 NEXT;
10508 if (!eq) NEXT;
10509 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010510 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010511 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010512 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010513 SKIP_BLANKS;
10514 }
10515}
10516
10517/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010518 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010519 * @ctxt: the XPath Parser context
10520 *
10521 * [22] AndExpr ::= EqualityExpr
10522 * | AndExpr 'and' EqualityExpr
10523 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010524 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010525 *
10526 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010527static void
10528xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10529 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010530 CHECK_ERROR;
10531 SKIP_BLANKS;
10532 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010533 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010534 SKIP(3);
10535 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010536 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010537 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010538 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010539 SKIP_BLANKS;
10540 }
10541}
10542
10543/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010544 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010545 * @ctxt: the XPath Parser context
10546 *
10547 * [14] Expr ::= OrExpr
10548 * [21] OrExpr ::= AndExpr
10549 * | OrExpr 'or' AndExpr
10550 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010551 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010552 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010553static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010554xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010555 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010556 CHECK_ERROR;
10557 SKIP_BLANKS;
10558 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010559 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010560 SKIP(2);
10561 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010562 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010563 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010564 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10565 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010566 SKIP_BLANKS;
10567 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010568 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010569 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010570 /*
10571 * This is the main place to eliminate sorting for
10572 * operations which don't require a sorted node-set.
10573 * E.g. count().
10574 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010575 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10576 }
Owen Taylor3473f882001-02-23 17:55:21 +000010577}
10578
10579/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010580 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010581 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010582 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010583 *
10584 * [8] Predicate ::= '[' PredicateExpr ']'
10585 * [9] PredicateExpr ::= Expr
10586 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010587 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010588 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010589static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010590xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010591 int op1 = ctxt->comp->last;
10592
10593 SKIP_BLANKS;
10594 if (CUR != '[') {
10595 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10596 }
10597 NEXT;
10598 SKIP_BLANKS;
10599
10600 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010601 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010602 CHECK_ERROR;
10603
10604 if (CUR != ']') {
10605 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10606 }
10607
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010608 if (filter)
10609 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10610 else
10611 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010612
10613 NEXT;
10614 SKIP_BLANKS;
10615}
10616
10617/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010618 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010619 * @ctxt: the XPath Parser context
10620 * @test: pointer to a xmlXPathTestVal
10621 * @type: pointer to a xmlXPathTypeVal
10622 * @prefix: placeholder for a possible name prefix
10623 *
10624 * [7] NodeTest ::= NameTest
10625 * | NodeType '(' ')'
10626 * | 'processing-instruction' '(' Literal ')'
10627 *
10628 * [37] NameTest ::= '*'
10629 * | NCName ':' '*'
10630 * | QName
10631 * [38] NodeType ::= 'comment'
10632 * | 'text'
10633 * | 'processing-instruction'
10634 * | 'node'
10635 *
William M. Brack08171912003-12-29 02:52:11 +000010636 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010637 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010638static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010639xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10640 xmlXPathTypeVal *type, const xmlChar **prefix,
10641 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010642 int blanks;
10643
10644 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10645 STRANGE;
10646 return(NULL);
10647 }
William M. Brack78637da2003-07-31 14:47:38 +000010648 *type = (xmlXPathTypeVal) 0;
10649 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010650 *prefix = NULL;
10651 SKIP_BLANKS;
10652
10653 if ((name == NULL) && (CUR == '*')) {
10654 /*
10655 * All elements
10656 */
10657 NEXT;
10658 *test = NODE_TEST_ALL;
10659 return(NULL);
10660 }
10661
10662 if (name == NULL)
10663 name = xmlXPathParseNCName(ctxt);
10664 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010665 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010666 }
10667
William M. Brack76e95df2003-10-18 16:20:14 +000010668 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010669 SKIP_BLANKS;
10670 if (CUR == '(') {
10671 NEXT;
10672 /*
10673 * NodeType or PI search
10674 */
10675 if (xmlStrEqual(name, BAD_CAST "comment"))
10676 *type = NODE_TYPE_COMMENT;
10677 else if (xmlStrEqual(name, BAD_CAST "node"))
10678 *type = NODE_TYPE_NODE;
10679 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10680 *type = NODE_TYPE_PI;
10681 else if (xmlStrEqual(name, BAD_CAST "text"))
10682 *type = NODE_TYPE_TEXT;
10683 else {
10684 if (name != NULL)
10685 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010686 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010687 }
10688
10689 *test = NODE_TEST_TYPE;
10690
10691 SKIP_BLANKS;
10692 if (*type == NODE_TYPE_PI) {
10693 /*
10694 * Specific case: search a PI by name.
10695 */
Owen Taylor3473f882001-02-23 17:55:21 +000010696 if (name != NULL)
10697 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010698 name = NULL;
10699 if (CUR != ')') {
10700 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010701 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010702 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010703 SKIP_BLANKS;
10704 }
Owen Taylor3473f882001-02-23 17:55:21 +000010705 }
10706 if (CUR != ')') {
10707 if (name != NULL)
10708 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010709 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010710 }
10711 NEXT;
10712 return(name);
10713 }
10714 *test = NODE_TEST_NAME;
10715 if ((!blanks) && (CUR == ':')) {
10716 NEXT;
10717
10718 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010719 * Since currently the parser context don't have a
10720 * namespace list associated:
10721 * The namespace name for this prefix can be computed
10722 * only at evaluation time. The compilation is done
10723 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010724 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010725#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010726 *prefix = xmlXPathNsLookup(ctxt->context, name);
10727 if (name != NULL)
10728 xmlFree(name);
10729 if (*prefix == NULL) {
10730 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10731 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010732#else
10733 *prefix = name;
10734#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010735
10736 if (CUR == '*') {
10737 /*
10738 * All elements
10739 */
10740 NEXT;
10741 *test = NODE_TEST_ALL;
10742 return(NULL);
10743 }
10744
10745 name = xmlXPathParseNCName(ctxt);
10746 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010747 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010748 }
10749 }
10750 return(name);
10751}
10752
10753/**
10754 * xmlXPathIsAxisName:
10755 * @name: a preparsed name token
10756 *
10757 * [6] AxisName ::= 'ancestor'
10758 * | 'ancestor-or-self'
10759 * | 'attribute'
10760 * | 'child'
10761 * | 'descendant'
10762 * | 'descendant-or-self'
10763 * | 'following'
10764 * | 'following-sibling'
10765 * | 'namespace'
10766 * | 'parent'
10767 * | 'preceding'
10768 * | 'preceding-sibling'
10769 * | 'self'
10770 *
10771 * Returns the axis or 0
10772 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010773static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000010774xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000010775 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010776 switch (name[0]) {
10777 case 'a':
10778 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10779 ret = AXIS_ANCESTOR;
10780 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10781 ret = AXIS_ANCESTOR_OR_SELF;
10782 if (xmlStrEqual(name, BAD_CAST "attribute"))
10783 ret = AXIS_ATTRIBUTE;
10784 break;
10785 case 'c':
10786 if (xmlStrEqual(name, BAD_CAST "child"))
10787 ret = AXIS_CHILD;
10788 break;
10789 case 'd':
10790 if (xmlStrEqual(name, BAD_CAST "descendant"))
10791 ret = AXIS_DESCENDANT;
10792 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10793 ret = AXIS_DESCENDANT_OR_SELF;
10794 break;
10795 case 'f':
10796 if (xmlStrEqual(name, BAD_CAST "following"))
10797 ret = AXIS_FOLLOWING;
10798 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10799 ret = AXIS_FOLLOWING_SIBLING;
10800 break;
10801 case 'n':
10802 if (xmlStrEqual(name, BAD_CAST "namespace"))
10803 ret = AXIS_NAMESPACE;
10804 break;
10805 case 'p':
10806 if (xmlStrEqual(name, BAD_CAST "parent"))
10807 ret = AXIS_PARENT;
10808 if (xmlStrEqual(name, BAD_CAST "preceding"))
10809 ret = AXIS_PRECEDING;
10810 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10811 ret = AXIS_PRECEDING_SIBLING;
10812 break;
10813 case 's':
10814 if (xmlStrEqual(name, BAD_CAST "self"))
10815 ret = AXIS_SELF;
10816 break;
10817 }
10818 return(ret);
10819}
10820
10821/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010822 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000010823 * @ctxt: the XPath Parser context
10824 *
10825 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10826 * | AbbreviatedStep
10827 *
10828 * [12] AbbreviatedStep ::= '.' | '..'
10829 *
10830 * [5] AxisSpecifier ::= AxisName '::'
10831 * | AbbreviatedAxisSpecifier
10832 *
10833 * [13] AbbreviatedAxisSpecifier ::= '@'?
10834 *
10835 * Modified for XPtr range support as:
10836 *
10837 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10838 * | AbbreviatedStep
10839 * | 'range-to' '(' Expr ')' Predicate*
10840 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010841 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000010842 * A location step of . is short for self::node(). This is
10843 * particularly useful in conjunction with //. For example, the
10844 * location path .//para is short for
10845 * self::node()/descendant-or-self::node()/child::para
10846 * and so will select all para descendant elements of the context
10847 * node.
10848 * Similarly, a location step of .. is short for parent::node().
10849 * For example, ../title is short for parent::node()/child::title
10850 * and so will select the title children of the parent of the context
10851 * node.
10852 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010853static void
10854xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010855#ifdef LIBXML_XPTR_ENABLED
10856 int rangeto = 0;
10857 int op2 = -1;
10858#endif
10859
Owen Taylor3473f882001-02-23 17:55:21 +000010860 SKIP_BLANKS;
10861 if ((CUR == '.') && (NXT(1) == '.')) {
10862 SKIP(2);
10863 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010864 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10865 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010866 } else if (CUR == '.') {
10867 NEXT;
10868 SKIP_BLANKS;
10869 } else {
10870 xmlChar *name = NULL;
10871 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010872 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000010873 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010874 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010875 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000010876
10877 /*
10878 * The modification needed for XPointer change to the production
10879 */
10880#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010881 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000010882 name = xmlXPathParseNCName(ctxt);
10883 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010884 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010885 xmlFree(name);
10886 SKIP_BLANKS;
10887 if (CUR != '(') {
10888 XP_ERROR(XPATH_EXPR_ERROR);
10889 }
10890 NEXT;
10891 SKIP_BLANKS;
10892
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010893 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010894 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000010895 CHECK_ERROR;
10896
10897 SKIP_BLANKS;
10898 if (CUR != ')') {
10899 XP_ERROR(XPATH_EXPR_ERROR);
10900 }
10901 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010902 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010903 goto eval_predicates;
10904 }
10905 }
10906#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000010907 if (CUR == '*') {
10908 axis = AXIS_CHILD;
10909 } else {
10910 if (name == NULL)
10911 name = xmlXPathParseNCName(ctxt);
10912 if (name != NULL) {
10913 axis = xmlXPathIsAxisName(name);
10914 if (axis != 0) {
10915 SKIP_BLANKS;
10916 if ((CUR == ':') && (NXT(1) == ':')) {
10917 SKIP(2);
10918 xmlFree(name);
10919 name = NULL;
10920 } else {
10921 /* an element name can conflict with an axis one :-\ */
10922 axis = AXIS_CHILD;
10923 }
Owen Taylor3473f882001-02-23 17:55:21 +000010924 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000010925 axis = AXIS_CHILD;
10926 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010927 } else if (CUR == '@') {
10928 NEXT;
10929 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000010930 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000010931 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000010932 }
Owen Taylor3473f882001-02-23 17:55:21 +000010933 }
10934
10935 CHECK_ERROR;
10936
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010937 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000010938 if (test == 0)
10939 return;
10940
Daniel Veillarded6c5492005-07-23 15:00:22 +000010941 if ((prefix != NULL) && (ctxt->context != NULL) &&
10942 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10943 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10944 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10945 }
10946 }
Owen Taylor3473f882001-02-23 17:55:21 +000010947#ifdef DEBUG_STEP
10948 xmlGenericError(xmlGenericErrorContext,
10949 "Basis : computing new set\n");
10950#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010951
Owen Taylor3473f882001-02-23 17:55:21 +000010952#ifdef DEBUG_STEP
10953 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010954 if (ctxt->value == NULL)
10955 xmlGenericError(xmlGenericErrorContext, "no value\n");
10956 else if (ctxt->value->nodesetval == NULL)
10957 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10958 else
10959 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010960#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010961
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010962#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000010963eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010964#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010965 op1 = ctxt->comp->last;
10966 ctxt->comp->last = -1;
10967
Owen Taylor3473f882001-02-23 17:55:21 +000010968 SKIP_BLANKS;
10969 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010970 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010971 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010972
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010973#ifdef LIBXML_XPTR_ENABLED
10974 if (rangeto) {
10975 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10976 } else
10977#endif
10978 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10979 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010980
Owen Taylor3473f882001-02-23 17:55:21 +000010981 }
10982#ifdef DEBUG_STEP
10983 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010984 if (ctxt->value == NULL)
10985 xmlGenericError(xmlGenericErrorContext, "no value\n");
10986 else if (ctxt->value->nodesetval == NULL)
10987 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10988 else
10989 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
10990 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010991#endif
10992}
10993
10994/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010995 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000010996 * @ctxt: the XPath Parser context
10997 *
10998 * [3] RelativeLocationPath ::= Step
10999 * | RelativeLocationPath '/' Step
11000 * | AbbreviatedRelativeLocationPath
11001 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11002 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011003 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011004 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011005static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011006xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011007(xmlXPathParserContextPtr ctxt) {
11008 SKIP_BLANKS;
11009 if ((CUR == '/') && (NXT(1) == '/')) {
11010 SKIP(2);
11011 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011012 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11013 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011014 } else if (CUR == '/') {
11015 NEXT;
11016 SKIP_BLANKS;
11017 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011018 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011019 SKIP_BLANKS;
11020 while (CUR == '/') {
11021 if ((CUR == '/') && (NXT(1) == '/')) {
11022 SKIP(2);
11023 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011024 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011025 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011026 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011027 } else if (CUR == '/') {
11028 NEXT;
11029 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011030 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011031 }
11032 SKIP_BLANKS;
11033 }
11034}
11035
11036/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011037 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011038 * @ctxt: the XPath Parser context
11039 *
11040 * [1] LocationPath ::= RelativeLocationPath
11041 * | AbsoluteLocationPath
11042 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11043 * | AbbreviatedAbsoluteLocationPath
11044 * [10] AbbreviatedAbsoluteLocationPath ::=
11045 * '//' RelativeLocationPath
11046 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011047 * Compile a location path
11048 *
Owen Taylor3473f882001-02-23 17:55:21 +000011049 * // is short for /descendant-or-self::node()/. For example,
11050 * //para is short for /descendant-or-self::node()/child::para and
11051 * so will select any para element in the document (even a para element
11052 * that is a document element will be selected by //para since the
11053 * document element node is a child of the root node); div//para is
11054 * short for div/descendant-or-self::node()/child::para and so will
11055 * select all para descendants of div children.
11056 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011057static void
11058xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011059 SKIP_BLANKS;
11060 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011061 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011062 } else {
11063 while (CUR == '/') {
11064 if ((CUR == '/') && (NXT(1) == '/')) {
11065 SKIP(2);
11066 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011067 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11068 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011069 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011070 } else if (CUR == '/') {
11071 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011072 SKIP_BLANKS;
11073 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011074 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011075 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011076 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011077 }
11078 }
11079 }
11080}
11081
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011082/************************************************************************
11083 * *
11084 * XPath precompiled expression evaluation *
11085 * *
11086 ************************************************************************/
11087
Daniel Veillardf06307e2001-07-03 10:35:50 +000011088static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011089xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11090
11091/**
11092 * xmlXPathNodeCollectAndTest:
11093 * @ctxt: the XPath Parser context
11094 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +000011095 * @first: pointer to the first element in document order
11096 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011097 *
11098 * This is the function implementing a step: based on the current list
11099 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000011100 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011101 *
11102 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +000011103 *
William M. Brack08171912003-12-29 02:52:11 +000011104 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011105 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011106static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011107xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011108 xmlXPathStepOpPtr op,
11109 xmlNodePtr * first, xmlNodePtr * last)
11110{
William M. Brack78637da2003-07-31 14:47:38 +000011111 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11112 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11113 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011114 const xmlChar *prefix = op->value4;
11115 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +000011116 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011117
11118#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011119 int nbMatches = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011120#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011121 int inputIdx, total = 0, specialNodeInSet = 0;
11122 xmlNodeSetPtr inputList, resultList, list;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011123 xmlXPathTraversalFunction next = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011124 xmlXPathTraversalFunctionExt compoundNext = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011125 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +000011126 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011127 xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011128 xmlXPathObjectPtr obj;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011129 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011130
Daniel Veillardf06307e2001-07-03 10:35:50 +000011131 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011132 obj = valuePop(ctxt);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011133
11134 /*
11135 * Setup wrt namespaces.
11136 */
Daniel Veillarde043ee12001-04-16 14:08:07 +000011137 if (prefix != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011138 URI = xmlXPathNsLookup(xpctxt, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011139 if (URI == NULL) {
11140 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011141 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011142 }
Daniel Veillarde043ee12001-04-16 14:08:07 +000011143 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011144
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011145#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011146 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011147#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011148
11149 /*
11150 * Setup wrt the axis.
11151 */
11152 addNode = xmlXPathNodeSetAdd;
11153 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011154 switch (axis) {
11155 case AXIS_ANCESTOR:
11156#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011157 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011158#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011159 first = NULL;
11160 next = xmlXPathNextAncestor;
11161 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011162 case AXIS_ANCESTOR_OR_SELF:
11163#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011164 xmlGenericError(xmlGenericErrorContext,
11165 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011166#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011167 first = NULL;
11168 next = xmlXPathNextAncestorOrSelf;
11169 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011170 case AXIS_ATTRIBUTE:
11171#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011172 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011173#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011174 first = NULL;
11175 last = NULL;
11176 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +000011177 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011178 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011179 case AXIS_CHILD:
11180#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011181 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011182#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011183 last = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011184 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11185 /*
11186 * This iterator will give us only nodes which can
11187 * hold element nodes.
11188 */
11189 compoundNext = xmlXPathNextDescendantOrSelfElemParent;
11190 }
11191 if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011192 /*
11193 * Optimization if an element node type is 'element'.
11194 */
11195 next = xmlXPathNextChildElement;
11196 } else
11197 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +000011198 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011199 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011200 case AXIS_DESCENDANT:
11201#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011202 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011203#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011204 last = NULL;
11205 next = xmlXPathNextDescendant;
11206 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011207 case AXIS_DESCENDANT_OR_SELF:
11208#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011209 xmlGenericError(xmlGenericErrorContext,
11210 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011211#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011212 last = NULL;
11213 next = xmlXPathNextDescendantOrSelf;
11214 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011215 case AXIS_FOLLOWING:
11216#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011217 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011218#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011219 last = NULL;
11220 next = xmlXPathNextFollowing;
11221 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011222 case AXIS_FOLLOWING_SIBLING:
11223#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011224 xmlGenericError(xmlGenericErrorContext,
11225 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011226#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011227 last = NULL;
11228 next = xmlXPathNextFollowingSibling;
11229 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011230 case AXIS_NAMESPACE:
11231#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011232 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011233#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011234 first = NULL;
11235 last = NULL;
11236 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +000011237 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011238 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011239 case AXIS_PARENT:
11240#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011241 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011242#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011243 first = NULL;
11244 next = xmlXPathNextParent;
11245 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011246 case AXIS_PRECEDING:
11247#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011248 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011249#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011250 first = NULL;
11251 next = xmlXPathNextPrecedingInternal;
11252 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011253 case AXIS_PRECEDING_SIBLING:
11254#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011255 xmlGenericError(xmlGenericErrorContext,
11256 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011257#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011258 first = NULL;
11259 next = xmlXPathNextPrecedingSibling;
11260 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011261 case AXIS_SELF:
11262#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011263 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011264#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011265 first = NULL;
11266 last = NULL;
11267 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +000011268 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011269 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011270 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011271 if (next == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011272 xmlXPathReleaseObject(xpctxt, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011273 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011274 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011275
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011276 inputList = obj->nodesetval;
11277 if ((inputList == NULL) || (inputList->nodeNr <= 0)) {
11278 xmlXPathReleaseObject(xpctxt, obj);
11279 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011280 return(0);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011281 }
11282
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011283#ifdef DEBUG_STEP
11284 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011285 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011286 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011287 case NODE_TEST_NONE:
11288 xmlGenericError(xmlGenericErrorContext,
11289 " searching for none !!!\n");
11290 break;
11291 case NODE_TEST_TYPE:
11292 xmlGenericError(xmlGenericErrorContext,
11293 " searching for type %d\n", type);
11294 break;
11295 case NODE_TEST_PI:
11296 xmlGenericError(xmlGenericErrorContext,
11297 " searching for PI !!!\n");
11298 break;
11299 case NODE_TEST_ALL:
11300 xmlGenericError(xmlGenericErrorContext,
11301 " searching for *\n");
11302 break;
11303 case NODE_TEST_NS:
11304 xmlGenericError(xmlGenericErrorContext,
11305 " searching for namespace %s\n",
11306 prefix);
11307 break;
11308 case NODE_TEST_NAME:
11309 xmlGenericError(xmlGenericErrorContext,
11310 " searching for name %s\n", name);
11311 if (prefix != NULL)
11312 xmlGenericError(xmlGenericErrorContext,
11313 " with namespace %s\n", prefix);
11314 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011315 }
11316 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11317#endif
11318 /*
11319 * 2.3 Node Tests
11320 * - For the attribute axis, the principal node type is attribute.
11321 * - For the namespace axis, the principal node type is namespace.
11322 * - For other axes, the principal node type is element.
11323 *
11324 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011325 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011326 * select all element children of the context node
11327 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011328 oldContextNode = xpctxt->node;
11329 addNode = xmlXPathNodeSetAddUnique;
11330 resultList = NULL;
11331 list = NULL;
11332 compoundContextNode = NULL;
11333 contextNode = NULL;
11334 inputIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011335
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011336 while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) {
11337 if (compoundNext != NULL) {
11338 /*
11339 * This is a compound traversal.
11340 */
11341 if (contextNode == NULL) {
11342 /*
11343 * Set the context for the initial traversal.
11344 */
11345 compoundContextNode = inputList->nodeTab[inputIdx++];
11346 contextNode = compoundNext(NULL, compoundContextNode);
11347 } else
11348 contextNode = compoundNext(contextNode, compoundContextNode);
11349 if (contextNode == NULL)
11350 continue;
11351 /*
11352 * Set the context for the main traversal.
11353 */
11354 xpctxt->node = contextNode;
11355 } else
11356 xpctxt->node = inputList->nodeTab[inputIdx++];
11357
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011358 if (list == NULL) {
11359 list = xmlXPathNodeSetCreate(NULL);
11360 if (list == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011361 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011362 goto error;
11363 }
11364 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011365 cur = NULL;
11366 specialNodeInSet = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011367 do {
11368 cur = next(ctxt, cur);
11369 if (cur == NULL)
11370 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011371
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011372 if (first != NULL) {
11373 if (*first == cur)
11374 break;
11375 if ((*first != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011376 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011377#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011378 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011379#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011380 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011381#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011382 {
11383 break;
11384 }
11385 }
11386 if (last != NULL) {
11387 if (*last == cur)
11388 break;
11389 if ((*last != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011390 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011391#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011392 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011393#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011394 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011395#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011396 {
11397 break;
11398 }
11399 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011400
11401 total++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011402#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011403 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
11404#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011405 switch (test) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011406 case NODE_TEST_NONE:
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011407 STRANGE
11408 goto error;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011409 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011410 if ((cur->type == type) ||
11411 ((type == NODE_TYPE_NODE) &&
11412 ((cur->type == XML_DOCUMENT_NODE) ||
11413 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11414 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000011415 (cur->type == XML_NAMESPACE_DECL) ||
11416 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +000011417 (cur->type == XML_PI_NODE) ||
11418 (cur->type == XML_COMMENT_NODE) ||
11419 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +000011420 (cur->type == XML_TEXT_NODE))) ||
11421 ((type == NODE_TYPE_TEXT) &&
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011422 (cur->type == XML_CDATA_SECTION_NODE)))
11423 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011424#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011425 nbMatches++;
11426#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011427 if (cur->type == XML_NAMESPACE_DECL)
11428 specialNodeInSet = 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011429 /*
11430 * TODO: Don't we need to use xmlXPathNodeSetAddNs()
11431 * for namespace nodes here ?
11432 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011433 addNode(list, cur);
11434 }
11435 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011436 case NODE_TEST_PI:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011437 if ((cur->type == XML_PI_NODE) &&
11438 ((name == NULL) || xmlStrEqual(name, cur->name)))
11439 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011440#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011441 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011442#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011443 addNode(list, cur);
11444 }
11445 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011446 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011447 if (axis == AXIS_ATTRIBUTE) {
11448 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011449#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011450 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011451#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011452 addNode(list, cur);
11453 }
11454 } else if (axis == AXIS_NAMESPACE) {
11455 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011456#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011457 nbMatches++;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011458#endif
11459 specialNodeInSet = 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011460 xmlXPathNodeSetAddNs(list, xpctxt->node,
11461 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011462 }
11463 } else {
11464 if (cur->type == XML_ELEMENT_NODE) {
11465 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011466#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011467 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011468#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011469 addNode(list, cur);
11470 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011471 (xmlStrEqual(URI, cur->ns->href)))
11472 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011473#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011474 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011475#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011476 addNode(list, cur);
11477 }
11478 }
11479 }
11480 break;
11481 case NODE_TEST_NS:{
11482 TODO;
11483 break;
11484 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011485 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011486 switch (cur->type) {
11487 case XML_ELEMENT_NODE:
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011488 if (xmlStrEqual(name, cur->name)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011489 if (prefix == NULL) {
11490 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011491#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011492 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011493#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011494 addNode(list, cur);
11495 }
11496 } else {
11497 if ((cur->ns != NULL) &&
11498 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011499 cur->ns->href)))
11500 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011501#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011502 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011503#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011504 addNode(list, cur);
11505 }
11506 }
11507 }
11508 break;
11509 case XML_ATTRIBUTE_NODE:{
11510 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011511
Daniel Veillardf06307e2001-07-03 10:35:50 +000011512 if (xmlStrEqual(name, attr->name)) {
11513 if (prefix == NULL) {
11514 if ((attr->ns == NULL) ||
11515 (attr->ns->prefix == NULL)) {
11516#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011517 nbMatches++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011518#endif
11519 addNode(list,
11520 (xmlNodePtr) attr);
11521 }
11522 } else {
11523 if ((attr->ns != NULL) &&
11524 (xmlStrEqual(URI,
11525 attr->ns->
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011526 href)))
11527 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011528#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011529 nbMatches++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011530#endif
11531 addNode(list,
11532 (xmlNodePtr) attr);
11533 }
11534 }
11535 }
11536 break;
11537 }
11538 case XML_NAMESPACE_DECL:
11539 if (cur->type == XML_NAMESPACE_DECL) {
11540 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011541
Daniel Veillardf06307e2001-07-03 10:35:50 +000011542 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011543 && (xmlStrEqual(ns->prefix, name)))
11544 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011545#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011546 nbMatches++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011547#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011548 specialNodeInSet = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011549 xmlXPathNodeSetAddNs(list,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011550 xpctxt->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011551 }
11552 }
11553 break;
11554 default:
11555 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011556 } /* switch (cur->type) */
11557 break; /* case NODE_TEST_NAME: */
11558 } /* switch (test) */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 } while (cur != NULL);
11560
11561 /*
11562 * If there is some predicate filtering do it now
11563 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011564 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011565 xmlXPathObjectPtr obj2;
11566
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011567 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011568 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
11569 CHECK_TYPE0(XPATH_NODESET);
11570 obj2 = valuePop(ctxt);
11571 list = obj2->nodesetval;
11572 obj2->nodesetval = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011573 xmlXPathReleaseObject(xpctxt, obj2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011574
William M. Brack2c19a7b2005-04-10 01:03:23 +000011575 if (ctxt->error != XPATH_EXPRESSION_OK) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011576 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011577 goto error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000011578 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011579 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011580 if (resultList == NULL) {
11581 resultList = list;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011582 list = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011583 } else if ((list != NULL) && (list->nodeNr > 0)) {
11584 resultList = mergeNodeSet(resultList, list);
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011585 /*
11586 * This is the list containing the current matching nodes.
11587 * Avoid massive creation/freeing and preserve it for the
11588 * next iterations.
11589 */
11590 /* If a namespace node was put it, then we need a more
11591 * time consuming cleanup.
11592 */
11593 if (specialNodeInSet)
11594 xmlXPathNodeSetClear(list);
11595 else
11596 list->nodeNr = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011597 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011598 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011599
11600 xpctxt->node = oldContextNode;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011601 /*
11602 * Cleanup the temporary list of current node-test matches.
11603 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011604 if ((list != NULL) && (list != resultList)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011605 xmlXPathFreeNodeSet(list);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011606 list = NULL;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011607 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011608
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011609#ifdef DEBUG_STEP
11610 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011611 "\nExamined %d nodes, found %d nodes at that step\n",
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011612 total, nbMatches);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011613#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011614
11615 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, resultList));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011616
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011617 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011618 /*
11619 * QUESTION TODO: What does this do and why?
11620 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011621 ctxt->value->boolval = 1;
11622 ctxt->value->user = obj->user;
11623 obj->user = NULL;
11624 obj->boolval = 0;
11625 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011626 xmlXPathReleaseObject(xpctxt, obj);
11627 return(total);
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011628
11629error:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011630 xpctxt->node = oldContextNode;
11631 xmlXPathReleaseObject(xpctxt, obj);
11632 if ((list != NULL) && (list != resultList)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011633 xmlXPathFreeNodeSet(list);
11634 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011635 if (resultList != NULL)
11636 xmlXPathFreeNodeSet(resultList);
11637 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011638}
11639
11640/**
11641 * xmlXPathNodeCollectAndTestNth:
11642 * @ctxt: the XPath Parser context
11643 * @op: the XPath precompiled step operation
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011644 * @reqpos: the requested position wrt to the axis
Daniel Veillardf06307e2001-07-03 10:35:50 +000011645 * @first: pointer to the first element in document order
11646 * @last: pointer to the last element in document order
11647 *
11648 * This is the function implementing a step: based on the current list
11649 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000011650 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +000011651 *
11652 * Pushes the new NodeSet resulting from the search.
11653 * Returns the number of node traversed
11654 */
11655static int
11656xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011657 xmlXPathStepOpPtr op, int reqpos,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011658 xmlNodePtr * first, xmlNodePtr * last)
11659{
William M. Brack78637da2003-07-31 14:47:38 +000011660 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11661 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11662 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011663 const xmlChar *prefix = op->value4;
11664 const xmlChar *name = op->value5;
11665 const xmlChar *URI = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011666 int pos; /* The current context position */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011667
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011668 int inputIdx, total = 0;
11669 xmlNodeSetPtr inputList, list;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011670 xmlXPathTraversalFunction next = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011671 xmlXPathTraversalFunctionExt compoundNext = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011672 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011673 xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011674 xmlXPathObjectPtr obj;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011675 xmlXPathContextPtr xpctxt = ctxt->context;
11676
Daniel Veillardf06307e2001-07-03 10:35:50 +000011677
11678 CHECK_TYPE0(XPATH_NODESET);
11679 obj = valuePop(ctxt);
11680 addNode = xmlXPathNodeSetAdd;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011681
Daniel Veillardf06307e2001-07-03 10:35:50 +000011682 if (prefix != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011683 URI = xmlXPathNsLookup(xpctxt, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011684 if (URI == NULL) {
11685 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011686 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011687 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011688 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011689
Daniel Veillardf06307e2001-07-03 10:35:50 +000011690#ifdef DEBUG_STEP_NTH
11691 xmlGenericError(xmlGenericErrorContext, "new step : ");
11692 if (first != NULL) {
11693 if (*first != NULL)
11694 xmlGenericError(xmlGenericErrorContext, "first = %s ",
11695 (*first)->name);
11696 else
11697 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
11698 }
11699 if (last != NULL) {
11700 if (*last != NULL)
11701 xmlGenericError(xmlGenericErrorContext, "last = %s ",
11702 (*last)->name);
11703 else
11704 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
11705 }
11706#endif
11707 switch (axis) {
11708 case AXIS_ANCESTOR:
11709#ifdef DEBUG_STEP_NTH
11710 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11711#endif
11712 first = NULL;
11713 next = xmlXPathNextAncestor;
11714 break;
11715 case AXIS_ANCESTOR_OR_SELF:
11716#ifdef DEBUG_STEP_NTH
11717 xmlGenericError(xmlGenericErrorContext,
11718 "axis 'ancestors-or-self' ");
11719#endif
11720 first = NULL;
11721 next = xmlXPathNextAncestorOrSelf;
11722 break;
11723 case AXIS_ATTRIBUTE:
11724#ifdef DEBUG_STEP_NTH
11725 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11726#endif
11727 first = NULL;
11728 last = NULL;
11729 next = xmlXPathNextAttribute;
11730 break;
11731 case AXIS_CHILD:
11732#ifdef DEBUG_STEP_NTH
11733 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11734#endif
11735 last = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011736 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11737 /*
11738 * This iterator will give us only nodes which can
11739 * hold element nodes.
11740 */
11741 compoundNext = xmlXPathNextDescendantOrSelfElemParent;
11742 }
11743 if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) {
11744 /*
11745 * Optimization if an element node type is 'element'.
11746 */
11747 next = xmlXPathNextChildElement;
11748 } else
11749 next = xmlXPathNextChild;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011750 break;
11751 case AXIS_DESCENDANT:
11752#ifdef DEBUG_STEP_NTH
11753 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11754#endif
11755 last = NULL;
11756 next = xmlXPathNextDescendant;
11757 break;
11758 case AXIS_DESCENDANT_OR_SELF:
11759#ifdef DEBUG_STEP_NTH
11760 xmlGenericError(xmlGenericErrorContext,
11761 "axis 'descendant-or-self' ");
11762#endif
11763 last = NULL;
11764 next = xmlXPathNextDescendantOrSelf;
11765 break;
11766 case AXIS_FOLLOWING:
11767#ifdef DEBUG_STEP_NTH
11768 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11769#endif
11770 last = NULL;
11771 next = xmlXPathNextFollowing;
11772 break;
11773 case AXIS_FOLLOWING_SIBLING:
11774#ifdef DEBUG_STEP_NTH
11775 xmlGenericError(xmlGenericErrorContext,
11776 "axis 'following-siblings' ");
11777#endif
11778 last = NULL;
11779 next = xmlXPathNextFollowingSibling;
11780 break;
11781 case AXIS_NAMESPACE:
11782#ifdef DEBUG_STEP_NTH
11783 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11784#endif
11785 last = NULL;
11786 first = NULL;
11787 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11788 break;
11789 case AXIS_PARENT:
11790#ifdef DEBUG_STEP_NTH
11791 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11792#endif
11793 first = NULL;
11794 next = xmlXPathNextParent;
11795 break;
11796 case AXIS_PRECEDING:
11797#ifdef DEBUG_STEP_NTH
11798 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11799#endif
11800 first = NULL;
11801 next = xmlXPathNextPrecedingInternal;
11802 break;
11803 case AXIS_PRECEDING_SIBLING:
11804#ifdef DEBUG_STEP_NTH
11805 xmlGenericError(xmlGenericErrorContext,
11806 "axis 'preceding-sibling' ");
11807#endif
11808 first = NULL;
11809 next = xmlXPathNextPrecedingSibling;
11810 break;
11811 case AXIS_SELF:
11812#ifdef DEBUG_STEP_NTH
11813 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11814#endif
11815 first = NULL;
11816 last = NULL;
11817 next = xmlXPathNextSelf;
11818 break;
11819 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011820 if (next == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011821 xmlXPathReleaseObject(xpctxt, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011822 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011823 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011824
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011825 inputList = obj->nodesetval;
11826 if ((inputList == NULL) || (inputList->nodeNr <= 0)) {
11827 xmlXPathReleaseObject(xpctxt, obj);
11828 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011829 return(0);
11830 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011831
Daniel Veillardf06307e2001-07-03 10:35:50 +000011832#ifdef DEBUG_STEP_NTH
11833 xmlGenericError(xmlGenericErrorContext,
11834 " context contains %d nodes\n", nodelist->nodeNr);
11835 switch (test) {
11836 case NODE_TEST_NONE:
11837 xmlGenericError(xmlGenericErrorContext,
11838 " searching for none !!!\n");
11839 break;
11840 case NODE_TEST_TYPE:
11841 xmlGenericError(xmlGenericErrorContext,
11842 " searching for type %d\n", type);
11843 break;
11844 case NODE_TEST_PI:
11845 xmlGenericError(xmlGenericErrorContext,
11846 " searching for PI !!!\n");
11847 break;
11848 case NODE_TEST_ALL:
11849 xmlGenericError(xmlGenericErrorContext,
11850 " searching for *\n");
11851 break;
11852 case NODE_TEST_NS:
11853 xmlGenericError(xmlGenericErrorContext,
11854 " searching for namespace %s\n",
11855 prefix);
11856 break;
11857 case NODE_TEST_NAME:
11858 xmlGenericError(xmlGenericErrorContext,
11859 " searching for name %s\n", name);
11860 if (prefix != NULL)
11861 xmlGenericError(xmlGenericErrorContext,
11862 " with namespace %s\n", prefix);
11863 break;
11864 }
11865 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11866#endif
11867 /*
11868 * 2.3 Node Tests
11869 * - For the attribute axis, the principal node type is attribute.
11870 * - For the namespace axis, the principal node type is namespace.
11871 * - For other axes, the principal node type is element.
11872 *
11873 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011874 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +000011875 * select all element children of the context node
11876 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011877 oldContextNode = xpctxt->node;
11878 addNode = xmlXPathNodeSetAddUnique;
11879 list = NULL;
11880 compoundContextNode = NULL;
11881 contextNode = NULL;
11882 inputIdx = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011883 list = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011884
11885 while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) {
11886 if (compoundNext != NULL) {
11887 /*
11888 * This is a compound traversal.
11889 */
11890 if (contextNode == NULL) {
11891 /*
11892 * Set the context for the initial traversal.
11893 */
11894 compoundContextNode = inputList->nodeTab[inputIdx++];
11895 contextNode = compoundNext(NULL, compoundContextNode);
11896 } else
11897 contextNode = compoundNext(contextNode, compoundContextNode);
11898 if (contextNode == NULL)
11899 continue;
11900 /*
11901 * Set the context for the main traversal.
11902 */
11903 xpctxt->node = contextNode;
11904 } else
11905 xpctxt->node = inputList->nodeTab[inputIdx++];
Daniel Veillardf06307e2001-07-03 10:35:50 +000011906
11907 cur = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011908 pos = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011909 do {
11910 cur = next(ctxt, cur);
11911 if (cur == NULL)
11912 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011913
11914 if (first != NULL) {
11915 if (*first == cur)
11916 break;
11917 if ((*first != NULL) &&
11918 ((total % 256) == 0) &&
11919#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11920 (xmlXPathCmpNodesExt(*first, cur) >= 0))
11921#else
11922 (xmlXPathCmpNodes(*first, cur) >= 0))
11923#endif
11924 {
11925 break;
11926 }
11927 }
11928 if (last != NULL) {
11929 if (*last == cur)
11930 break;
11931 if ((*last != NULL) &&
11932 ((total % 256) == 0) &&
11933#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11934 (xmlXPathCmpNodesExt(cur, *last) >= 0))
11935#else
11936 (xmlXPathCmpNodes(cur, *last) >= 0))
11937#endif
11938 {
11939 break;
11940 }
11941 }
11942
11943 total++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011944 switch (test) {
11945 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011946 total = 0;
11947 STRANGE
11948 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011949 case NODE_TEST_TYPE:
11950 if ((cur->type == type) ||
11951 ((type == NODE_TYPE_NODE) &&
11952 ((cur->type == XML_DOCUMENT_NODE) ||
11953 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11954 (cur->type == XML_ELEMENT_NODE) ||
11955 (cur->type == XML_PI_NODE) ||
11956 (cur->type == XML_COMMENT_NODE) ||
11957 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +000011958 (cur->type == XML_TEXT_NODE))) ||
11959 ((type == NODE_TYPE_TEXT) &&
11960 (cur->type == XML_CDATA_SECTION_NODE))) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011961 pos++;
11962 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011963 addNode(list, cur);
11964 }
11965 break;
11966 case NODE_TEST_PI:
11967 if (cur->type == XML_PI_NODE) {
11968 if ((name != NULL) &&
11969 (!xmlStrEqual(name, cur->name)))
11970 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011971 pos++;
11972 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011973 addNode(list, cur);
11974 }
11975 break;
11976 case NODE_TEST_ALL:
11977 if (axis == AXIS_ATTRIBUTE) {
11978 if (cur->type == XML_ATTRIBUTE_NODE) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011979 pos++;
11980 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011981 addNode(list, cur);
11982 }
11983 } else if (axis == AXIS_NAMESPACE) {
11984 if (cur->type == XML_NAMESPACE_DECL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011985 pos++;
11986 if (pos == reqpos)
11987 xmlXPathNodeSetAddNs(list, xpctxt->node,
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011988 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011989 }
11990 } else {
11991 if (cur->type == XML_ELEMENT_NODE) {
11992 if (prefix == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011993 pos++;
11994 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011995 addNode(list, cur);
11996 } else if ((cur->ns != NULL) &&
11997 (xmlStrEqual(URI, cur->ns->href))) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011998 pos++;
11999 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012000 addNode(list, cur);
12001 }
12002 }
12003 }
12004 break;
12005 case NODE_TEST_NS:{
12006 TODO;
12007 break;
12008 }
12009 case NODE_TEST_NAME:
12010 switch (cur->type) {
12011 case XML_ELEMENT_NODE:
12012 if (xmlStrEqual(name, cur->name)) {
12013 if (prefix == NULL) {
12014 if (cur->ns == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012015 pos++;
12016 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012017 addNode(list, cur);
12018 }
12019 } else {
12020 if ((cur->ns != NULL) &&
12021 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012022 cur->ns->href)))
12023 {
12024 pos++;
12025 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012026 addNode(list, cur);
12027 }
12028 }
12029 }
12030 break;
12031 case XML_ATTRIBUTE_NODE:{
12032 xmlAttrPtr attr = (xmlAttrPtr) cur;
12033
12034 if (xmlStrEqual(name, attr->name)) {
12035 if (prefix == NULL) {
12036 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012037 (attr->ns->prefix == NULL))
12038 {
12039 pos++;
12040 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012041 addNode(list, cur);
12042 }
12043 } else {
12044 if ((attr->ns != NULL) &&
12045 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012046 attr->ns->href)))
12047 {
12048 pos++;
12049 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012050 addNode(list, cur);
12051 }
12052 }
12053 }
12054 break;
12055 }
12056 case XML_NAMESPACE_DECL:
12057 if (cur->type == XML_NAMESPACE_DECL) {
12058 xmlNsPtr ns = (xmlNsPtr) cur;
12059
12060 if ((ns->prefix != NULL) && (name != NULL)
12061 && (xmlStrEqual(ns->prefix, name))) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012062 pos++;
12063 if (pos == reqpos)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000012064 xmlXPathNodeSetAddNs(list,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012065 xpctxt->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012066 }
12067 }
12068 break;
12069 default:
12070 break;
12071 }
12072 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012073 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012074 } while (pos < reqpos);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012075 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012076 xpctxt->node = oldContextNode;
12077
Daniel Veillardf06307e2001-07-03 10:35:50 +000012078#ifdef DEBUG_STEP_NTH
12079 xmlGenericError(xmlGenericErrorContext,
12080 "\nExamined %d nodes, found %d nodes at that step\n",
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012081 total, list->nodeNr);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012082#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012083
12084 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list));
12085
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012086 if ((obj->boolval) && (obj->user != NULL)) {
12087 ctxt->value->boolval = 1;
12088 ctxt->value->user = obj->user;
12089 obj->user = NULL;
12090 obj->boolval = 0;
12091 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012092 xmlXPathReleaseObject(xpctxt, obj);
12093 return(total);
12094
12095error:
12096 xpctxt->node = oldContextNode;
12097 xmlXPathReleaseObject(xpctxt, obj);
12098 if (list != NULL)
12099 xmlXPathFreeNodeSet(list);
12100 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012101}
12102
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012103static int
12104xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12105 xmlXPathStepOpPtr op, xmlNodePtr * first);
12106
Daniel Veillardf06307e2001-07-03 10:35:50 +000012107/**
12108 * xmlXPathCompOpEvalFirst:
12109 * @ctxt: the XPath parser context with the compiled expression
12110 * @op: an XPath compiled operation
12111 * @first: the first elem found so far
12112 *
12113 * Evaluate the Precompiled XPath operation searching only the first
12114 * element in document order
12115 *
12116 * Returns the number of examined objects.
12117 */
12118static int
12119xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12120 xmlXPathStepOpPtr op, xmlNodePtr * first)
12121{
12122 int total = 0, cur;
12123 xmlXPathCompExprPtr comp;
12124 xmlXPathObjectPtr arg1, arg2;
12125
Daniel Veillard556c6682001-10-06 09:59:51 +000012126 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012127 comp = ctxt->comp;
12128 switch (op->op) {
12129 case XPATH_OP_END:
12130 return (0);
12131 case XPATH_OP_UNION:
12132 total =
12133 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12134 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012136 if ((ctxt->value != NULL)
12137 && (ctxt->value->type == XPATH_NODESET)
12138 && (ctxt->value->nodesetval != NULL)
12139 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12140 /*
12141 * limit tree traversing to first node in the result
12142 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012143 /*
12144 * OPTIMIZE TODO: This implicitely sorts
12145 * the result, even if not needed. E.g. if the argument
12146 * of the count() function, no sorting is needed.
12147 * OPTIMIZE TODO: How do we know if the node-list wasn't
12148 * aready sorted?
12149 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012150 if (ctxt->value->nodesetval->nodeNr > 1)
12151 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012152 *first = ctxt->value->nodesetval->nodeTab[0];
12153 }
12154 cur =
12155 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12156 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012157 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012158 CHECK_TYPE0(XPATH_NODESET);
12159 arg2 = valuePop(ctxt);
12160
12161 CHECK_TYPE0(XPATH_NODESET);
12162 arg1 = valuePop(ctxt);
12163
12164 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12165 arg2->nodesetval);
12166 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012167 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012168 /* optimizer */
12169 if (total > cur)
12170 xmlXPathCompSwap(op);
12171 return (total + cur);
12172 case XPATH_OP_ROOT:
12173 xmlXPathRoot(ctxt);
12174 return (0);
12175 case XPATH_OP_NODE:
12176 if (op->ch1 != -1)
12177 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012178 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012179 if (op->ch2 != -1)
12180 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012181 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012182 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12183 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012184 return (total);
12185 case XPATH_OP_RESET:
12186 if (op->ch1 != -1)
12187 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012188 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012189 if (op->ch2 != -1)
12190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012191 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012192 ctxt->context->node = NULL;
12193 return (total);
12194 case XPATH_OP_COLLECT:{
12195 if (op->ch1 == -1)
12196 return (total);
12197
12198 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012199 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012200
12201 /*
12202 * Optimization for [n] selection where n is a number
12203 */
12204 if ((op->ch2 != -1) &&
12205 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12206 (comp->steps[op->ch2].ch1 == -1) &&
12207 (comp->steps[op->ch2].ch2 != -1) &&
12208 (comp->steps[comp->steps[op->ch2].ch2].op ==
12209 XPATH_OP_VALUE)) {
12210 xmlXPathObjectPtr val;
12211
12212 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12213 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12214 int indx = (int) val->floatval;
12215
12216 if (val->floatval == (float) indx) {
12217 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
12218 first, NULL);
12219 return (total);
12220 }
12221 }
12222 }
12223 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
12224 return (total);
12225 }
12226 case XPATH_OP_VALUE:
12227 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012228 xmlXPathCacheObjectCopy(ctxt->context,
12229 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012230 return (0);
12231 case XPATH_OP_SORT:
12232 if (op->ch1 != -1)
12233 total +=
12234 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12235 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012236 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012237 if ((ctxt->value != NULL)
12238 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012239 && (ctxt->value->nodesetval != NULL)
12240 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012241 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12242 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012243#ifdef XP_OPTIMIZED_FILTER_FIRST
12244 case XPATH_OP_FILTER:
12245 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12246 return (total);
12247#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012248 default:
12249 return (xmlXPathCompOpEval(ctxt, op));
12250 }
12251}
12252
12253/**
12254 * xmlXPathCompOpEvalLast:
12255 * @ctxt: the XPath parser context with the compiled expression
12256 * @op: an XPath compiled operation
12257 * @last: the last elem found so far
12258 *
12259 * Evaluate the Precompiled XPath operation searching only the last
12260 * element in document order
12261 *
William M. Brack08171912003-12-29 02:52:11 +000012262 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012263 */
12264static int
12265xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12266 xmlNodePtr * last)
12267{
12268 int total = 0, cur;
12269 xmlXPathCompExprPtr comp;
12270 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012271 xmlNodePtr bak;
12272 xmlDocPtr bakd;
12273 int pp;
12274 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012275
Daniel Veillard556c6682001-10-06 09:59:51 +000012276 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012277 comp = ctxt->comp;
12278 switch (op->op) {
12279 case XPATH_OP_END:
12280 return (0);
12281 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012282 bakd = ctxt->context->doc;
12283 bak = ctxt->context->node;
12284 pp = ctxt->context->proximityPosition;
12285 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012286 total =
12287 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012288 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012289 if ((ctxt->value != NULL)
12290 && (ctxt->value->type == XPATH_NODESET)
12291 && (ctxt->value->nodesetval != NULL)
12292 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12293 /*
12294 * limit tree traversing to first node in the result
12295 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012296 if (ctxt->value->nodesetval->nodeNr > 1)
12297 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012298 *last =
12299 ctxt->value->nodesetval->nodeTab[ctxt->value->
12300 nodesetval->nodeNr -
12301 1];
12302 }
William M. Brackce4fc562004-01-22 02:47:18 +000012303 ctxt->context->doc = bakd;
12304 ctxt->context->node = bak;
12305 ctxt->context->proximityPosition = pp;
12306 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012307 cur =
12308 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012309 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012310 if ((ctxt->value != NULL)
12311 && (ctxt->value->type == XPATH_NODESET)
12312 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012313 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012314 }
12315 CHECK_TYPE0(XPATH_NODESET);
12316 arg2 = valuePop(ctxt);
12317
12318 CHECK_TYPE0(XPATH_NODESET);
12319 arg1 = valuePop(ctxt);
12320
12321 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12322 arg2->nodesetval);
12323 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012324 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012325 /* optimizer */
12326 if (total > cur)
12327 xmlXPathCompSwap(op);
12328 return (total + cur);
12329 case XPATH_OP_ROOT:
12330 xmlXPathRoot(ctxt);
12331 return (0);
12332 case XPATH_OP_NODE:
12333 if (op->ch1 != -1)
12334 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012335 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012336 if (op->ch2 != -1)
12337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012338 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012339 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12340 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012341 return (total);
12342 case XPATH_OP_RESET:
12343 if (op->ch1 != -1)
12344 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012345 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012346 if (op->ch2 != -1)
12347 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012348 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012349 ctxt->context->node = NULL;
12350 return (total);
12351 case XPATH_OP_COLLECT:{
12352 if (op->ch1 == -1)
12353 return (0);
12354
12355 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012356 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012357
12358 /*
12359 * Optimization for [n] selection where n is a number
12360 */
12361 if ((op->ch2 != -1) &&
12362 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12363 (comp->steps[op->ch2].ch1 == -1) &&
12364 (comp->steps[op->ch2].ch2 != -1) &&
12365 (comp->steps[comp->steps[op->ch2].ch2].op ==
12366 XPATH_OP_VALUE)) {
12367 xmlXPathObjectPtr val;
12368
12369 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12370 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12371 int indx = (int) val->floatval;
12372
12373 if (val->floatval == (float) indx) {
12374 total +=
12375 xmlXPathNodeCollectAndTestNth(ctxt, op,
12376 indx, NULL,
12377 last);
12378 return (total);
12379 }
12380 }
12381 }
12382 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
12383 return (total);
12384 }
12385 case XPATH_OP_VALUE:
12386 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012387 xmlXPathCacheObjectCopy(ctxt->context,
12388 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012389 return (0);
12390 case XPATH_OP_SORT:
12391 if (op->ch1 != -1)
12392 total +=
12393 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12394 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012395 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012396 if ((ctxt->value != NULL)
12397 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012398 && (ctxt->value->nodesetval != NULL)
12399 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012400 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12401 return (total);
12402 default:
12403 return (xmlXPathCompOpEval(ctxt, op));
12404 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012405}
12406
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012407#ifdef XP_OPTIMIZED_FILTER_FIRST
12408static int
12409xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12410 xmlXPathStepOpPtr op, xmlNodePtr * first)
12411{
12412 int total = 0;
12413 xmlXPathCompExprPtr comp;
12414 xmlXPathObjectPtr res;
12415 xmlXPathObjectPtr obj;
12416 xmlNodeSetPtr oldset;
12417 xmlNodePtr oldnode;
12418 xmlDocPtr oldDoc;
12419 int i;
12420
12421 CHECK_ERROR0;
12422 comp = ctxt->comp;
12423 /*
12424 * Optimization for ()[last()] selection i.e. the last elem
12425 */
12426 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12427 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12428 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12429 int f = comp->steps[op->ch2].ch1;
12430
12431 if ((f != -1) &&
12432 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12433 (comp->steps[f].value5 == NULL) &&
12434 (comp->steps[f].value == 0) &&
12435 (comp->steps[f].value4 != NULL) &&
12436 (xmlStrEqual
12437 (comp->steps[f].value4, BAD_CAST "last"))) {
12438 xmlNodePtr last = NULL;
12439
12440 total +=
12441 xmlXPathCompOpEvalLast(ctxt,
12442 &comp->steps[op->ch1],
12443 &last);
12444 CHECK_ERROR0;
12445 /*
12446 * The nodeset should be in document order,
12447 * Keep only the last value
12448 */
12449 if ((ctxt->value != NULL) &&
12450 (ctxt->value->type == XPATH_NODESET) &&
12451 (ctxt->value->nodesetval != NULL) &&
12452 (ctxt->value->nodesetval->nodeTab != NULL) &&
12453 (ctxt->value->nodesetval->nodeNr > 1)) {
12454 ctxt->value->nodesetval->nodeTab[0] =
12455 ctxt->value->nodesetval->nodeTab[ctxt->
12456 value->
12457 nodesetval->
12458 nodeNr -
12459 1];
12460 ctxt->value->nodesetval->nodeNr = 1;
12461 *first = *(ctxt->value->nodesetval->nodeTab);
12462 }
12463 return (total);
12464 }
12465 }
12466
12467 if (op->ch1 != -1)
12468 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12469 CHECK_ERROR0;
12470 if (op->ch2 == -1)
12471 return (total);
12472 if (ctxt->value == NULL)
12473 return (total);
12474
12475#ifdef LIBXML_XPTR_ENABLED
12476 oldnode = ctxt->context->node;
12477 /*
12478 * Hum are we filtering the result of an XPointer expression
12479 */
12480 if (ctxt->value->type == XPATH_LOCATIONSET) {
12481 xmlXPathObjectPtr tmp = NULL;
12482 xmlLocationSetPtr newlocset = NULL;
12483 xmlLocationSetPtr oldlocset;
12484
12485 /*
12486 * Extract the old locset, and then evaluate the result of the
12487 * expression for all the element in the locset. use it to grow
12488 * up a new locset.
12489 */
12490 CHECK_TYPE0(XPATH_LOCATIONSET);
12491 obj = valuePop(ctxt);
12492 oldlocset = obj->user;
12493 ctxt->context->node = NULL;
12494
12495 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12496 ctxt->context->contextSize = 0;
12497 ctxt->context->proximityPosition = 0;
12498 if (op->ch2 != -1)
12499 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12500 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012501 if (res != NULL) {
12502 xmlXPathReleaseObject(ctxt->context, res);
12503 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012504 valuePush(ctxt, obj);
12505 CHECK_ERROR0;
12506 return (total);
12507 }
12508 newlocset = xmlXPtrLocationSetCreate(NULL);
12509
12510 for (i = 0; i < oldlocset->locNr; i++) {
12511 /*
12512 * Run the evaluation with a node list made of a
12513 * single item in the nodelocset.
12514 */
12515 ctxt->context->node = oldlocset->locTab[i]->user;
12516 ctxt->context->contextSize = oldlocset->locNr;
12517 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012518 if (tmp == NULL) {
12519 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12520 ctxt->context->node);
12521 } else {
12522 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12523 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012524 }
12525 valuePush(ctxt, tmp);
12526 if (op->ch2 != -1)
12527 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12528 if (ctxt->error != XPATH_EXPRESSION_OK) {
12529 xmlXPathFreeObject(obj);
12530 return(0);
12531 }
12532 /*
12533 * The result of the evaluation need to be tested to
12534 * decided whether the filter succeeded or not
12535 */
12536 res = valuePop(ctxt);
12537 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12538 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012539 xmlXPathCacheObjectCopy(ctxt->context,
12540 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012541 }
12542 /*
12543 * Cleanup
12544 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012545 if (res != NULL) {
12546 xmlXPathReleaseObject(ctxt->context, res);
12547 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012548 if (ctxt->value == tmp) {
12549 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012550 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012551 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012552 * REVISIT TODO: Don't create a temporary nodeset
12553 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012554 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012555 /* OLD: xmlXPathFreeObject(res); */
12556 } else
12557 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012558 ctxt->context->node = NULL;
12559 /*
12560 * Only put the first node in the result, then leave.
12561 */
12562 if (newlocset->locNr > 0) {
12563 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12564 break;
12565 }
12566 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012567 if (tmp != NULL) {
12568 xmlXPathReleaseObject(ctxt->context, tmp);
12569 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012570 /*
12571 * The result is used as the new evaluation locset.
12572 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012573 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012574 ctxt->context->node = NULL;
12575 ctxt->context->contextSize = -1;
12576 ctxt->context->proximityPosition = -1;
12577 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12578 ctxt->context->node = oldnode;
12579 return (total);
12580 }
12581#endif /* LIBXML_XPTR_ENABLED */
12582
12583 /*
12584 * Extract the old set, and then evaluate the result of the
12585 * expression for all the element in the set. use it to grow
12586 * up a new set.
12587 */
12588 CHECK_TYPE0(XPATH_NODESET);
12589 obj = valuePop(ctxt);
12590 oldset = obj->nodesetval;
12591
12592 oldnode = ctxt->context->node;
12593 oldDoc = ctxt->context->doc;
12594 ctxt->context->node = NULL;
12595
12596 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12597 ctxt->context->contextSize = 0;
12598 ctxt->context->proximityPosition = 0;
12599 /* QUESTION TODO: Why was this code commented out?
12600 if (op->ch2 != -1)
12601 total +=
12602 xmlXPathCompOpEval(ctxt,
12603 &comp->steps[op->ch2]);
12604 CHECK_ERROR0;
12605 res = valuePop(ctxt);
12606 if (res != NULL)
12607 xmlXPathFreeObject(res);
12608 */
12609 valuePush(ctxt, obj);
12610 ctxt->context->node = oldnode;
12611 CHECK_ERROR0;
12612 } else {
12613 xmlNodeSetPtr newset;
12614 xmlXPathObjectPtr tmp = NULL;
12615 /*
12616 * Initialize the new set.
12617 * Also set the xpath document in case things like
12618 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012619 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012620 newset = xmlXPathNodeSetCreate(NULL);
12621
12622 for (i = 0; i < oldset->nodeNr; i++) {
12623 /*
12624 * Run the evaluation with a node list made of
12625 * a single item in the nodeset.
12626 */
12627 ctxt->context->node = oldset->nodeTab[i];
12628 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12629 (oldset->nodeTab[i]->doc != NULL))
12630 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012631 if (tmp == NULL) {
12632 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12633 ctxt->context->node);
12634 } else {
12635 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12636 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012637 }
12638 valuePush(ctxt, tmp);
12639 ctxt->context->contextSize = oldset->nodeNr;
12640 ctxt->context->proximityPosition = i + 1;
12641 if (op->ch2 != -1)
12642 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12643 if (ctxt->error != XPATH_EXPRESSION_OK) {
12644 xmlXPathFreeNodeSet(newset);
12645 xmlXPathFreeObject(obj);
12646 return(0);
12647 }
12648 /*
12649 * The result of the evaluation needs to be tested to
12650 * decide whether the filter succeeded or not
12651 */
12652 res = valuePop(ctxt);
12653 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12654 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12655 }
12656 /*
12657 * Cleanup
12658 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012659 if (res != NULL) {
12660 xmlXPathReleaseObject(ctxt->context, res);
12661 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012662 if (ctxt->value == tmp) {
12663 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012664 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012665 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012666 * in order to avoid massive recreation inside this
12667 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012668 */
12669 xmlXPathNodeSetClear(tmp->nodesetval);
12670 } else
12671 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012672 ctxt->context->node = NULL;
12673 /*
12674 * Only put the first node in the result, then leave.
12675 */
12676 if (newset->nodeNr > 0) {
12677 *first = *(newset->nodeTab);
12678 break;
12679 }
12680 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012681 if (tmp != NULL) {
12682 xmlXPathReleaseObject(ctxt->context, tmp);
12683 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012684 /*
12685 * The result is used as the new evaluation set.
12686 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012687 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012688 ctxt->context->node = NULL;
12689 ctxt->context->contextSize = -1;
12690 ctxt->context->proximityPosition = -1;
12691 /* may want to move this past the '}' later */
12692 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012693 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012694 }
12695 ctxt->context->node = oldnode;
12696 return(total);
12697}
12698#endif /* XP_OPTIMIZED_FILTER_FIRST */
12699
Owen Taylor3473f882001-02-23 17:55:21 +000012700/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012701 * xmlXPathCompOpEval:
12702 * @ctxt: the XPath parser context with the compiled expression
12703 * @op: an XPath compiled operation
12704 *
12705 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000012706 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012707 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012708static int
12709xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12710{
12711 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012712 int equal, ret;
12713 xmlXPathCompExprPtr comp;
12714 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012715 xmlNodePtr bak;
12716 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000012717 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000012718 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012719
Daniel Veillard556c6682001-10-06 09:59:51 +000012720 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012721 comp = ctxt->comp;
12722 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012723 case XPATH_OP_END:
12724 return (0);
12725 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012726 bakd = ctxt->context->doc;
12727 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012728 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012729 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012730 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012731 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012732 xmlXPathBooleanFunction(ctxt, 1);
12733 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12734 return (total);
12735 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012736 ctxt->context->doc = bakd;
12737 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012738 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012739 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012740 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012741 if (ctxt->error) {
12742 xmlXPathFreeObject(arg2);
12743 return(0);
12744 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012745 xmlXPathBooleanFunction(ctxt, 1);
12746 arg1 = valuePop(ctxt);
12747 arg1->boolval &= arg2->boolval;
12748 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012749 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012750 return (total);
12751 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012752 bakd = ctxt->context->doc;
12753 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012754 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012755 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012756 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012757 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012758 xmlXPathBooleanFunction(ctxt, 1);
12759 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12760 return (total);
12761 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012762 ctxt->context->doc = bakd;
12763 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012764 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012765 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012766 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012767 if (ctxt->error) {
12768 xmlXPathFreeObject(arg2);
12769 return(0);
12770 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012771 xmlXPathBooleanFunction(ctxt, 1);
12772 arg1 = valuePop(ctxt);
12773 arg1->boolval |= arg2->boolval;
12774 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012775 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012776 return (total);
12777 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012778 bakd = ctxt->context->doc;
12779 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012780 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012781 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012782 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012783 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012784 ctxt->context->doc = bakd;
12785 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012786 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012787 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012788 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012789 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000012790 if (op->value)
12791 equal = xmlXPathEqualValues(ctxt);
12792 else
12793 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012794 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012795 return (total);
12796 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012797 bakd = ctxt->context->doc;
12798 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012799 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012800 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012801 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012802 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012803 ctxt->context->doc = bakd;
12804 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012805 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012806 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012807 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012808 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012809 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012810 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012811 return (total);
12812 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012813 bakd = ctxt->context->doc;
12814 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012815 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012816 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012817 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012818 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012819 if (op->ch2 != -1) {
12820 ctxt->context->doc = bakd;
12821 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012822 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012823 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012824 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012825 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012826 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012827 if (op->value == 0)
12828 xmlXPathSubValues(ctxt);
12829 else if (op->value == 1)
12830 xmlXPathAddValues(ctxt);
12831 else if (op->value == 2)
12832 xmlXPathValueFlipSign(ctxt);
12833 else if (op->value == 3) {
12834 CAST_TO_NUMBER;
12835 CHECK_TYPE0(XPATH_NUMBER);
12836 }
12837 return (total);
12838 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012839 bakd = ctxt->context->doc;
12840 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012841 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012842 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012843 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012844 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012845 ctxt->context->doc = bakd;
12846 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012847 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012848 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012849 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012850 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012851 if (op->value == 0)
12852 xmlXPathMultValues(ctxt);
12853 else if (op->value == 1)
12854 xmlXPathDivValues(ctxt);
12855 else if (op->value == 2)
12856 xmlXPathModValues(ctxt);
12857 return (total);
12858 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012859 bakd = ctxt->context->doc;
12860 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012861 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012862 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012863 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012864 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012865 ctxt->context->doc = bakd;
12866 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012867 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012868 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012869 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012870 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012871 CHECK_TYPE0(XPATH_NODESET);
12872 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012873
Daniel Veillardf06307e2001-07-03 10:35:50 +000012874 CHECK_TYPE0(XPATH_NODESET);
12875 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012876
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012877 if ((arg1->nodesetval == NULL) ||
12878 ((arg2->nodesetval != NULL) &&
12879 (arg2->nodesetval->nodeNr != 0)))
12880 {
12881 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12882 arg2->nodesetval);
12883 }
12884
Daniel Veillardf06307e2001-07-03 10:35:50 +000012885 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012886 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012887 return (total);
12888 case XPATH_OP_ROOT:
12889 xmlXPathRoot(ctxt);
12890 return (total);
12891 case XPATH_OP_NODE:
12892 if (op->ch1 != -1)
12893 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012894 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012895 if (op->ch2 != -1)
12896 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012897 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012898 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12899 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012900 return (total);
12901 case XPATH_OP_RESET:
12902 if (op->ch1 != -1)
12903 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012904 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012905 if (op->ch2 != -1)
12906 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012907 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012908 ctxt->context->node = NULL;
12909 return (total);
12910 case XPATH_OP_COLLECT:{
12911 if (op->ch1 == -1)
12912 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012913
Daniel Veillardf06307e2001-07-03 10:35:50 +000012914 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012915 CHECK_ERROR0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012916
12917 if ((op->ch2 != -1) &&
Daniel Veillardf06307e2001-07-03 10:35:50 +000012918 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12919 (comp->steps[op->ch2].ch1 == -1) &&
12920 (comp->steps[op->ch2].ch2 != -1) &&
12921 (comp->steps[comp->steps[op->ch2].ch2].op ==
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012922 XPATH_OP_VALUE))
12923 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012924 xmlXPathObjectPtr val;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012925 /*
12926 * Optimization for [n] selection where n is a number
12927 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012928 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12929 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12930 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012931
Daniel Veillardf06307e2001-07-03 10:35:50 +000012932 if (val->floatval == (float) indx) {
12933 total +=
12934 xmlXPathNodeCollectAndTestNth(ctxt, op,
12935 indx, NULL,
12936 NULL);
12937 return (total);
12938 }
12939 }
12940 }
12941 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
12942 return (total);
12943 }
12944 case XPATH_OP_VALUE:
12945 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012946 xmlXPathCacheObjectCopy(ctxt->context,
12947 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012948 return (total);
12949 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000012950 xmlXPathObjectPtr val;
12951
Daniel Veillardf06307e2001-07-03 10:35:50 +000012952 if (op->ch1 != -1)
12953 total +=
12954 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012955 if (op->value5 == NULL) {
12956 val = xmlXPathVariableLookup(ctxt->context, op->value4);
12957 if (val == NULL) {
12958 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12959 return(0);
12960 }
12961 valuePush(ctxt, val);
12962 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012963 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012964
Daniel Veillardf06307e2001-07-03 10:35:50 +000012965 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12966 if (URI == NULL) {
12967 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012968 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012969 op->value4, op->value5);
12970 return (total);
12971 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012972 val = xmlXPathVariableLookupNS(ctxt->context,
12973 op->value4, URI);
12974 if (val == NULL) {
12975 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12976 return(0);
12977 }
12978 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012979 }
12980 return (total);
12981 }
12982 case XPATH_OP_FUNCTION:{
12983 xmlXPathFunction func;
12984 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000012985 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012986
12987 if (op->ch1 != -1)
12988 total +=
12989 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012990 if (ctxt->valueNr < op->value) {
12991 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012992 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000012993 ctxt->error = XPATH_INVALID_OPERAND;
12994 return (total);
12995 }
12996 for (i = 0; i < op->value; i++)
12997 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
12998 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012999 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013000 ctxt->error = XPATH_INVALID_OPERAND;
13001 return (total);
13002 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013003 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013004 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013005 else {
13006 const xmlChar *URI = NULL;
13007
13008 if (op->value5 == NULL)
13009 func =
13010 xmlXPathFunctionLookup(ctxt->context,
13011 op->value4);
13012 else {
13013 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13014 if (URI == NULL) {
13015 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013016 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013017 op->value4, op->value5);
13018 return (total);
13019 }
13020 func = xmlXPathFunctionLookupNS(ctxt->context,
13021 op->value4, URI);
13022 }
13023 if (func == NULL) {
13024 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013025 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013026 op->value4);
13027 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013028 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013029 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013030 op->cacheURI = (void *) URI;
13031 }
13032 oldFunc = ctxt->context->function;
13033 oldFuncURI = ctxt->context->functionURI;
13034 ctxt->context->function = op->value4;
13035 ctxt->context->functionURI = op->cacheURI;
13036 func(ctxt, op->value);
13037 ctxt->context->function = oldFunc;
13038 ctxt->context->functionURI = oldFuncURI;
13039 return (total);
13040 }
13041 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013042 bakd = ctxt->context->doc;
13043 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013044 pp = ctxt->context->proximityPosition;
13045 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013046 if (op->ch1 != -1)
13047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013048 ctxt->context->contextSize = cs;
13049 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013050 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013051 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013052 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013053 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013055 ctxt->context->doc = bakd;
13056 ctxt->context->node = bak;
13057 CHECK_ERROR0;
13058 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013059 return (total);
13060 case XPATH_OP_PREDICATE:
13061 case XPATH_OP_FILTER:{
13062 xmlXPathObjectPtr res;
13063 xmlXPathObjectPtr obj, tmp;
13064 xmlNodeSetPtr newset = NULL;
13065 xmlNodeSetPtr oldset;
13066 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013067 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013068 int i;
13069
13070 /*
13071 * Optimization for ()[1] selection i.e. the first elem
13072 */
13073 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013074#ifdef XP_OPTIMIZED_FILTER_FIRST
13075 /*
13076 * FILTER TODO: Can we assume that the inner processing
13077 * will result in an ordered list if we have an
13078 * XPATH_OP_FILTER?
13079 * What about an additional field or flag on
13080 * xmlXPathObject like @sorted ? This way we wouln'd need
13081 * to assume anything, so it would be more robust and
13082 * easier to optimize.
13083 */
13084 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13085 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13086#else
13087 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13088#endif
13089 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013090 xmlXPathObjectPtr val;
13091
13092 val = comp->steps[op->ch2].value4;
13093 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13094 (val->floatval == 1.0)) {
13095 xmlNodePtr first = NULL;
13096
13097 total +=
13098 xmlXPathCompOpEvalFirst(ctxt,
13099 &comp->steps[op->ch1],
13100 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013101 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013102 /*
13103 * The nodeset should be in document order,
13104 * Keep only the first value
13105 */
13106 if ((ctxt->value != NULL) &&
13107 (ctxt->value->type == XPATH_NODESET) &&
13108 (ctxt->value->nodesetval != NULL) &&
13109 (ctxt->value->nodesetval->nodeNr > 1))
13110 ctxt->value->nodesetval->nodeNr = 1;
13111 return (total);
13112 }
13113 }
13114 /*
13115 * Optimization for ()[last()] selection i.e. the last elem
13116 */
13117 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13118 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13119 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13120 int f = comp->steps[op->ch2].ch1;
13121
13122 if ((f != -1) &&
13123 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13124 (comp->steps[f].value5 == NULL) &&
13125 (comp->steps[f].value == 0) &&
13126 (comp->steps[f].value4 != NULL) &&
13127 (xmlStrEqual
13128 (comp->steps[f].value4, BAD_CAST "last"))) {
13129 xmlNodePtr last = NULL;
13130
13131 total +=
13132 xmlXPathCompOpEvalLast(ctxt,
13133 &comp->steps[op->ch1],
13134 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013135 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013136 /*
13137 * The nodeset should be in document order,
13138 * Keep only the last value
13139 */
13140 if ((ctxt->value != NULL) &&
13141 (ctxt->value->type == XPATH_NODESET) &&
13142 (ctxt->value->nodesetval != NULL) &&
13143 (ctxt->value->nodesetval->nodeTab != NULL) &&
13144 (ctxt->value->nodesetval->nodeNr > 1)) {
13145 ctxt->value->nodesetval->nodeTab[0] =
13146 ctxt->value->nodesetval->nodeTab[ctxt->
13147 value->
13148 nodesetval->
13149 nodeNr -
13150 1];
13151 ctxt->value->nodesetval->nodeNr = 1;
13152 }
13153 return (total);
13154 }
13155 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013156 /*
13157 * Process inner predicates first.
13158 * Example "index[parent::book][1]":
13159 * ...
13160 * PREDICATE <-- we are here "[1]"
13161 * PREDICATE <-- process "[parent::book]" first
13162 * SORT
13163 * COLLECT 'parent' 'name' 'node' book
13164 * NODE
13165 * ELEM Object is a number : 1
13166 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013167 if (op->ch1 != -1)
13168 total +=
13169 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013170 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013171 if (op->ch2 == -1)
13172 return (total);
13173 if (ctxt->value == NULL)
13174 return (total);
13175
13176 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013177
13178#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013179 /*
13180 * Hum are we filtering the result of an XPointer expression
13181 */
13182 if (ctxt->value->type == XPATH_LOCATIONSET) {
13183 xmlLocationSetPtr newlocset = NULL;
13184 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013185
Daniel Veillardf06307e2001-07-03 10:35:50 +000013186 /*
13187 * Extract the old locset, and then evaluate the result of the
13188 * expression for all the element in the locset. use it to grow
13189 * up a new locset.
13190 */
13191 CHECK_TYPE0(XPATH_LOCATIONSET);
13192 obj = valuePop(ctxt);
13193 oldlocset = obj->user;
13194 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013195
Daniel Veillardf06307e2001-07-03 10:35:50 +000013196 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13197 ctxt->context->contextSize = 0;
13198 ctxt->context->proximityPosition = 0;
13199 if (op->ch2 != -1)
13200 total +=
13201 xmlXPathCompOpEval(ctxt,
13202 &comp->steps[op->ch2]);
13203 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013204 if (res != NULL) {
13205 xmlXPathReleaseObject(ctxt->context, res);
13206 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013207 valuePush(ctxt, obj);
13208 CHECK_ERROR0;
13209 return (total);
13210 }
13211 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013212
Daniel Veillardf06307e2001-07-03 10:35:50 +000013213 for (i = 0; i < oldlocset->locNr; i++) {
13214 /*
13215 * Run the evaluation with a node list made of a
13216 * single item in the nodelocset.
13217 */
13218 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013219 ctxt->context->contextSize = oldlocset->locNr;
13220 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013221 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13222 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013223 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013224
Daniel Veillardf06307e2001-07-03 10:35:50 +000013225 if (op->ch2 != -1)
13226 total +=
13227 xmlXPathCompOpEval(ctxt,
13228 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013229 if (ctxt->error != XPATH_EXPRESSION_OK) {
13230 xmlXPathFreeObject(obj);
13231 return(0);
13232 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013233
Daniel Veillardf06307e2001-07-03 10:35:50 +000013234 /*
13235 * The result of the evaluation need to be tested to
13236 * decided whether the filter succeeded or not
13237 */
13238 res = valuePop(ctxt);
13239 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13240 xmlXPtrLocationSetAdd(newlocset,
13241 xmlXPathObjectCopy
13242 (oldlocset->locTab[i]));
13243 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013244
Daniel Veillardf06307e2001-07-03 10:35:50 +000013245 /*
13246 * Cleanup
13247 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013248 if (res != NULL) {
13249 xmlXPathReleaseObject(ctxt->context, res);
13250 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013251 if (ctxt->value == tmp) {
13252 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013253 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013254 }
13255
13256 ctxt->context->node = NULL;
13257 }
13258
13259 /*
13260 * The result is used as the new evaluation locset.
13261 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013262 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 ctxt->context->node = NULL;
13264 ctxt->context->contextSize = -1;
13265 ctxt->context->proximityPosition = -1;
13266 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13267 ctxt->context->node = oldnode;
13268 return (total);
13269 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013270#endif /* LIBXML_XPTR_ENABLED */
13271
Daniel Veillardf06307e2001-07-03 10:35:50 +000013272 /*
13273 * Extract the old set, and then evaluate the result of the
13274 * expression for all the element in the set. use it to grow
13275 * up a new set.
13276 */
13277 CHECK_TYPE0(XPATH_NODESET);
13278 obj = valuePop(ctxt);
13279 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013280
Daniel Veillardf06307e2001-07-03 10:35:50 +000013281 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013282 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013283 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013284
Daniel Veillardf06307e2001-07-03 10:35:50 +000013285 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13286 ctxt->context->contextSize = 0;
13287 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013288/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013289 if (op->ch2 != -1)
13290 total +=
13291 xmlXPathCompOpEval(ctxt,
13292 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013293 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013294 res = valuePop(ctxt);
13295 if (res != NULL)
13296 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013297*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013298 valuePush(ctxt, obj);
13299 ctxt->context->node = oldnode;
13300 CHECK_ERROR0;
13301 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013302 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013303 /*
13304 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013305 * Also set the xpath document in case things like
13306 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013307 */
13308 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013309 /*
13310 * SPEC XPath 1.0:
13311 * "For each node in the node-set to be filtered, the
13312 * PredicateExpr is evaluated with that node as the
13313 * context node, with the number of nodes in the
13314 * node-set as the context size, and with the proximity
13315 * position of the node in the node-set with respect to
13316 * the axis as the context position;"
13317 * @oldset is the node-set" to be filtered.
13318 *
13319 * SPEC XPath 1.0:
13320 * "only predicates change the context position and
13321 * context size (see [2.4 Predicates])."
13322 * Example:
13323 * node-set context pos
13324 * nA 1
13325 * nB 2
13326 * nC 3
13327 * After applying predicate [position() > 1] :
13328 * node-set context pos
13329 * nB 1
13330 * nC 2
13331 *
13332 * removed the first node in the node-set, then
13333 * the context position of the
13334 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013335 for (i = 0; i < oldset->nodeNr; i++) {
13336 /*
13337 * Run the evaluation with a node list made of
13338 * a single item in the nodeset.
13339 */
13340 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013341 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13342 (oldset->nodeTab[i]->doc != NULL))
13343 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013344 if (tmp == NULL) {
13345 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13346 ctxt->context->node);
13347 } else {
13348 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13349 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013350 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 valuePush(ctxt, tmp);
13352 ctxt->context->contextSize = oldset->nodeNr;
13353 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013354 /*
13355 * Evaluate the predicate against the context node.
13356 * Can/should we optimize position() predicates
13357 * here (e.g. "[1]")?
13358 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013359 if (op->ch2 != -1)
13360 total +=
13361 xmlXPathCompOpEval(ctxt,
13362 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013363 if (ctxt->error != XPATH_EXPRESSION_OK) {
13364 xmlXPathFreeNodeSet(newset);
13365 xmlXPathFreeObject(obj);
13366 return(0);
13367 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013368
Daniel Veillardf06307e2001-07-03 10:35:50 +000013369 /*
William M. Brack08171912003-12-29 02:52:11 +000013370 * The result of the evaluation needs to be tested to
13371 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013372 */
13373 /*
13374 * OPTIMIZE TODO: Can we use
13375 * xmlXPathNodeSetAdd*Unique()* instead?
13376 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013377 res = valuePop(ctxt);
13378 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13379 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13380 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013381
Daniel Veillardf06307e2001-07-03 10:35:50 +000013382 /*
13383 * Cleanup
13384 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013385 if (res != NULL) {
13386 xmlXPathReleaseObject(ctxt->context, res);
13387 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013388 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013389 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013390 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013391 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013392 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013393 * in order to avoid massive recreation inside this
13394 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013395 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013396 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013397 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013398 ctxt->context->node = NULL;
13399 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013400 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013401 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013402 /*
13403 * The result is used as the new evaluation set.
13404 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013405 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013406 ctxt->context->node = NULL;
13407 ctxt->context->contextSize = -1;
13408 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013409 /* may want to move this past the '}' later */
13410 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013411 valuePush(ctxt,
13412 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013413 }
13414 ctxt->context->node = oldnode;
13415 return (total);
13416 }
13417 case XPATH_OP_SORT:
13418 if (op->ch1 != -1)
13419 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013420 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013421 if ((ctxt->value != NULL) &&
13422 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013423 (ctxt->value->nodesetval != NULL) &&
13424 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013425 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013426 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013427 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013428 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013429#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013430 case XPATH_OP_RANGETO:{
13431 xmlXPathObjectPtr range;
13432 xmlXPathObjectPtr res, obj;
13433 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013434 xmlLocationSetPtr newlocset = NULL;
13435 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013436 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013437 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013438
Daniel Veillardf06307e2001-07-03 10:35:50 +000013439 if (op->ch1 != -1)
13440 total +=
13441 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13442 if (op->ch2 == -1)
13443 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013444
William M. Brack08171912003-12-29 02:52:11 +000013445 if (ctxt->value->type == XPATH_LOCATIONSET) {
13446 /*
13447 * Extract the old locset, and then evaluate the result of the
13448 * expression for all the element in the locset. use it to grow
13449 * up a new locset.
13450 */
13451 CHECK_TYPE0(XPATH_LOCATIONSET);
13452 obj = valuePop(ctxt);
13453 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013454
William M. Brack08171912003-12-29 02:52:11 +000013455 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013456 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013457 ctxt->context->contextSize = 0;
13458 ctxt->context->proximityPosition = 0;
13459 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13460 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013461 if (res != NULL) {
13462 xmlXPathReleaseObject(ctxt->context, res);
13463 }
William M. Brack08171912003-12-29 02:52:11 +000013464 valuePush(ctxt, obj);
13465 CHECK_ERROR0;
13466 return (total);
13467 }
13468 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013469
William M. Brack08171912003-12-29 02:52:11 +000013470 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013471 /*
William M. Brack08171912003-12-29 02:52:11 +000013472 * Run the evaluation with a node list made of a
13473 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013474 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013475 ctxt->context->node = oldlocset->locTab[i]->user;
13476 ctxt->context->contextSize = oldlocset->locNr;
13477 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013478 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13479 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013480 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013481
Daniel Veillardf06307e2001-07-03 10:35:50 +000013482 if (op->ch2 != -1)
13483 total +=
13484 xmlXPathCompOpEval(ctxt,
13485 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013486 if (ctxt->error != XPATH_EXPRESSION_OK) {
13487 xmlXPathFreeObject(obj);
13488 return(0);
13489 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013490
Daniel Veillardf06307e2001-07-03 10:35:50 +000013491 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013492 if (res->type == XPATH_LOCATIONSET) {
13493 xmlLocationSetPtr rloc =
13494 (xmlLocationSetPtr)res->user;
13495 for (j=0; j<rloc->locNr; j++) {
13496 range = xmlXPtrNewRange(
13497 oldlocset->locTab[i]->user,
13498 oldlocset->locTab[i]->index,
13499 rloc->locTab[j]->user2,
13500 rloc->locTab[j]->index2);
13501 if (range != NULL) {
13502 xmlXPtrLocationSetAdd(newlocset, range);
13503 }
13504 }
13505 } else {
13506 range = xmlXPtrNewRangeNodeObject(
13507 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13508 if (range != NULL) {
13509 xmlXPtrLocationSetAdd(newlocset,range);
13510 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013511 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013512
Daniel Veillardf06307e2001-07-03 10:35:50 +000013513 /*
13514 * Cleanup
13515 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013516 if (res != NULL) {
13517 xmlXPathReleaseObject(ctxt->context, res);
13518 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013519 if (ctxt->value == tmp) {
13520 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013521 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013522 }
13523
13524 ctxt->context->node = NULL;
13525 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013526 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013527 CHECK_TYPE0(XPATH_NODESET);
13528 obj = valuePop(ctxt);
13529 oldset = obj->nodesetval;
13530 ctxt->context->node = NULL;
13531
13532 newlocset = xmlXPtrLocationSetCreate(NULL);
13533
13534 if (oldset != NULL) {
13535 for (i = 0; i < oldset->nodeNr; i++) {
13536 /*
13537 * Run the evaluation with a node list made of a single item
13538 * in the nodeset.
13539 */
13540 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013541 /*
13542 * OPTIMIZE TODO: Avoid recreation for every iteration.
13543 */
13544 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13545 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013546 valuePush(ctxt, tmp);
13547
13548 if (op->ch2 != -1)
13549 total +=
13550 xmlXPathCompOpEval(ctxt,
13551 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013552 if (ctxt->error != XPATH_EXPRESSION_OK) {
13553 xmlXPathFreeObject(obj);
13554 return(0);
13555 }
William M. Brack08171912003-12-29 02:52:11 +000013556
William M. Brack08171912003-12-29 02:52:11 +000013557 res = valuePop(ctxt);
13558 range =
13559 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13560 res);
13561 if (range != NULL) {
13562 xmlXPtrLocationSetAdd(newlocset, range);
13563 }
13564
13565 /*
13566 * Cleanup
13567 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013568 if (res != NULL) {
13569 xmlXPathReleaseObject(ctxt->context, res);
13570 }
William M. Brack08171912003-12-29 02:52:11 +000013571 if (ctxt->value == tmp) {
13572 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013573 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013574 }
13575
13576 ctxt->context->node = NULL;
13577 }
13578 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013579 }
13580
13581 /*
13582 * The result is used as the new evaluation set.
13583 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013584 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013585 ctxt->context->node = NULL;
13586 ctxt->context->contextSize = -1;
13587 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013588 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013589 return (total);
13590 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013591#endif /* LIBXML_XPTR_ENABLED */
13592 }
13593 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013594 "XPath: unknown precompiled operation %d\n", op->op);
13595 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013596}
13597
Daniel Veillard56de87e2005-02-16 00:22:29 +000013598#ifdef XPATH_STREAMING
13599/**
13600 * xmlXPathRunStreamEval:
13601 * @ctxt: the XPath parser context with the compiled expression
13602 *
13603 * Evaluate the Precompiled Streamable XPath expression in the given context.
13604 */
13605static xmlXPathObjectPtr
13606xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013607 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013608 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013609 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013610#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13611 int eval_all_nodes;
13612#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000013613 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013614 xmlXPathObjectPtr retval;
13615 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013616
13617 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013618
13619 if ((ctxt == NULL) || (comp == NULL))
13620 return(NULL);
13621 max_depth = xmlPatternMaxDepth(comp);
13622 if (max_depth == -1)
13623 return(NULL);
13624 if (max_depth == -2)
13625 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013626 min_depth = xmlPatternMinDepth(comp);
13627 if (min_depth == -1)
13628 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013629 from_root = xmlPatternFromRoot(comp);
13630 if (from_root < 0)
13631 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013632#if 0
13633 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13634#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013635
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013636 retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013637 if (retval == NULL)
13638 return(NULL);
13639
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013640 /*
13641 * handle the special cases of / amd . being matched
13642 */
13643 if (min_depth == 0) {
13644 if (from_root) {
13645 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
13646 } else {
13647 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
13648 }
13649 }
13650 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013651 return(retval);
13652 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013653
Daniel Veillard56de87e2005-02-16 00:22:29 +000013654 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013655 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013656 } else if (ctxt->node != NULL) {
13657 switch (ctxt->node->type) {
13658 case XML_ELEMENT_NODE:
13659 case XML_DOCUMENT_NODE:
13660 case XML_DOCUMENT_FRAG_NODE:
13661 case XML_HTML_DOCUMENT_NODE:
13662#ifdef LIBXML_DOCB_ENABLED
13663 case XML_DOCB_DOCUMENT_NODE:
13664#endif
13665 cur = ctxt->node;
13666 break;
13667 case XML_ATTRIBUTE_NODE:
13668 case XML_TEXT_NODE:
13669 case XML_CDATA_SECTION_NODE:
13670 case XML_ENTITY_REF_NODE:
13671 case XML_ENTITY_NODE:
13672 case XML_PI_NODE:
13673 case XML_COMMENT_NODE:
13674 case XML_NOTATION_NODE:
13675 case XML_DTD_NODE:
13676 case XML_DOCUMENT_TYPE_NODE:
13677 case XML_ELEMENT_DECL:
13678 case XML_ATTRIBUTE_DECL:
13679 case XML_ENTITY_DECL:
13680 case XML_NAMESPACE_DECL:
13681 case XML_XINCLUDE_START:
13682 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013683 break;
13684 }
13685 limit = cur;
13686 }
13687 if (cur == NULL)
13688 return(retval);
13689
13690 patstream = xmlPatternGetStreamCtxt(comp);
13691 if (patstream == NULL) {
13692 return(retval);
13693 }
13694
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013695#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13696 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13697#endif
13698
Daniel Veillard56de87e2005-02-16 00:22:29 +000013699 if (from_root) {
13700 ret = xmlStreamPush(patstream, NULL, NULL);
13701 if (ret < 0) {
13702 } else if (ret == 1) {
13703 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13704 }
13705 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013706 depth = 0;
13707 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013708next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013709 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013710 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013711
13712 switch (cur->type) {
13713 case XML_ELEMENT_NODE:
13714#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13715 case XML_TEXT_NODE:
13716 case XML_CDATA_SECTION_NODE:
13717 case XML_COMMENT_NODE:
13718 case XML_PI_NODE:
13719#endif
13720 if (cur->type == XML_ELEMENT_NODE) {
13721 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013722 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000013723 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013724#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13725 else if (eval_all_nodes)
13726 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13727 else
13728 break;
13729#endif
13730
13731 if (ret < 0) {
13732 /* NOP. */
13733 } else if (ret == 1) {
13734 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13735 }
13736 if ((cur->children == NULL) || (depth >= max_depth)) {
13737 ret = xmlStreamPop(patstream);
13738 while (cur->next != NULL) {
13739 cur = cur->next;
13740 if ((cur->type != XML_ENTITY_DECL) &&
13741 (cur->type != XML_DTD_NODE))
13742 goto next_node;
13743 }
13744 }
13745 default:
13746 break;
13747 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013748
13749scan_children:
13750 if ((cur->children != NULL) && (depth < max_depth)) {
13751 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013752 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000013753 */
13754 if (cur->children->type != XML_ENTITY_DECL) {
13755 cur = cur->children;
13756 depth++;
13757 /*
13758 * Skip DTDs
13759 */
13760 if (cur->type != XML_DTD_NODE)
13761 continue;
13762 }
13763 }
13764
13765 if (cur == limit)
13766 break;
13767
13768 while (cur->next != NULL) {
13769 cur = cur->next;
13770 if ((cur->type != XML_ENTITY_DECL) &&
13771 (cur->type != XML_DTD_NODE))
13772 goto next_node;
13773 }
13774
13775 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013776 cur = cur->parent;
13777 depth--;
13778 if ((cur == NULL) || (cur == limit))
13779 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013780 if (cur->type == XML_ELEMENT_NODE) {
13781 ret = xmlStreamPop(patstream);
13782 }
13783#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13784 else if ((eval_all_nodes) &&
13785 ((cur->type == XML_TEXT_NODE) ||
13786 (cur->type == XML_CDATA_SECTION_NODE) ||
13787 (cur->type == XML_COMMENT_NODE) ||
13788 (cur->type == XML_PI_NODE)))
13789 {
13790 ret = xmlStreamPop(patstream);
13791 }
13792#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013793 if (cur->next != NULL) {
13794 cur = cur->next;
13795 break;
13796 }
13797 } while (cur != NULL);
13798
13799 } while ((cur != NULL) && (depth >= 0));
13800done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013801#if 0
13802 printf("stream eval: checked %d nodes selected %d\n",
13803 nb_nodes, retval->nodesetval->nodeNr);
13804#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013805 xmlFreeStreamCtxt(patstream);
13806 return(retval);
13807}
13808#endif /* XPATH_STREAMING */
13809
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013810/**
13811 * xmlXPathRunEval:
13812 * @ctxt: the XPath parser context with the compiled expression
13813 *
13814 * Evaluate the Precompiled XPath expression in the given context.
13815 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013816static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013817xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
13818 xmlXPathCompExprPtr comp;
13819
13820 if ((ctxt == NULL) || (ctxt->comp == NULL))
13821 return;
13822
13823 if (ctxt->valueTab == NULL) {
13824 /* Allocate the value stack */
13825 ctxt->valueTab = (xmlXPathObjectPtr *)
13826 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13827 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000013828 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013829 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013830 }
13831 ctxt->valueNr = 0;
13832 ctxt->valueMax = 10;
13833 ctxt->value = NULL;
13834 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013835#ifdef XPATH_STREAMING
13836 if (ctxt->comp->stream) {
13837 xmlXPathObjectPtr ret;
13838 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
13839 if (ret != NULL) {
13840 valuePush(ctxt, ret);
13841 return;
13842 }
13843 }
13844#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013845 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013846 if(comp->last < 0) {
13847 xmlGenericError(xmlGenericErrorContext,
13848 "xmlXPathRunEval: last is less than zero\n");
13849 return;
13850 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013851 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13852}
13853
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013854/************************************************************************
13855 * *
13856 * Public interfaces *
13857 * *
13858 ************************************************************************/
13859
13860/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013861 * xmlXPathEvalPredicate:
13862 * @ctxt: the XPath context
13863 * @res: the Predicate Expression evaluation result
13864 *
13865 * Evaluate a predicate result for the current node.
13866 * A PredicateExpr is evaluated by evaluating the Expr and converting
13867 * the result to a boolean. If the result is a number, the result will
13868 * be converted to true if the number is equal to the position of the
13869 * context node in the context node list (as returned by the position
13870 * function) and will be converted to false otherwise; if the result
13871 * is not a number, then the result will be converted as if by a call
13872 * to the boolean function.
13873 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013874 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013875 */
13876int
13877xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013878 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013879 switch (res->type) {
13880 case XPATH_BOOLEAN:
13881 return(res->boolval);
13882 case XPATH_NUMBER:
13883 return(res->floatval == ctxt->proximityPosition);
13884 case XPATH_NODESET:
13885 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013886 if (res->nodesetval == NULL)
13887 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013888 return(res->nodesetval->nodeNr != 0);
13889 case XPATH_STRING:
13890 return((res->stringval != NULL) &&
13891 (xmlStrlen(res->stringval) != 0));
13892 default:
13893 STRANGE
13894 }
13895 return(0);
13896}
13897
13898/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013899 * xmlXPathEvaluatePredicateResult:
13900 * @ctxt: the XPath Parser context
13901 * @res: the Predicate Expression evaluation result
13902 *
13903 * Evaluate a predicate result for the current node.
13904 * A PredicateExpr is evaluated by evaluating the Expr and converting
13905 * the result to a boolean. If the result is a number, the result will
13906 * be converted to true if the number is equal to the position of the
13907 * context node in the context node list (as returned by the position
13908 * function) and will be converted to false otherwise; if the result
13909 * is not a number, then the result will be converted as if by a call
13910 * to the boolean function.
13911 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013912 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013913 */
13914int
13915xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13916 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013917 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013918 switch (res->type) {
13919 case XPATH_BOOLEAN:
13920 return(res->boolval);
13921 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000013922#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000013923 return((res->floatval == ctxt->context->proximityPosition) &&
13924 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000013925#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013926 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000013927#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013928 case XPATH_NODESET:
13929 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000013930 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000013931 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013932 return(res->nodesetval->nodeNr != 0);
13933 case XPATH_STRING:
13934 return((res->stringval != NULL) &&
13935 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000013936#ifdef LIBXML_XPTR_ENABLED
13937 case XPATH_LOCATIONSET:{
13938 xmlLocationSetPtr ptr = res->user;
13939 if (ptr == NULL)
13940 return(0);
13941 return (ptr->locNr != 0);
13942 }
13943#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013944 default:
13945 STRANGE
13946 }
13947 return(0);
13948}
13949
Daniel Veillard56de87e2005-02-16 00:22:29 +000013950#ifdef XPATH_STREAMING
13951/**
13952 * xmlXPathTryStreamCompile:
13953 * @ctxt: an XPath context
13954 * @str: the XPath expression
13955 *
13956 * Try to compile the XPath expression as a streamable subset.
13957 *
13958 * Returns the compiled expression or NULL if failed to compile.
13959 */
13960static xmlXPathCompExprPtr
13961xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13962 /*
13963 * Optimization: use streaming patterns when the XPath expression can
13964 * be compiled to a stream lookup
13965 */
13966 xmlPatternPtr stream;
13967 xmlXPathCompExprPtr comp;
13968 xmlDictPtr dict = NULL;
13969 const xmlChar **namespaces = NULL;
13970 xmlNsPtr ns;
13971 int i, j;
13972
13973 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13974 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013975 const xmlChar *tmp;
13976
13977 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013978 * We don't try to handle expressions using the verbose axis
13979 * specifiers ("::"), just the simplied form at this point.
13980 * Additionally, if there is no list of namespaces available and
13981 * there's a ":" in the expression, indicating a prefixed QName,
13982 * then we won't try to compile either. xmlPatterncompile() needs
13983 * to have a list of namespaces at compilation time in order to
13984 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013985 */
13986 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013987 if ((tmp != NULL) &&
13988 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13989 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013990
Daniel Veillard56de87e2005-02-16 00:22:29 +000013991 if (ctxt != NULL) {
13992 dict = ctxt->dict;
13993 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000013994 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000013995 if (namespaces == NULL) {
13996 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
13997 return(NULL);
13998 }
13999 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14000 ns = ctxt->namespaces[j];
14001 namespaces[i++] = ns->href;
14002 namespaces[i++] = ns->prefix;
14003 }
14004 namespaces[i++] = NULL;
14005 namespaces[i++] = NULL;
14006 }
14007 }
14008
William M. Brackea152c02005-06-09 18:12:28 +000014009 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14010 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014011 if (namespaces != NULL) {
14012 xmlFree((xmlChar **)namespaces);
14013 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014014 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14015 comp = xmlXPathNewCompExpr();
14016 if (comp == NULL) {
14017 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14018 return(NULL);
14019 }
14020 comp->stream = stream;
14021 comp->dict = dict;
14022 if (comp->dict)
14023 xmlDictReference(comp->dict);
14024 return(comp);
14025 }
14026 xmlFreePattern(stream);
14027 }
14028 return(NULL);
14029}
14030#endif /* XPATH_STREAMING */
14031
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014032
14033static int
14034xmlXPathCanRewriteDosExpression(xmlChar *expr)
14035{
14036 if (expr == NULL)
14037 return(0);
14038 do {
14039 if ((*expr == '/') && (*(++expr) == '/'))
14040 return(1);
14041 } while (*expr++);
14042 return(0);
14043}
14044static void
14045xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14046{
14047 /*
14048 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14049 * internal representation.
14050 */
14051 if (op->ch1 != -1) {
14052 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14053 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14054 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14055 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14056 {
14057 /*
14058 * This is an "foo"
14059 */
14060 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14061
14062 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14063 (prevop->ch1 != -1) &&
14064 ((xmlXPathAxisVal) prevop->value ==
14065 AXIS_DESCENDANT_OR_SELF) &&
14066 (prevop->ch2 == -1) &&
14067 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14068 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14069 {
14070 /*
14071 * This is a "descendant-or-self::node()" without predicates.
14072 * Eliminate it.
14073 */
14074 op->ch1 = prevop->ch1;
14075 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14076 }
14077 }
14078 if (op->ch1 != -1)
14079 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14080 }
14081 if (op->ch2 != -1)
14082 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14083}
14084
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014085/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014086 * xmlXPathCtxtCompile:
14087 * @ctxt: an XPath context
14088 * @str: the XPath expression
14089 *
14090 * Compile an XPath expression
14091 *
14092 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14093 * the caller has to free the object.
14094 */
14095xmlXPathCompExprPtr
14096xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14097 xmlXPathParserContextPtr pctxt;
14098 xmlXPathCompExprPtr comp;
14099
Daniel Veillard56de87e2005-02-16 00:22:29 +000014100#ifdef XPATH_STREAMING
14101 comp = xmlXPathTryStreamCompile(ctxt, str);
14102 if (comp != NULL)
14103 return(comp);
14104#endif
14105
Daniel Veillard4773df22004-01-23 13:15:13 +000014106 xmlXPathInit();
14107
14108 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014109 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014110
14111 if( pctxt->error != XPATH_EXPRESSION_OK )
14112 {
14113 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014114 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014115 }
14116
14117 if (*pctxt->cur != 0) {
14118 /*
14119 * aleksey: in some cases this line prints *second* error message
14120 * (see bug #78858) and probably this should be fixed.
14121 * However, we are not sure that all error messages are printed
14122 * out in other places. It's not critical so we leave it as-is for now
14123 */
14124 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14125 comp = NULL;
14126 } else {
14127 comp = pctxt->comp;
14128 pctxt->comp = NULL;
14129 }
14130 xmlXPathFreeParserContext(pctxt);
14131 if (comp != NULL) {
14132 comp->expr = xmlStrdup(str);
14133#ifdef DEBUG_EVAL_COUNTS
14134 comp->string = xmlStrdup(str);
14135 comp->nb = 0;
14136#endif
14137 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014138
14139 if ((comp->nbStep > 2) &&
14140 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14141 {
14142 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14143 }
14144
Daniel Veillard4773df22004-01-23 13:15:13 +000014145 return(comp);
14146}
14147
14148/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014149 * xmlXPathCompile:
14150 * @str: the XPath expression
14151 *
14152 * Compile an XPath expression
14153 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014154 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014155 * the caller has to free the object.
14156 */
14157xmlXPathCompExprPtr
14158xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014159 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014160}
14161
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014162/**
14163 * xmlXPathCompiledEval:
14164 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000014165 * @ctx: the XPath context
14166 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014167 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000014168 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014169 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014170 * the caller has to free the object.
14171 */
14172xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014173xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000014174 xmlXPathParserContextPtr ctxt;
14175 xmlXPathObjectPtr res, tmp, init = NULL;
14176 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000014177#ifndef LIBXML_THREAD_ENABLED
14178 static int reentance = 0;
14179#endif
Owen Taylor3473f882001-02-23 17:55:21 +000014180
William M. Brackf13f77f2004-11-12 16:03:48 +000014181 CHECK_CTXT(ctx)
14182
14183 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014184 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000014185 xmlXPathInit();
14186
Daniel Veillard81463942001-10-16 12:34:39 +000014187#ifndef LIBXML_THREAD_ENABLED
14188 reentance++;
14189 if (reentance > 1)
14190 xmlXPathDisableOptimizer = 1;
14191#endif
14192
Daniel Veillardf06307e2001-07-03 10:35:50 +000014193#ifdef DEBUG_EVAL_COUNTS
14194 comp->nb++;
14195 if ((comp->string != NULL) && (comp->nb > 100)) {
14196 fprintf(stderr, "100 x %s\n", comp->string);
14197 comp->nb = 0;
14198 }
14199#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014200 ctxt = xmlXPathCompParserContext(comp, ctx);
14201 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014202
14203 if (ctxt->value == NULL) {
14204 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014205 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000014206 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014207 } else {
14208 res = valuePop(ctxt);
14209 }
14210
Daniel Veillardf06307e2001-07-03 10:35:50 +000014211
Owen Taylor3473f882001-02-23 17:55:21 +000014212 do {
14213 tmp = valuePop(ctxt);
14214 if (tmp != NULL) {
14215 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014216 stack++;
14217 xmlXPathReleaseObject(ctx, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014218 }
14219 } while (tmp != NULL);
14220 if ((stack != 0) && (res != NULL)) {
14221 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014222 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000014223 stack);
14224 }
14225 if (ctxt->error != XPATH_EXPRESSION_OK) {
14226 xmlXPathFreeObject(res);
14227 res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014228 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014229 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014230 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014231#ifndef LIBXML_THREAD_ENABLED
14232 reentance--;
14233#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014234 return(res);
14235}
14236
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014237/**
14238 * xmlXPathEvalExpr:
14239 * @ctxt: the XPath Parser context
14240 *
14241 * Parse and evaluate an XPath expression in the given context,
14242 * then push the result on the context stack
14243 */
14244void
14245xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014246#ifdef XPATH_STREAMING
14247 xmlXPathCompExprPtr comp;
14248#endif
14249
Daniel Veillarda82b1822004-11-08 16:24:57 +000014250 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014251
14252#ifdef XPATH_STREAMING
14253 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14254 if (comp != NULL) {
14255 if (ctxt->comp != NULL)
14256 xmlXPathFreeCompExpr(ctxt->comp);
14257 ctxt->comp = comp;
14258 if (ctxt->cur != NULL)
14259 while (*ctxt->cur != 0) ctxt->cur++;
14260 } else
14261#endif
14262 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014263 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000014264 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014265 CHECK_ERROR;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000014266 xmlXPathRunEval(ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014267}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014268
14269/**
14270 * xmlXPathEval:
14271 * @str: the XPath expression
14272 * @ctx: the XPath context
14273 *
14274 * Evaluate the XPath Location Path in the given context.
14275 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014276 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014277 * the caller has to free the object.
14278 */
14279xmlXPathObjectPtr
14280xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14281 xmlXPathParserContextPtr ctxt;
14282 xmlXPathObjectPtr res, tmp, init = NULL;
14283 int stack = 0;
14284
William M. Brackf13f77f2004-11-12 16:03:48 +000014285 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014286
William M. Brackf13f77f2004-11-12 16:03:48 +000014287 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014288
14289 ctxt = xmlXPathNewParserContext(str, ctx);
14290 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014291
14292 if (ctxt->value == NULL) {
14293 xmlGenericError(xmlGenericErrorContext,
14294 "xmlXPathEval: evaluation failed\n");
14295 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014296 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14297#ifdef XPATH_STREAMING
14298 && (ctxt->comp->stream == NULL)
14299#endif
14300 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014301 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14302 res = NULL;
14303 } else {
14304 res = valuePop(ctxt);
14305 }
14306
14307 do {
14308 tmp = valuePop(ctxt);
14309 if (tmp != NULL) {
14310 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014311 stack++;
14312 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014313 }
14314 } while (tmp != NULL);
14315 if ((stack != 0) && (res != NULL)) {
14316 xmlGenericError(xmlGenericErrorContext,
14317 "xmlXPathEval: %d object left on the stack\n",
14318 stack);
14319 }
14320 if (ctxt->error != XPATH_EXPRESSION_OK) {
14321 xmlXPathFreeObject(res);
14322 res = NULL;
14323 }
14324
Owen Taylor3473f882001-02-23 17:55:21 +000014325 xmlXPathFreeParserContext(ctxt);
14326 return(res);
14327}
14328
14329/**
14330 * xmlXPathEvalExpression:
14331 * @str: the XPath expression
14332 * @ctxt: the XPath context
14333 *
14334 * Evaluate the XPath expression in the given context.
14335 *
14336 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14337 * the caller has to free the object.
14338 */
14339xmlXPathObjectPtr
14340xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14341 xmlXPathParserContextPtr pctxt;
14342 xmlXPathObjectPtr res, tmp;
14343 int stack = 0;
14344
William M. Brackf13f77f2004-11-12 16:03:48 +000014345 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014346
William M. Brackf13f77f2004-11-12 16:03:48 +000014347 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014348
14349 pctxt = xmlXPathNewParserContext(str, ctxt);
14350 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014351
14352 if (*pctxt->cur != 0) {
14353 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14354 res = NULL;
14355 } else {
14356 res = valuePop(pctxt);
14357 }
14358 do {
14359 tmp = valuePop(pctxt);
14360 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014361 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014362 stack++;
14363 }
14364 } while (tmp != NULL);
14365 if ((stack != 0) && (res != NULL)) {
14366 xmlGenericError(xmlGenericErrorContext,
14367 "xmlXPathEvalExpression: %d object left on the stack\n",
14368 stack);
14369 }
14370 xmlXPathFreeParserContext(pctxt);
14371 return(res);
14372}
14373
Daniel Veillard42766c02002-08-22 20:52:17 +000014374/************************************************************************
14375 * *
14376 * Extra functions not pertaining to the XPath spec *
14377 * *
14378 ************************************************************************/
14379/**
14380 * xmlXPathEscapeUriFunction:
14381 * @ctxt: the XPath Parser context
14382 * @nargs: the number of arguments
14383 *
14384 * Implement the escape-uri() XPath function
14385 * string escape-uri(string $str, bool $escape-reserved)
14386 *
14387 * This function applies the URI escaping rules defined in section 2 of [RFC
14388 * 2396] to the string supplied as $uri-part, which typically represents all
14389 * or part of a URI. The effect of the function is to replace any special
14390 * character in the string by an escape sequence of the form %xx%yy...,
14391 * where xxyy... is the hexadecimal representation of the octets used to
14392 * represent the character in UTF-8.
14393 *
14394 * The set of characters that are escaped depends on the setting of the
14395 * boolean argument $escape-reserved.
14396 *
14397 * If $escape-reserved is true, all characters are escaped other than lower
14398 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14399 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14400 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14401 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14402 * A-F).
14403 *
14404 * If $escape-reserved is false, the behavior differs in that characters
14405 * referred to in [RFC 2396] as reserved characters are not escaped. These
14406 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14407 *
14408 * [RFC 2396] does not define whether escaped URIs should use lower case or
14409 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14410 * compared using string comparison functions, this function must always use
14411 * the upper-case letters A-F.
14412 *
14413 * Generally, $escape-reserved should be set to true when escaping a string
14414 * that is to form a single part of a URI, and to false when escaping an
14415 * entire URI or URI reference.
14416 *
14417 * In the case of non-ascii characters, the string is encoded according to
14418 * utf-8 and then converted according to RFC 2396.
14419 *
14420 * Examples
14421 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14422 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14423 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14424 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14425 *
14426 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014427static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014428xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14429 xmlXPathObjectPtr str;
14430 int escape_reserved;
14431 xmlBufferPtr target;
14432 xmlChar *cptr;
14433 xmlChar escape[4];
14434
14435 CHECK_ARITY(2);
14436
14437 escape_reserved = xmlXPathPopBoolean(ctxt);
14438
14439 CAST_TO_STRING;
14440 str = valuePop(ctxt);
14441
14442 target = xmlBufferCreate();
14443
14444 escape[0] = '%';
14445 escape[3] = 0;
14446
14447 if (target) {
14448 for (cptr = str->stringval; *cptr; cptr++) {
14449 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14450 (*cptr >= 'a' && *cptr <= 'z') ||
14451 (*cptr >= '0' && *cptr <= '9') ||
14452 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14453 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14454 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14455 (*cptr == '%' &&
14456 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14457 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14458 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14459 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14460 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14461 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14462 (!escape_reserved &&
14463 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14464 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14465 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14466 *cptr == ','))) {
14467 xmlBufferAdd(target, cptr, 1);
14468 } else {
14469 if ((*cptr >> 4) < 10)
14470 escape[1] = '0' + (*cptr >> 4);
14471 else
14472 escape[1] = 'A' - 10 + (*cptr >> 4);
14473 if ((*cptr & 0xF) < 10)
14474 escape[2] = '0' + (*cptr & 0xF);
14475 else
14476 escape[2] = 'A' - 10 + (*cptr & 0xF);
14477
14478 xmlBufferAdd(target, &escape[0], 3);
14479 }
14480 }
14481 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014482 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14483 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014484 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014485 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014486}
14487
Owen Taylor3473f882001-02-23 17:55:21 +000014488/**
14489 * xmlXPathRegisterAllFunctions:
14490 * @ctxt: the XPath context
14491 *
14492 * Registers all default XPath functions in this context
14493 */
14494void
14495xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14496{
14497 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14498 xmlXPathBooleanFunction);
14499 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14500 xmlXPathCeilingFunction);
14501 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14502 xmlXPathCountFunction);
14503 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14504 xmlXPathConcatFunction);
14505 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14506 xmlXPathContainsFunction);
14507 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14508 xmlXPathIdFunction);
14509 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14510 xmlXPathFalseFunction);
14511 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14512 xmlXPathFloorFunction);
14513 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14514 xmlXPathLastFunction);
14515 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14516 xmlXPathLangFunction);
14517 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14518 xmlXPathLocalNameFunction);
14519 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14520 xmlXPathNotFunction);
14521 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14522 xmlXPathNameFunction);
14523 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14524 xmlXPathNamespaceURIFunction);
14525 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14526 xmlXPathNormalizeFunction);
14527 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14528 xmlXPathNumberFunction);
14529 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14530 xmlXPathPositionFunction);
14531 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14532 xmlXPathRoundFunction);
14533 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14534 xmlXPathStringFunction);
14535 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14536 xmlXPathStringLengthFunction);
14537 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14538 xmlXPathStartsWithFunction);
14539 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14540 xmlXPathSubstringFunction);
14541 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14542 xmlXPathSubstringBeforeFunction);
14543 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14544 xmlXPathSubstringAfterFunction);
14545 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14546 xmlXPathSumFunction);
14547 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14548 xmlXPathTrueFunction);
14549 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14550 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014551
14552 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14553 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14554 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014555}
14556
14557#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014558#define bottom_xpath
14559#include "elfgcchack.h"