blob: 17bdee363aa91602444e6e9137f202743f514fa7 [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
571
572typedef struct _xmlXPathStepOp xmlXPathStepOp;
573typedef xmlXPathStepOp *xmlXPathStepOpPtr;
574struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000575 xmlXPathOp op; /* The identifier of the operation */
576 int ch1; /* First child */
577 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000578 int value;
579 int value2;
580 int value3;
581 void *value4;
582 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000583 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000584 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000585};
586
587struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000588 int nbStep; /* Number of steps in this expression */
589 int maxStep; /* Maximum number of steps allocated */
590 xmlXPathStepOp *steps; /* ops for computation of this expression */
591 int last; /* index of last step in expression */
592 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000593 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000594#ifdef DEBUG_EVAL_COUNTS
595 int nb;
596 xmlChar *string;
597#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000598#ifdef XPATH_STREAMING
599 xmlPatternPtr stream;
600#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000601};
602
603/************************************************************************
604 * *
605 * Parser Type functions *
606 * *
607 ************************************************************************/
608
609/**
610 * xmlXPathNewCompExpr:
611 *
612 * Create a new Xpath component
613 *
614 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
615 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000616static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000617xmlXPathNewCompExpr(void) {
618 xmlXPathCompExprPtr cur;
619
620 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
621 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000622 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000623 return(NULL);
624 }
625 memset(cur, 0, sizeof(xmlXPathCompExpr));
626 cur->maxStep = 10;
627 cur->nbStep = 0;
628 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
629 sizeof(xmlXPathStepOp));
630 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000631 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000632 xmlFree(cur);
633 return(NULL);
634 }
635 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
636 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000637#ifdef DEBUG_EVAL_COUNTS
638 cur->nb = 0;
639#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000640 return(cur);
641}
642
643/**
644 * xmlXPathFreeCompExpr:
645 * @comp: an XPATH comp
646 *
647 * Free up the memory allocated by @comp
648 */
649void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000650xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
651{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000652 xmlXPathStepOpPtr op;
653 int i;
654
655 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000656 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000657 if (comp->dict == NULL) {
658 for (i = 0; i < comp->nbStep; i++) {
659 op = &comp->steps[i];
660 if (op->value4 != NULL) {
661 if (op->op == XPATH_OP_VALUE)
662 xmlXPathFreeObject(op->value4);
663 else
664 xmlFree(op->value4);
665 }
666 if (op->value5 != NULL)
667 xmlFree(op->value5);
668 }
669 } else {
670 for (i = 0; i < comp->nbStep; i++) {
671 op = &comp->steps[i];
672 if (op->value4 != NULL) {
673 if (op->op == XPATH_OP_VALUE)
674 xmlXPathFreeObject(op->value4);
675 }
676 }
677 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000678 }
679 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000680 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000681 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000682#ifdef DEBUG_EVAL_COUNTS
683 if (comp->string != NULL) {
684 xmlFree(comp->string);
685 }
686#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000687#ifdef XPATH_STREAMING
688 if (comp->stream != NULL) {
689 xmlFreePatternList(comp->stream);
690 }
691#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000692 if (comp->expr != NULL) {
693 xmlFree(comp->expr);
694 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000695
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000696 xmlFree(comp);
697}
698
699/**
700 * xmlXPathCompExprAdd:
701 * @comp: the compiled expression
702 * @ch1: first child index
703 * @ch2: second child index
704 * @op: an op
705 * @value: the first int value
706 * @value2: the second int value
707 * @value3: the third int value
708 * @value4: the first string value
709 * @value5: the second string value
710 *
William M. Brack08171912003-12-29 02:52:11 +0000711 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000712 *
713 * Returns -1 in case of failure, the index otherwise
714 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000715static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000716xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
717 xmlXPathOp op, int value,
718 int value2, int value3, void *value4, void *value5) {
719 if (comp->nbStep >= comp->maxStep) {
720 xmlXPathStepOp *real;
721
722 comp->maxStep *= 2;
723 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
724 comp->maxStep * sizeof(xmlXPathStepOp));
725 if (real == NULL) {
726 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000727 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000728 return(-1);
729 }
730 comp->steps = real;
731 }
732 comp->last = comp->nbStep;
733 comp->steps[comp->nbStep].ch1 = ch1;
734 comp->steps[comp->nbStep].ch2 = ch2;
735 comp->steps[comp->nbStep].op = op;
736 comp->steps[comp->nbStep].value = value;
737 comp->steps[comp->nbStep].value2 = value2;
738 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000739 if ((comp->dict != NULL) &&
740 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
741 (op == XPATH_OP_COLLECT))) {
742 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000743 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000744 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000745 xmlFree(value4);
746 } else
747 comp->steps[comp->nbStep].value4 = NULL;
748 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000749 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000750 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000751 xmlFree(value5);
752 } else
753 comp->steps[comp->nbStep].value5 = NULL;
754 } else {
755 comp->steps[comp->nbStep].value4 = value4;
756 comp->steps[comp->nbStep].value5 = value5;
757 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000758 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000759 return(comp->nbStep++);
760}
761
Daniel Veillardf06307e2001-07-03 10:35:50 +0000762/**
763 * xmlXPathCompSwap:
764 * @comp: the compiled expression
765 * @op: operation index
766 *
767 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000768 */
769static void
770xmlXPathCompSwap(xmlXPathStepOpPtr op) {
771 int tmp;
772
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000773#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000774 /*
775 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000776 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000777 * application
778 */
779 if (xmlXPathDisableOptimizer)
780 return;
781#endif
782
Daniel Veillardf06307e2001-07-03 10:35:50 +0000783 tmp = op->ch1;
784 op->ch1 = op->ch2;
785 op->ch2 = tmp;
786}
787
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000788#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
789 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
790 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000791#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
792 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
793 (op), (val), (val2), (val3), (val4), (val5))
794
795#define PUSH_LEAVE_EXPR(op, val, val2) \
796xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
797
798#define PUSH_UNARY_EXPR(op, ch, val, val2) \
799xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
800
801#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000802xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
803 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000804
805/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000806 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000807 * XPath object cache structures *
808 * *
809 ************************************************************************/
810
811/* #define XP_DEFAULT_CACHE_ON */
812
813#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->objCache != NULL))
814
815typedef struct _xmlXPathObjectCache xmlXPathObjectCache;
816typedef xmlXPathObjectCache *xmlXPathObjectCachePtr;
817struct _xmlXPathObjectCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000818 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
819 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
820 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
821 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
822 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000823 int maxNodeset;
824 int maxString;
825 int maxBoolean;
826 int maxNumber;
827 int maxMisc;
828#ifdef XP_DEBUG_OBJ_USAGE
829 int dbgCachedAll;
830 int dbgCachedNodeset;
831 int dbgCachedString;
832 int dbgCachedBool;
833 int dbgCachedNumber;
834 int dbgCachedPoint;
835 int dbgCachedRange;
836 int dbgCachedLocset;
837 int dbgCachedUsers;
838 int dbgCachedXSLTTree;
839 int dbgCachedUndefined;
840
841
842 int dbgReusedAll;
843 int dbgReusedNodeset;
844 int dbgReusedString;
845 int dbgReusedBool;
846 int dbgReusedNumber;
847 int dbgReusedPoint;
848 int dbgReusedRange;
849 int dbgReusedLocset;
850 int dbgReusedUsers;
851 int dbgReusedXSLTTree;
852 int dbgReusedUndefined;
853
854#endif
855};
856
857/************************************************************************
858 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000859 * Debugging related functions *
860 * *
861 ************************************************************************/
862
Owen Taylor3473f882001-02-23 17:55:21 +0000863#define STRANGE \
864 xmlGenericError(xmlGenericErrorContext, \
865 "Internal error at %s:%d\n", \
866 __FILE__, __LINE__);
867
868#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000869static void
870xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000871 int i;
872 char shift[100];
873
874 for (i = 0;((i < depth) && (i < 25));i++)
875 shift[2 * i] = shift[2 * i + 1] = ' ';
876 shift[2 * i] = shift[2 * i + 1] = 0;
877 if (cur == NULL) {
878 fprintf(output, shift);
879 fprintf(output, "Node is NULL !\n");
880 return;
881
882 }
883
884 if ((cur->type == XML_DOCUMENT_NODE) ||
885 (cur->type == XML_HTML_DOCUMENT_NODE)) {
886 fprintf(output, shift);
887 fprintf(output, " /\n");
888 } else if (cur->type == XML_ATTRIBUTE_NODE)
889 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
890 else
891 xmlDebugDumpOneNode(output, cur, depth);
892}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000893static void
894xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000895 xmlNodePtr tmp;
896 int i;
897 char shift[100];
898
899 for (i = 0;((i < depth) && (i < 25));i++)
900 shift[2 * i] = shift[2 * i + 1] = ' ';
901 shift[2 * i] = shift[2 * i + 1] = 0;
902 if (cur == NULL) {
903 fprintf(output, shift);
904 fprintf(output, "Node is NULL !\n");
905 return;
906
907 }
908
909 while (cur != NULL) {
910 tmp = cur;
911 cur = cur->next;
912 xmlDebugDumpOneNode(output, tmp, depth);
913 }
914}
Owen Taylor3473f882001-02-23 17:55:21 +0000915
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000916static void
917xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000918 int i;
919 char shift[100];
920
921 for (i = 0;((i < depth) && (i < 25));i++)
922 shift[2 * i] = shift[2 * i + 1] = ' ';
923 shift[2 * i] = shift[2 * i + 1] = 0;
924
925 if (cur == NULL) {
926 fprintf(output, shift);
927 fprintf(output, "NodeSet is NULL !\n");
928 return;
929
930 }
931
Daniel Veillard911f49a2001-04-07 15:39:35 +0000932 if (cur != NULL) {
933 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
934 for (i = 0;i < cur->nodeNr;i++) {
935 fprintf(output, shift);
936 fprintf(output, "%d", i + 1);
937 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
938 }
Owen Taylor3473f882001-02-23 17:55:21 +0000939 }
940}
941
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000942static void
943xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000944 int i;
945 char shift[100];
946
947 for (i = 0;((i < depth) && (i < 25));i++)
948 shift[2 * i] = shift[2 * i + 1] = ' ';
949 shift[2 * i] = shift[2 * i + 1] = 0;
950
951 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
952 fprintf(output, shift);
953 fprintf(output, "Value Tree is NULL !\n");
954 return;
955
956 }
957
958 fprintf(output, shift);
959 fprintf(output, "%d", i + 1);
960 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
961}
Owen Taylor3473f882001-02-23 17:55:21 +0000962#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000963static void
964xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000965 int i;
966 char shift[100];
967
968 for (i = 0;((i < depth) && (i < 25));i++)
969 shift[2 * i] = shift[2 * i + 1] = ' ';
970 shift[2 * i] = shift[2 * i + 1] = 0;
971
972 if (cur == NULL) {
973 fprintf(output, shift);
974 fprintf(output, "LocationSet is NULL !\n");
975 return;
976
977 }
978
979 for (i = 0;i < cur->locNr;i++) {
980 fprintf(output, shift);
981 fprintf(output, "%d : ", i + 1);
982 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
983 }
984}
Daniel Veillard017b1082001-06-21 11:20:21 +0000985#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000986
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000987/**
988 * xmlXPathDebugDumpObject:
989 * @output: the FILE * to dump the output
990 * @cur: the object to inspect
991 * @depth: indentation level
992 *
993 * Dump the content of the object for debugging purposes
994 */
995void
996xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000997 int i;
998 char shift[100];
999
Daniel Veillarda82b1822004-11-08 16:24:57 +00001000 if (output == NULL) return;
1001
Owen Taylor3473f882001-02-23 17:55:21 +00001002 for (i = 0;((i < depth) && (i < 25));i++)
1003 shift[2 * i] = shift[2 * i + 1] = ' ';
1004 shift[2 * i] = shift[2 * i + 1] = 0;
1005
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001006
1007 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001008
1009 if (cur == NULL) {
1010 fprintf(output, "Object is empty (NULL)\n");
1011 return;
1012 }
1013 switch(cur->type) {
1014 case XPATH_UNDEFINED:
1015 fprintf(output, "Object is uninitialized\n");
1016 break;
1017 case XPATH_NODESET:
1018 fprintf(output, "Object is a Node Set :\n");
1019 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1020 break;
1021 case XPATH_XSLT_TREE:
1022 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001023 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001024 break;
1025 case XPATH_BOOLEAN:
1026 fprintf(output, "Object is a Boolean : ");
1027 if (cur->boolval) fprintf(output, "true\n");
1028 else fprintf(output, "false\n");
1029 break;
1030 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001031 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001032 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001033 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001034 break;
1035 case -1:
1036 fprintf(output, "Object is a number : -Infinity\n");
1037 break;
1038 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001039 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001040 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001041 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1042 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001043 } else {
1044 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1045 }
1046 }
Owen Taylor3473f882001-02-23 17:55:21 +00001047 break;
1048 case XPATH_STRING:
1049 fprintf(output, "Object is a string : ");
1050 xmlDebugDumpString(output, cur->stringval);
1051 fprintf(output, "\n");
1052 break;
1053 case XPATH_POINT:
1054 fprintf(output, "Object is a point : index %d in node", cur->index);
1055 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1056 fprintf(output, "\n");
1057 break;
1058 case XPATH_RANGE:
1059 if ((cur->user2 == NULL) ||
1060 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1061 fprintf(output, "Object is a collapsed range :\n");
1062 fprintf(output, shift);
1063 if (cur->index >= 0)
1064 fprintf(output, "index %d in ", cur->index);
1065 fprintf(output, "node\n");
1066 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1067 depth + 1);
1068 } else {
1069 fprintf(output, "Object is a range :\n");
1070 fprintf(output, shift);
1071 fprintf(output, "From ");
1072 if (cur->index >= 0)
1073 fprintf(output, "index %d in ", cur->index);
1074 fprintf(output, "node\n");
1075 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1076 depth + 1);
1077 fprintf(output, shift);
1078 fprintf(output, "To ");
1079 if (cur->index2 >= 0)
1080 fprintf(output, "index %d in ", cur->index2);
1081 fprintf(output, "node\n");
1082 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1083 depth + 1);
1084 fprintf(output, "\n");
1085 }
1086 break;
1087 case XPATH_LOCATIONSET:
1088#if defined(LIBXML_XPTR_ENABLED)
1089 fprintf(output, "Object is a Location Set:\n");
1090 xmlXPathDebugDumpLocationSet(output,
1091 (xmlLocationSetPtr) cur->user, depth);
1092#endif
1093 break;
1094 case XPATH_USERS:
1095 fprintf(output, "Object is user defined\n");
1096 break;
1097 }
1098}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001099
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001100static void
1101xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001102 xmlXPathStepOpPtr op, int depth) {
1103 int i;
1104 char shift[100];
1105
1106 for (i = 0;((i < depth) && (i < 25));i++)
1107 shift[2 * i] = shift[2 * i + 1] = ' ';
1108 shift[2 * i] = shift[2 * i + 1] = 0;
1109
1110 fprintf(output, shift);
1111 if (op == NULL) {
1112 fprintf(output, "Step is NULL\n");
1113 return;
1114 }
1115 switch (op->op) {
1116 case XPATH_OP_END:
1117 fprintf(output, "END"); break;
1118 case XPATH_OP_AND:
1119 fprintf(output, "AND"); break;
1120 case XPATH_OP_OR:
1121 fprintf(output, "OR"); break;
1122 case XPATH_OP_EQUAL:
1123 if (op->value)
1124 fprintf(output, "EQUAL =");
1125 else
1126 fprintf(output, "EQUAL !=");
1127 break;
1128 case XPATH_OP_CMP:
1129 if (op->value)
1130 fprintf(output, "CMP <");
1131 else
1132 fprintf(output, "CMP >");
1133 if (!op->value2)
1134 fprintf(output, "=");
1135 break;
1136 case XPATH_OP_PLUS:
1137 if (op->value == 0)
1138 fprintf(output, "PLUS -");
1139 else if (op->value == 1)
1140 fprintf(output, "PLUS +");
1141 else if (op->value == 2)
1142 fprintf(output, "PLUS unary -");
1143 else if (op->value == 3)
1144 fprintf(output, "PLUS unary - -");
1145 break;
1146 case XPATH_OP_MULT:
1147 if (op->value == 0)
1148 fprintf(output, "MULT *");
1149 else if (op->value == 1)
1150 fprintf(output, "MULT div");
1151 else
1152 fprintf(output, "MULT mod");
1153 break;
1154 case XPATH_OP_UNION:
1155 fprintf(output, "UNION"); break;
1156 case XPATH_OP_ROOT:
1157 fprintf(output, "ROOT"); break;
1158 case XPATH_OP_NODE:
1159 fprintf(output, "NODE"); break;
1160 case XPATH_OP_RESET:
1161 fprintf(output, "RESET"); break;
1162 case XPATH_OP_SORT:
1163 fprintf(output, "SORT"); break;
1164 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001165 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1166 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1167 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001168 const xmlChar *prefix = op->value4;
1169 const xmlChar *name = op->value5;
1170
1171 fprintf(output, "COLLECT ");
1172 switch (axis) {
1173 case AXIS_ANCESTOR:
1174 fprintf(output, " 'ancestors' "); break;
1175 case AXIS_ANCESTOR_OR_SELF:
1176 fprintf(output, " 'ancestors-or-self' "); break;
1177 case AXIS_ATTRIBUTE:
1178 fprintf(output, " 'attributes' "); break;
1179 case AXIS_CHILD:
1180 fprintf(output, " 'child' "); break;
1181 case AXIS_DESCENDANT:
1182 fprintf(output, " 'descendant' "); break;
1183 case AXIS_DESCENDANT_OR_SELF:
1184 fprintf(output, " 'descendant-or-self' "); break;
1185 case AXIS_FOLLOWING:
1186 fprintf(output, " 'following' "); break;
1187 case AXIS_FOLLOWING_SIBLING:
1188 fprintf(output, " 'following-siblings' "); break;
1189 case AXIS_NAMESPACE:
1190 fprintf(output, " 'namespace' "); break;
1191 case AXIS_PARENT:
1192 fprintf(output, " 'parent' "); break;
1193 case AXIS_PRECEDING:
1194 fprintf(output, " 'preceding' "); break;
1195 case AXIS_PRECEDING_SIBLING:
1196 fprintf(output, " 'preceding-sibling' "); break;
1197 case AXIS_SELF:
1198 fprintf(output, " 'self' "); break;
1199 }
1200 switch (test) {
1201 case NODE_TEST_NONE:
1202 fprintf(output, "'none' "); break;
1203 case NODE_TEST_TYPE:
1204 fprintf(output, "'type' "); break;
1205 case NODE_TEST_PI:
1206 fprintf(output, "'PI' "); break;
1207 case NODE_TEST_ALL:
1208 fprintf(output, "'all' "); break;
1209 case NODE_TEST_NS:
1210 fprintf(output, "'namespace' "); break;
1211 case NODE_TEST_NAME:
1212 fprintf(output, "'name' "); break;
1213 }
1214 switch (type) {
1215 case NODE_TYPE_NODE:
1216 fprintf(output, "'node' "); break;
1217 case NODE_TYPE_COMMENT:
1218 fprintf(output, "'comment' "); break;
1219 case NODE_TYPE_TEXT:
1220 fprintf(output, "'text' "); break;
1221 case NODE_TYPE_PI:
1222 fprintf(output, "'PI' "); break;
1223 }
1224 if (prefix != NULL)
1225 fprintf(output, "%s:", prefix);
1226 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001227 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001228 break;
1229
1230 }
1231 case XPATH_OP_VALUE: {
1232 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1233
1234 fprintf(output, "ELEM ");
1235 xmlXPathDebugDumpObject(output, object, 0);
1236 goto finish;
1237 }
1238 case XPATH_OP_VARIABLE: {
1239 const xmlChar *prefix = op->value5;
1240 const xmlChar *name = op->value4;
1241
1242 if (prefix != NULL)
1243 fprintf(output, "VARIABLE %s:%s", prefix, name);
1244 else
1245 fprintf(output, "VARIABLE %s", name);
1246 break;
1247 }
1248 case XPATH_OP_FUNCTION: {
1249 int nbargs = op->value;
1250 const xmlChar *prefix = op->value5;
1251 const xmlChar *name = op->value4;
1252
1253 if (prefix != NULL)
1254 fprintf(output, "FUNCTION %s:%s(%d args)",
1255 prefix, name, nbargs);
1256 else
1257 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1258 break;
1259 }
1260 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1261 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001262 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001263#ifdef LIBXML_XPTR_ENABLED
1264 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1265#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001266 default:
1267 fprintf(output, "UNKNOWN %d\n", op->op); return;
1268 }
1269 fprintf(output, "\n");
1270finish:
1271 if (op->ch1 >= 0)
1272 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1273 if (op->ch2 >= 0)
1274 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1275}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001276
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001277/**
1278 * xmlXPathDebugDumpCompExpr:
1279 * @output: the FILE * for the output
1280 * @comp: the precompiled XPath expression
1281 * @depth: the indentation level.
1282 *
1283 * Dumps the tree of the compiled XPath expression.
1284 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001285void
1286xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1287 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001288 int i;
1289 char shift[100];
1290
Daniel Veillarda82b1822004-11-08 16:24:57 +00001291 if ((output == NULL) || (comp == NULL)) return;
1292
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001293 for (i = 0;((i < depth) && (i < 25));i++)
1294 shift[2 * i] = shift[2 * i + 1] = ' ';
1295 shift[2 * i] = shift[2 * i + 1] = 0;
1296
1297 fprintf(output, shift);
1298
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001299 fprintf(output, "Compiled Expression : %d elements\n",
1300 comp->nbStep);
1301 i = comp->last;
1302 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1303}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001304
1305#ifdef XP_DEBUG_OBJ_USAGE
1306
1307/*
1308* XPath object usage related debugging variables.
1309*/
1310static int xmlXPathDebugObjCounterUndefined = 0;
1311static int xmlXPathDebugObjCounterNodeset = 0;
1312static int xmlXPathDebugObjCounterBool = 0;
1313static int xmlXPathDebugObjCounterNumber = 0;
1314static int xmlXPathDebugObjCounterString = 0;
1315static int xmlXPathDebugObjCounterPoint = 0;
1316static int xmlXPathDebugObjCounterRange = 0;
1317static int xmlXPathDebugObjCounterLocset = 0;
1318static int xmlXPathDebugObjCounterUsers = 0;
1319static int xmlXPathDebugObjCounterXSLTTree = 0;
1320static int xmlXPathDebugObjCounterAll = 0;
1321
1322static int xmlXPathDebugObjTotalUndefined = 0;
1323static int xmlXPathDebugObjTotalNodeset = 0;
1324static int xmlXPathDebugObjTotalBool = 0;
1325static int xmlXPathDebugObjTotalNumber = 0;
1326static int xmlXPathDebugObjTotalString = 0;
1327static int xmlXPathDebugObjTotalPoint = 0;
1328static int xmlXPathDebugObjTotalRange = 0;
1329static int xmlXPathDebugObjTotalLocset = 0;
1330static int xmlXPathDebugObjTotalUsers = 0;
1331static int xmlXPathDebugObjTotalXSLTTree = 0;
1332static int xmlXPathDebugObjTotalAll = 0;
1333
1334static int xmlXPathDebugObjMaxUndefined = 0;
1335static int xmlXPathDebugObjMaxNodeset = 0;
1336static int xmlXPathDebugObjMaxBool = 0;
1337static int xmlXPathDebugObjMaxNumber = 0;
1338static int xmlXPathDebugObjMaxString = 0;
1339static int xmlXPathDebugObjMaxPoint = 0;
1340static int xmlXPathDebugObjMaxRange = 0;
1341static int xmlXPathDebugObjMaxLocset = 0;
1342static int xmlXPathDebugObjMaxUsers = 0;
1343static int xmlXPathDebugObjMaxXSLTTree = 0;
1344static int xmlXPathDebugObjMaxAll = 0;
1345
1346/* REVISIT TODO: Make this static when committing */
1347static void
1348xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1349{
1350 if (ctxt != NULL) {
1351 if (ctxt->objCache != NULL) {
1352 xmlXPathObjectCachePtr cache =
1353 (xmlXPathObjectCachePtr) ctxt->objCache;
1354
1355 cache->dbgCachedAll = 0;
1356 cache->dbgCachedNodeset = 0;
1357 cache->dbgCachedString = 0;
1358 cache->dbgCachedBool = 0;
1359 cache->dbgCachedNumber = 0;
1360 cache->dbgCachedPoint = 0;
1361 cache->dbgCachedRange = 0;
1362 cache->dbgCachedLocset = 0;
1363 cache->dbgCachedUsers = 0;
1364 cache->dbgCachedXSLTTree = 0;
1365 cache->dbgCachedUndefined = 0;
1366
1367 cache->dbgReusedAll = 0;
1368 cache->dbgReusedNodeset = 0;
1369 cache->dbgReusedString = 0;
1370 cache->dbgReusedBool = 0;
1371 cache->dbgReusedNumber = 0;
1372 cache->dbgReusedPoint = 0;
1373 cache->dbgReusedRange = 0;
1374 cache->dbgReusedLocset = 0;
1375 cache->dbgReusedUsers = 0;
1376 cache->dbgReusedXSLTTree = 0;
1377 cache->dbgReusedUndefined = 0;
1378 }
1379 }
1380
1381 xmlXPathDebugObjCounterUndefined = 0;
1382 xmlXPathDebugObjCounterNodeset = 0;
1383 xmlXPathDebugObjCounterBool = 0;
1384 xmlXPathDebugObjCounterNumber = 0;
1385 xmlXPathDebugObjCounterString = 0;
1386 xmlXPathDebugObjCounterPoint = 0;
1387 xmlXPathDebugObjCounterRange = 0;
1388 xmlXPathDebugObjCounterLocset = 0;
1389 xmlXPathDebugObjCounterUsers = 0;
1390 xmlXPathDebugObjCounterXSLTTree = 0;
1391 xmlXPathDebugObjCounterAll = 0;
1392
1393 xmlXPathDebugObjTotalUndefined = 0;
1394 xmlXPathDebugObjTotalNodeset = 0;
1395 xmlXPathDebugObjTotalBool = 0;
1396 xmlXPathDebugObjTotalNumber = 0;
1397 xmlXPathDebugObjTotalString = 0;
1398 xmlXPathDebugObjTotalPoint = 0;
1399 xmlXPathDebugObjTotalRange = 0;
1400 xmlXPathDebugObjTotalLocset = 0;
1401 xmlXPathDebugObjTotalUsers = 0;
1402 xmlXPathDebugObjTotalXSLTTree = 0;
1403 xmlXPathDebugObjTotalAll = 0;
1404
1405 xmlXPathDebugObjMaxUndefined = 0;
1406 xmlXPathDebugObjMaxNodeset = 0;
1407 xmlXPathDebugObjMaxBool = 0;
1408 xmlXPathDebugObjMaxNumber = 0;
1409 xmlXPathDebugObjMaxString = 0;
1410 xmlXPathDebugObjMaxPoint = 0;
1411 xmlXPathDebugObjMaxRange = 0;
1412 xmlXPathDebugObjMaxLocset = 0;
1413 xmlXPathDebugObjMaxUsers = 0;
1414 xmlXPathDebugObjMaxXSLTTree = 0;
1415 xmlXPathDebugObjMaxAll = 0;
1416
1417}
1418
1419static void
1420xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1421 xmlXPathObjectType objType)
1422{
1423 int isCached = 0;
1424
1425 if (ctxt != NULL) {
1426 if (ctxt->objCache != NULL) {
1427 xmlXPathObjectCachePtr cache =
1428 (xmlXPathObjectCachePtr) ctxt->objCache;
1429
1430 isCached = 1;
1431
1432 cache->dbgReusedAll++;
1433 switch (objType) {
1434 case XPATH_UNDEFINED:
1435 cache->dbgReusedUndefined++;
1436 break;
1437 case XPATH_NODESET:
1438 cache->dbgReusedNodeset++;
1439 break;
1440 case XPATH_BOOLEAN:
1441 cache->dbgReusedBool++;
1442 break;
1443 case XPATH_NUMBER:
1444 cache->dbgReusedNumber++;
1445 break;
1446 case XPATH_STRING:
1447 cache->dbgReusedString++;
1448 break;
1449 case XPATH_POINT:
1450 cache->dbgReusedPoint++;
1451 break;
1452 case XPATH_RANGE:
1453 cache->dbgReusedRange++;
1454 break;
1455 case XPATH_LOCATIONSET:
1456 cache->dbgReusedLocset++;
1457 break;
1458 case XPATH_USERS:
1459 cache->dbgReusedUsers++;
1460 break;
1461 case XPATH_XSLT_TREE:
1462 cache->dbgReusedXSLTTree++;
1463 break;
1464 default:
1465 break;
1466 }
1467 }
1468 }
1469
1470 switch (objType) {
1471 case XPATH_UNDEFINED:
1472 if (! isCached)
1473 xmlXPathDebugObjTotalUndefined++;
1474 xmlXPathDebugObjCounterUndefined++;
1475 if (xmlXPathDebugObjCounterUndefined >
1476 xmlXPathDebugObjMaxUndefined)
1477 xmlXPathDebugObjMaxUndefined =
1478 xmlXPathDebugObjCounterUndefined;
1479 break;
1480 case XPATH_NODESET:
1481 if (! isCached)
1482 xmlXPathDebugObjTotalNodeset++;
1483 xmlXPathDebugObjCounterNodeset++;
1484 if (xmlXPathDebugObjCounterNodeset >
1485 xmlXPathDebugObjMaxNodeset)
1486 xmlXPathDebugObjMaxNodeset =
1487 xmlXPathDebugObjCounterNodeset;
1488 break;
1489 case XPATH_BOOLEAN:
1490 if (! isCached)
1491 xmlXPathDebugObjTotalBool++;
1492 xmlXPathDebugObjCounterBool++;
1493 if (xmlXPathDebugObjCounterBool >
1494 xmlXPathDebugObjMaxBool)
1495 xmlXPathDebugObjMaxBool =
1496 xmlXPathDebugObjCounterBool;
1497 break;
1498 case XPATH_NUMBER:
1499 if (! isCached)
1500 xmlXPathDebugObjTotalNumber++;
1501 xmlXPathDebugObjCounterNumber++;
1502 if (xmlXPathDebugObjCounterNumber >
1503 xmlXPathDebugObjMaxNumber)
1504 xmlXPathDebugObjMaxNumber =
1505 xmlXPathDebugObjCounterNumber;
1506 break;
1507 case XPATH_STRING:
1508 if (! isCached)
1509 xmlXPathDebugObjTotalString++;
1510 xmlXPathDebugObjCounterString++;
1511 if (xmlXPathDebugObjCounterString >
1512 xmlXPathDebugObjMaxString)
1513 xmlXPathDebugObjMaxString =
1514 xmlXPathDebugObjCounterString;
1515 break;
1516 case XPATH_POINT:
1517 if (! isCached)
1518 xmlXPathDebugObjTotalPoint++;
1519 xmlXPathDebugObjCounterPoint++;
1520 if (xmlXPathDebugObjCounterPoint >
1521 xmlXPathDebugObjMaxPoint)
1522 xmlXPathDebugObjMaxPoint =
1523 xmlXPathDebugObjCounterPoint;
1524 break;
1525 case XPATH_RANGE:
1526 if (! isCached)
1527 xmlXPathDebugObjTotalRange++;
1528 xmlXPathDebugObjCounterRange++;
1529 if (xmlXPathDebugObjCounterRange >
1530 xmlXPathDebugObjMaxRange)
1531 xmlXPathDebugObjMaxRange =
1532 xmlXPathDebugObjCounterRange;
1533 break;
1534 case XPATH_LOCATIONSET:
1535 if (! isCached)
1536 xmlXPathDebugObjTotalLocset++;
1537 xmlXPathDebugObjCounterLocset++;
1538 if (xmlXPathDebugObjCounterLocset >
1539 xmlXPathDebugObjMaxLocset)
1540 xmlXPathDebugObjMaxLocset =
1541 xmlXPathDebugObjCounterLocset;
1542 break;
1543 case XPATH_USERS:
1544 if (! isCached)
1545 xmlXPathDebugObjTotalUsers++;
1546 xmlXPathDebugObjCounterUsers++;
1547 if (xmlXPathDebugObjCounterUsers >
1548 xmlXPathDebugObjMaxUsers)
1549 xmlXPathDebugObjMaxUsers =
1550 xmlXPathDebugObjCounterUsers;
1551 break;
1552 case XPATH_XSLT_TREE:
1553 if (! isCached)
1554 xmlXPathDebugObjTotalXSLTTree++;
1555 xmlXPathDebugObjCounterXSLTTree++;
1556 if (xmlXPathDebugObjCounterXSLTTree >
1557 xmlXPathDebugObjMaxXSLTTree)
1558 xmlXPathDebugObjMaxXSLTTree =
1559 xmlXPathDebugObjCounterXSLTTree;
1560 break;
1561 default:
1562 break;
1563 }
1564 if (! isCached)
1565 xmlXPathDebugObjTotalAll++;
1566 xmlXPathDebugObjCounterAll++;
1567 if (xmlXPathDebugObjCounterAll >
1568 xmlXPathDebugObjMaxAll)
1569 xmlXPathDebugObjMaxAll =
1570 xmlXPathDebugObjCounterAll;
1571}
1572
1573static void
1574xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1575 xmlXPathObjectType objType)
1576{
1577 int isCached = 0;
1578
1579 if (ctxt != NULL) {
1580 if (ctxt->objCache != NULL) {
1581 xmlXPathObjectCachePtr cache =
1582 (xmlXPathObjectCachePtr) ctxt->objCache;
1583
1584 isCached = 1;
1585
1586 cache->dbgCachedAll++;
1587 switch (objType) {
1588 case XPATH_UNDEFINED:
1589 cache->dbgCachedUndefined++;
1590 break;
1591 case XPATH_NODESET:
1592 cache->dbgCachedNodeset++;
1593 break;
1594 case XPATH_BOOLEAN:
1595 cache->dbgCachedBool++;
1596 break;
1597 case XPATH_NUMBER:
1598 cache->dbgCachedNumber++;
1599 break;
1600 case XPATH_STRING:
1601 cache->dbgCachedString++;
1602 break;
1603 case XPATH_POINT:
1604 cache->dbgCachedPoint++;
1605 break;
1606 case XPATH_RANGE:
1607 cache->dbgCachedRange++;
1608 break;
1609 case XPATH_LOCATIONSET:
1610 cache->dbgCachedLocset++;
1611 break;
1612 case XPATH_USERS:
1613 cache->dbgCachedUsers++;
1614 break;
1615 case XPATH_XSLT_TREE:
1616 cache->dbgCachedXSLTTree++;
1617 break;
1618 default:
1619 break;
1620 }
1621
1622 }
1623 }
1624 switch (objType) {
1625 case XPATH_UNDEFINED:
1626 xmlXPathDebugObjCounterUndefined--;
1627 break;
1628 case XPATH_NODESET:
1629 xmlXPathDebugObjCounterNodeset--;
1630 break;
1631 case XPATH_BOOLEAN:
1632 xmlXPathDebugObjCounterBool--;
1633 break;
1634 case XPATH_NUMBER:
1635 xmlXPathDebugObjCounterNumber--;
1636 break;
1637 case XPATH_STRING:
1638 xmlXPathDebugObjCounterString--;
1639 break;
1640 case XPATH_POINT:
1641 xmlXPathDebugObjCounterPoint--;
1642 break;
1643 case XPATH_RANGE:
1644 xmlXPathDebugObjCounterRange--;
1645 break;
1646 case XPATH_LOCATIONSET:
1647 xmlXPathDebugObjCounterLocset--;
1648 break;
1649 case XPATH_USERS:
1650 xmlXPathDebugObjCounterUsers--;
1651 break;
1652 case XPATH_XSLT_TREE:
1653 xmlXPathDebugObjCounterXSLTTree--;
1654 break;
1655 default:
1656 break;
1657 }
1658 xmlXPathDebugObjCounterAll--;
1659}
1660
1661/* REVISIT TODO: Make this static when committing */
1662static void
1663xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1664{
1665 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1666 reqXSLTTree, reqUndefined;
1667 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1668 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1669 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1670 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1671 int leftObjs = xmlXPathDebugObjCounterAll;
1672
1673 reqAll = xmlXPathDebugObjTotalAll;
1674 reqNodeset = xmlXPathDebugObjTotalNodeset;
1675 reqString = xmlXPathDebugObjTotalString;
1676 reqBool = xmlXPathDebugObjTotalBool;
1677 reqNumber = xmlXPathDebugObjTotalNumber;
1678 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1679 reqUndefined = xmlXPathDebugObjTotalUndefined;
1680
1681 printf("# XPath object usage:\n");
1682
1683 if (ctxt != NULL) {
1684 if (ctxt->objCache != NULL) {
1685 xmlXPathObjectCachePtr cache =
1686 (xmlXPathObjectCachePtr) ctxt->objCache;
1687
1688 reAll = cache->dbgReusedAll;
1689 reqAll += reAll;
1690 reNodeset = cache->dbgReusedNodeset;
1691 reqNodeset += reNodeset;
1692 reString = cache->dbgReusedString;
1693 reqString += reString;
1694 reBool = cache->dbgReusedBool;
1695 reqBool += reBool;
1696 reNumber = cache->dbgReusedNumber;
1697 reqNumber += reNumber;
1698 reXSLTTree = cache->dbgReusedXSLTTree;
1699 reqXSLTTree += reXSLTTree;
1700 reUndefined = cache->dbgReusedUndefined;
1701 reqUndefined += reUndefined;
1702
1703 caAll = cache->dbgCachedAll;
1704 caBool = cache->dbgCachedBool;
1705 caNodeset = cache->dbgCachedNodeset;
1706 caString = cache->dbgCachedString;
1707 caNumber = cache->dbgCachedNumber;
1708 caXSLTTree = cache->dbgCachedXSLTTree;
1709 caUndefined = cache->dbgCachedUndefined;
1710
1711 if (cache->nodesetObjs)
1712 leftObjs -= cache->nodesetObjs->number;
1713 if (cache->stringObjs)
1714 leftObjs -= cache->stringObjs->number;
1715 if (cache->booleanObjs)
1716 leftObjs -= cache->booleanObjs->number;
1717 if (cache->numberObjs)
1718 leftObjs -= cache->numberObjs->number;
1719 if (cache->miscObjs)
1720 leftObjs -= cache->miscObjs->number;
1721 }
1722 }
1723
1724 printf("# all\n");
1725 printf("# total : %d\n", reqAll);
1726 printf("# left : %d\n", leftObjs);
1727 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1728 printf("# reused : %d\n", reAll);
1729 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1730
1731 printf("# node-sets\n");
1732 printf("# total : %d\n", reqNodeset);
1733 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1734 printf("# reused : %d\n", reNodeset);
1735 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1736
1737 printf("# strings\n");
1738 printf("# total : %d\n", reqString);
1739 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1740 printf("# reused : %d\n", reString);
1741 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1742
1743 printf("# booleans\n");
1744 printf("# total : %d\n", reqBool);
1745 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1746 printf("# reused : %d\n", reBool);
1747 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1748
1749 printf("# numbers\n");
1750 printf("# total : %d\n", reqNumber);
1751 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1752 printf("# reused : %d\n", reNumber);
1753 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1754
1755 printf("# XSLT result tree fragments\n");
1756 printf("# total : %d\n", reqXSLTTree);
1757 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1758 printf("# reused : %d\n", reXSLTTree);
1759 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1760
1761 printf("# undefined\n");
1762 printf("# total : %d\n", reqUndefined);
1763 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1764 printf("# reused : %d\n", reUndefined);
1765 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1766
1767}
1768
1769#endif /* XP_DEBUG_OBJ_USAGE */
1770
Daniel Veillard017b1082001-06-21 11:20:21 +00001771#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001772
1773/************************************************************************
1774 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001775 * XPath object caching *
1776 * *
1777 ************************************************************************/
1778
1779/**
1780 * xmlXPathNewObjectCache:
1781 *
1782 * Create a new object cache
1783 *
1784 * Returns the xmlXPathObjectCahce just allocated.
1785 */
1786static xmlXPathObjectCachePtr
1787xmlXPathNewObjectCache(void)
1788{
1789 xmlXPathObjectCachePtr ret;
1790
1791 ret = (xmlXPathObjectCachePtr) xmlMalloc(sizeof(xmlXPathObjectCache));
1792 if (ret == NULL) {
1793 xmlXPathErrMemory(NULL, "creating object cache\n");
1794 return(NULL);
1795 }
1796 memset(ret, 0 , (size_t) sizeof(xmlXPathObjectCache));
1797 ret->maxNodeset = 100;
1798 ret->maxString = 100;
1799 ret->maxBoolean = 100;
1800 ret->maxNumber = 100;
1801 ret->maxMisc = 100;
1802 return(ret);
1803}
1804
1805static void
1806xmlXPathFreeObjectCacheList(xmlPointerListPtr list)
1807{
1808 int i;
1809 xmlXPathObjectPtr obj;
1810
1811 if (list == NULL)
1812 return;
1813
1814 for (i = 0; i < list->number; i++) {
1815 obj = list->items[i];
1816 /*
1817 * Note that it is already assured that we don't need to
1818 * look out for namespace nodes in the node-set.
1819 */
1820 if (obj->nodesetval != NULL) {
1821 if (obj->nodesetval->nodeTab != NULL)
1822 xmlFree(obj->nodesetval->nodeTab);
1823 xmlFree(obj->nodesetval);
1824 }
1825 xmlFree(obj);
1826#ifdef XP_DEBUG_OBJ_USAGE
1827 xmlXPathDebugObjCounterAll--;
1828#endif
1829 }
1830 xmlPointerListFree(list);
1831}
1832
1833static void
1834xmlXPathFreeObjectCache(xmlXPathObjectCachePtr cache)
1835{
1836 if (cache == NULL)
1837 return;
1838 if (cache->nodesetObjs)
1839 xmlXPathFreeObjectCacheList(cache->nodesetObjs);
1840 if (cache->stringObjs)
1841 xmlXPathFreeObjectCacheList(cache->stringObjs);
1842 if (cache->booleanObjs)
1843 xmlXPathFreeObjectCacheList(cache->booleanObjs);
1844 if (cache->numberObjs)
1845 xmlXPathFreeObjectCacheList(cache->numberObjs);
1846 if (cache->miscObjs)
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00001847 xmlXPathFreeObjectCacheList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 xmlFree(cache);
1849}
1850
1851/**
1852 * xmlXPathContextSetObjectCache:
1853 *
1854 * @ctxt: the XPath context
1855 * @active: enables/disables (creates/frees) the cache
1856 * @maxNumberPerSlot: the maximum number of XPath objects to be cached per slot
1857 * @options: currently not used
1858 *
1859 * Creates/frees an object cache on the XPath context.
1860 * If activates XPath objects (xmlXPathObject) will be cached internally
1861 * to be reused.
1862 * @maxNumberPerSlot is the maximum number of XPath objects to be cached per
1863 * slot. There are 5 slots for: node-set, string, number, boolean, and
1864 * misc objects. Use <0 for the default number (100).
1865 *
1866 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1867 */
1868int
1869xmlXPathContextSetObjectCache(xmlXPathContextPtr ctxt,
1870 int active,
1871 int maxNumberPerSlot,
1872 int options ATTRIBUTE_UNUSED)
1873{
1874 if (ctxt == NULL)
1875 return(-1);
1876 if (active) {
1877 xmlXPathObjectCachePtr cache;
1878
1879 if (ctxt->objCache == NULL) {
1880 ctxt->objCache = xmlXPathNewObjectCache();
1881 if (ctxt->objCache == NULL)
1882 return(-1);
1883 }
1884 cache = (xmlXPathObjectCachePtr) ctxt->objCache;
1885 if (maxNumberPerSlot < 0)
1886 maxNumberPerSlot = 100;
1887 cache->maxNodeset = maxNumberPerSlot;
1888 cache->maxString = maxNumberPerSlot;
1889 cache->maxNumber = maxNumberPerSlot;
1890 cache->maxBoolean = maxNumberPerSlot;
1891 cache->maxMisc = maxNumberPerSlot;
1892 } else if (ctxt->objCache != NULL) {
1893 xmlXPathFreeObjectCache((xmlXPathObjectCachePtr) ctxt->objCache);
1894 ctxt->objCache = NULL;
1895 }
1896 return(0);
1897}
1898
1899/**
1900 * xmlXPathCacheWrapNodeSet:
1901 * @ctxt: the XPath context
1902 * @val: the NodePtr value
1903 *
1904 * This is the cached version of xmlXPathWrapNodeSet().
1905 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1906 *
1907 * Returns the created or reused object.
1908 */
1909static xmlXPathObjectPtr
1910xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1911{
1912 if ((ctxt != NULL) && (ctxt->objCache != NULL)) {
1913 xmlXPathObjectCachePtr cache =
1914 (xmlXPathObjectCachePtr) ctxt->objCache;
1915
1916 if ((cache->miscObjs != NULL) &&
1917 (cache->miscObjs->number != 0))
1918 {
1919 xmlXPathObjectPtr ret;
1920
1921 ret = (xmlXPathObjectPtr)
1922 cache->miscObjs->items[--cache->miscObjs->number];
1923 ret->type = XPATH_NODESET;
1924 ret->nodesetval = val;
1925#ifdef XP_DEBUG_OBJ_USAGE
1926 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1927#endif
1928 return(ret);
1929 }
1930 }
1931
1932 return(xmlXPathWrapNodeSet(val));
1933
1934}
1935
1936/**
1937 * xmlXPathCacheWrapString:
1938 * @ctxt: the XPath context
1939 * @val: the xmlChar * value
1940 *
1941 * This is the cached version of xmlXPathWrapString().
1942 * Wraps the @val string into an XPath object.
1943 *
1944 * Returns the created or reused object.
1945 */
1946static xmlXPathObjectPtr
1947xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1948{
1949 if ((ctxt != NULL) && (ctxt->objCache != NULL)) {
1950 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
1951
1952 if ((cache->stringObjs != NULL) &&
1953 (cache->stringObjs->number != 0))
1954 {
1955
1956 xmlXPathObjectPtr ret;
1957
1958 ret = (xmlXPathObjectPtr)
1959 cache->stringObjs->items[--cache->stringObjs->number];
1960 ret->type = XPATH_STRING;
1961 ret->stringval = val;
1962#ifdef XP_DEBUG_OBJ_USAGE
1963 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1964#endif
1965 return(ret);
1966 } else if ((cache->miscObjs != NULL) &&
1967 (cache->miscObjs->number != 0))
1968 {
1969 xmlXPathObjectPtr ret;
1970 /*
1971 * Fallback to misc-cache.
1972 */
1973 ret = (xmlXPathObjectPtr)
1974 cache->miscObjs->items[--cache->miscObjs->number];
1975
1976 ret->type = XPATH_STRING;
1977 ret->stringval = val;
1978#ifdef XP_DEBUG_OBJ_USAGE
1979 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1980#endif
1981 return(ret);
1982 }
1983 }
1984 return(xmlXPathWrapString(val));
1985}
1986
1987/**
1988 * xmlXPathCacheNewNodeSet:
1989 * @ctxt: the XPath context
1990 * @val: the NodePtr value
1991 *
1992 * This is the cached version of xmlXPathNewNodeSet().
1993 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1994 * it with the single Node @val
1995 *
1996 * Returns the created or reused object.
1997 */
1998static xmlXPathObjectPtr
1999xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2000{
2001 if ((ctxt != NULL) && (ctxt->objCache)) {
2002 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2003
2004 if ((cache->nodesetObjs != NULL) &&
2005 (cache->nodesetObjs->number != 0))
2006 {
2007 xmlXPathObjectPtr ret;
2008 /*
2009 * Use the nodset-cache.
2010 */
2011 ret = (xmlXPathObjectPtr)
2012 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2013 ret->type = XPATH_NODESET;
2014 ret->boolval = 0;
2015 if (val) {
2016 if ((ret->nodesetval->nodeMax == 0) ||
2017 (val->type == XML_NAMESPACE_DECL))
2018 {
2019 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2020 } else {
2021 ret->nodesetval->nodeTab[0] = val;
2022 ret->nodesetval->nodeNr = 1;
2023 }
2024 }
2025#ifdef XP_DEBUG_OBJ_USAGE
2026 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2027#endif
2028 return(ret);
2029 } else if ((cache->miscObjs != NULL) &&
2030 (cache->miscObjs->number != 0))
2031 {
2032 xmlXPathObjectPtr ret;
2033 /*
2034 * Fallback to misc-cache.
2035 */
2036
2037 ret = (xmlXPathObjectPtr)
2038 cache->miscObjs->items[--cache->miscObjs->number];
2039
2040 ret->type = XPATH_NODESET;
2041 ret->boolval = 0;
2042 ret->nodesetval = xmlXPathNodeSetCreate(val);
2043#ifdef XP_DEBUG_OBJ_USAGE
2044 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2045#endif
2046 return(ret);
2047 }
2048 }
2049 return(xmlXPathNewNodeSet(val));
2050}
2051
2052/**
2053 * xmlXPathCacheNewCString:
2054 * @ctxt: the XPath context
2055 * @val: the char * value
2056 *
2057 * This is the cached version of xmlXPathNewCString().
2058 * Acquire an xmlXPathObjectPtr of type string and of value @val
2059 *
2060 * Returns the created or reused object.
2061 */
2062static xmlXPathObjectPtr
2063xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2064{
2065 if ((ctxt != NULL) && (ctxt->objCache)) {
2066 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2067
2068 if ((cache->stringObjs != NULL) &&
2069 (cache->stringObjs->number != 0))
2070 {
2071 xmlXPathObjectPtr ret;
2072
2073 ret = (xmlXPathObjectPtr)
2074 cache->stringObjs->items[--cache->stringObjs->number];
2075
2076 ret->type = XPATH_STRING;
2077 ret->stringval = xmlStrdup(BAD_CAST val);
2078#ifdef XP_DEBUG_OBJ_USAGE
2079 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2080#endif
2081 return(ret);
2082 } else if ((cache->miscObjs != NULL) &&
2083 (cache->miscObjs->number != 0))
2084 {
2085 xmlXPathObjectPtr ret;
2086
2087 ret = (xmlXPathObjectPtr)
2088 cache->miscObjs->items[--cache->miscObjs->number];
2089
2090 ret->type = XPATH_STRING;
2091 ret->stringval = xmlStrdup(BAD_CAST val);
2092#ifdef XP_DEBUG_OBJ_USAGE
2093 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2094#endif
2095 return(ret);
2096 }
2097 }
2098 return(xmlXPathNewCString(val));
2099}
2100
2101/**
2102 * xmlXPathCacheNewString:
2103 * @ctxt: the XPath context
2104 * @val: the xmlChar * value
2105 *
2106 * This is the cached version of xmlXPathNewString().
2107 * Acquire an xmlXPathObjectPtr of type string and of value @val
2108 *
2109 * Returns the created or reused object.
2110 */
2111static xmlXPathObjectPtr
2112xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2113{
2114 if ((ctxt != NULL) && (ctxt->objCache)) {
2115 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2116
2117 if ((cache->stringObjs != NULL) &&
2118 (cache->stringObjs->number != 0))
2119 {
2120 xmlXPathObjectPtr ret;
2121
2122 ret = (xmlXPathObjectPtr)
2123 cache->stringObjs->items[--cache->stringObjs->number];
2124 ret->type = XPATH_STRING;
2125 if (val != NULL)
2126 ret->stringval = xmlStrdup(val);
2127 else
2128 ret->stringval = xmlStrdup((const xmlChar *)"");
2129#ifdef XP_DEBUG_OBJ_USAGE
2130 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2131#endif
2132 return(ret);
2133 } else if ((cache->miscObjs != NULL) &&
2134 (cache->miscObjs->number != 0))
2135 {
2136 xmlXPathObjectPtr ret;
2137
2138 ret = (xmlXPathObjectPtr)
2139 cache->miscObjs->items[--cache->miscObjs->number];
2140
2141 ret->type = XPATH_STRING;
2142 if (val != NULL)
2143 ret->stringval = xmlStrdup(val);
2144 else
2145 ret->stringval = xmlStrdup((const xmlChar *)"");
2146#ifdef XP_DEBUG_OBJ_USAGE
2147 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2148#endif
2149 return(ret);
2150 }
2151 }
2152 return(xmlXPathNewString(val));
2153}
2154
2155/**
2156 * xmlXPathCacheNewBoolean:
2157 * @ctxt: the XPath context
2158 * @val: the boolean value
2159 *
2160 * This is the cached version of xmlXPathNewBoolean().
2161 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2162 *
2163 * Returns the created or reused object.
2164 */
2165static xmlXPathObjectPtr
2166xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2167{
2168 if ((ctxt != NULL) && (ctxt->objCache)) {
2169 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2170
2171 if ((cache->booleanObjs != NULL) &&
2172 (cache->booleanObjs->number != 0))
2173 {
2174 xmlXPathObjectPtr ret;
2175
2176 ret = (xmlXPathObjectPtr)
2177 cache->booleanObjs->items[--cache->booleanObjs->number];
2178 ret->type = XPATH_BOOLEAN;
2179 ret->boolval = (val != 0);
2180#ifdef XP_DEBUG_OBJ_USAGE
2181 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2182#endif
2183 return(ret);
2184 } else if ((cache->miscObjs != NULL) &&
2185 (cache->miscObjs->number != 0))
2186 {
2187 xmlXPathObjectPtr ret;
2188
2189 ret = (xmlXPathObjectPtr)
2190 cache->miscObjs->items[--cache->miscObjs->number];
2191
2192 ret->type = XPATH_BOOLEAN;
2193 ret->boolval = (val != 0);
2194#ifdef XP_DEBUG_OBJ_USAGE
2195 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2196#endif
2197 return(ret);
2198 }
2199 }
2200 return(xmlXPathNewBoolean(val));
2201}
2202
2203/**
2204 * xmlXPathCacheNewFloat:
2205 * @ctxt: the XPath context
2206 * @val: the double value
2207 *
2208 * This is the cached version of xmlXPathNewFloat().
2209 * Acquires an xmlXPathObjectPtr of type double and of value @val
2210 *
2211 * Returns the created or reused object.
2212 */
2213static xmlXPathObjectPtr
2214xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2215{
2216 if ((ctxt != NULL) && (ctxt->objCache)) {
2217 xmlXPathObjectCachePtr cache = (xmlXPathObjectCachePtr) ctxt->objCache;
2218
2219 if ((cache->numberObjs != NULL) &&
2220 (cache->numberObjs->number != 0))
2221 {
2222 xmlXPathObjectPtr ret;
2223
2224 ret = (xmlXPathObjectPtr)
2225 cache->numberObjs->items[--cache->numberObjs->number];
2226 ret->type = XPATH_NUMBER;
2227 ret->floatval = val;
2228#ifdef XP_DEBUG_OBJ_USAGE
2229 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2230#endif
2231 return(ret);
2232 } else if ((cache->miscObjs != NULL) &&
2233 (cache->miscObjs->number != 0))
2234 {
2235 xmlXPathObjectPtr ret;
2236
2237 ret = (xmlXPathObjectPtr)
2238 cache->miscObjs->items[--cache->miscObjs->number];
2239
2240 ret->type = XPATH_NUMBER;
2241 ret->floatval = val;
2242#ifdef XP_DEBUG_OBJ_USAGE
2243 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2244#endif
2245 return(ret);
2246 }
2247 }
2248 return(xmlXPathNewFloat(val));
2249}
2250
2251/**
2252 * xmlXPathCacheConvertString:
2253 * @ctxt: the XPath context
2254 * @val: an XPath object
2255 *
2256 * This is the cached version of xmlXPathConvertString().
2257 * Converts an existing object to its string() equivalent
2258 *
2259 * Returns a created or reused object, the old one is freed (cached)
2260 * (or the operation is done directly on @val)
2261 */
2262
2263static xmlXPathObjectPtr
2264xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2265 xmlChar *res = NULL;
2266
2267 if (val == NULL)
2268 return(xmlXPathCacheNewCString(ctxt, ""));
2269
2270 switch (val->type) {
2271 case XPATH_UNDEFINED:
2272#ifdef DEBUG_EXPR
2273 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2274#endif
2275 break;
2276 case XPATH_NODESET:
2277 case XPATH_XSLT_TREE:
2278 res = xmlXPathCastNodeSetToString(val->nodesetval);
2279 break;
2280 case XPATH_STRING:
2281 return(val);
2282 case XPATH_BOOLEAN:
2283 res = xmlXPathCastBooleanToString(val->boolval);
2284 break;
2285 case XPATH_NUMBER:
2286 res = xmlXPathCastNumberToString(val->floatval);
2287 break;
2288 case XPATH_USERS:
2289 case XPATH_POINT:
2290 case XPATH_RANGE:
2291 case XPATH_LOCATIONSET:
2292 TODO;
2293 break;
2294 }
2295 xmlXPathReleaseObject(ctxt, val);
2296 if (res == NULL)
2297 return(xmlXPathCacheNewCString(ctxt, ""));
2298 return(xmlXPathCacheWrapString(ctxt, res));
2299}
2300
2301/**
2302 * xmlXPathCacheObjectCopy:
2303 * @ctxt: the XPath context
2304 * @val: the original object
2305 *
2306 * This is the cached version of xmlXPathObjectCopy().
2307 * Acquire a copy of a given object
2308 *
2309 * Returns a created or reused created object.
2310 */
2311static xmlXPathObjectPtr
2312xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2313{
2314 if (val == NULL)
2315 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002316
2317 switch (val->type) {
2318 case XPATH_NODESET:
2319 if (XP_HAS_CACHE(ctxt))
2320 return(xmlXPathCacheWrapNodeSet(ctxt,
2321 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2322 case XPATH_STRING:
2323 if (XP_HAS_CACHE(ctxt))
2324 return(xmlXPathCacheNewString(ctxt, val->stringval));
2325 case XPATH_BOOLEAN:
2326 if (XP_HAS_CACHE(ctxt))
2327 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2328 case XPATH_NUMBER:
2329 if (XP_HAS_CACHE(ctxt))
2330 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2331 default:
2332 break;
2333 }
2334 return(xmlXPathObjectCopy(val));
2335}
2336
2337/**
2338 * xmlXPathCacheConvertBoolean:
2339 * @ctxt: the XPath context
2340 * @val: an XPath object
2341 *
2342 * This is the cached version of xmlXPathConvertBoolean().
2343 * Converts an existing object to its boolean() equivalent
2344 *
2345 * Returns a created or reused object, the old one is freed (or the operation
2346 * is done directly on @val)
2347 */
2348static xmlXPathObjectPtr
2349xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2350 xmlXPathObjectPtr ret;
2351
2352 if (val == NULL)
2353 return(xmlXPathCacheNewBoolean(ctxt, 0));
2354 if (val->type == XPATH_BOOLEAN)
2355 return(val);
2356 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2357 xmlXPathReleaseObject(ctxt, val);
2358 return(ret);
2359}
2360
2361/**
2362 * xmlXPathCacheConvertNumber:
2363 * @ctxt: the XPath context
2364 * @val: an XPath object
2365 *
2366 * This is the cached version of xmlXPathConvertNumber().
2367 * Converts an existing object to its number() equivalent
2368 *
2369 * Returns a created or reused object, the old one is freed (or the operation
2370 * is done directly on @val)
2371 */
2372static xmlXPathObjectPtr
2373xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2374 xmlXPathObjectPtr ret;
2375
2376 if (val == NULL)
2377 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2378 if (val->type == XPATH_NUMBER)
2379 return(val);
2380 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2381 xmlXPathReleaseObject(ctxt, val);
2382 return(ret);
2383}
2384
2385/************************************************************************
2386 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002387 * Parser stacks related functions and macros *
2388 * *
2389 ************************************************************************/
2390
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002391/**
2392 * valuePop:
2393 * @ctxt: an XPath evaluation context
2394 *
2395 * Pops the top XPath object from the value stack
2396 *
2397 * Returns the XPath object just removed
2398 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002399xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002400valuePop(xmlXPathParserContextPtr ctxt)
2401{
2402 xmlXPathObjectPtr ret;
2403
Daniel Veillarda82b1822004-11-08 16:24:57 +00002404 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002405 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002406 ctxt->valueNr--;
2407 if (ctxt->valueNr > 0)
2408 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2409 else
2410 ctxt->value = NULL;
2411 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002412 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002413 return (ret);
2414}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002415/**
2416 * valuePush:
2417 * @ctxt: an XPath evaluation context
2418 * @value: the XPath object
2419 *
2420 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002421 *
2422 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002423 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002424int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002425valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2426{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002427 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002428 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002429 xmlXPathObjectPtr *tmp;
2430
2431 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2432 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002433 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002434 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002435 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2436 return (0);
2437 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002438 ctxt->valueMax *= 2;
2439 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002440 }
2441 ctxt->valueTab[ctxt->valueNr] = value;
2442 ctxt->value = value;
2443 return (ctxt->valueNr++);
2444}
Owen Taylor3473f882001-02-23 17:55:21 +00002445
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002446/**
2447 * xmlXPathPopBoolean:
2448 * @ctxt: an XPath parser context
2449 *
2450 * Pops a boolean from the stack, handling conversion if needed.
2451 * Check error with #xmlXPathCheckError.
2452 *
2453 * Returns the boolean
2454 */
2455int
2456xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2457 xmlXPathObjectPtr obj;
2458 int ret;
2459
2460 obj = valuePop(ctxt);
2461 if (obj == NULL) {
2462 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2463 return(0);
2464 }
William M. Brack08171912003-12-29 02:52:11 +00002465 if (obj->type != XPATH_BOOLEAN)
2466 ret = xmlXPathCastToBoolean(obj);
2467 else
2468 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002469 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002470 return(ret);
2471}
2472
2473/**
2474 * xmlXPathPopNumber:
2475 * @ctxt: an XPath parser context
2476 *
2477 * Pops a number from the stack, handling conversion if needed.
2478 * Check error with #xmlXPathCheckError.
2479 *
2480 * Returns the number
2481 */
2482double
2483xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2484 xmlXPathObjectPtr obj;
2485 double ret;
2486
2487 obj = valuePop(ctxt);
2488 if (obj == NULL) {
2489 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2490 return(0);
2491 }
William M. Brack08171912003-12-29 02:52:11 +00002492 if (obj->type != XPATH_NUMBER)
2493 ret = xmlXPathCastToNumber(obj);
2494 else
2495 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002496 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002497 return(ret);
2498}
2499
2500/**
2501 * xmlXPathPopString:
2502 * @ctxt: an XPath parser context
2503 *
2504 * Pops a string from the stack, handling conversion if needed.
2505 * Check error with #xmlXPathCheckError.
2506 *
2507 * Returns the string
2508 */
2509xmlChar *
2510xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2511 xmlXPathObjectPtr obj;
2512 xmlChar * ret;
2513
2514 obj = valuePop(ctxt);
2515 if (obj == NULL) {
2516 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2517 return(NULL);
2518 }
William M. Brack08171912003-12-29 02:52:11 +00002519 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002520 /* TODO: needs refactoring somewhere else */
2521 if (obj->stringval == ret)
2522 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002523 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002524 return(ret);
2525}
2526
2527/**
2528 * xmlXPathPopNodeSet:
2529 * @ctxt: an XPath parser context
2530 *
2531 * Pops a node-set from the stack, handling conversion if needed.
2532 * Check error with #xmlXPathCheckError.
2533 *
2534 * Returns the node-set
2535 */
2536xmlNodeSetPtr
2537xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2538 xmlXPathObjectPtr obj;
2539 xmlNodeSetPtr ret;
2540
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002541 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002542 if (ctxt->value == NULL) {
2543 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2544 return(NULL);
2545 }
2546 if (!xmlXPathStackIsNodeSet(ctxt)) {
2547 xmlXPathSetTypeError(ctxt);
2548 return(NULL);
2549 }
2550 obj = valuePop(ctxt);
2551 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002552#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002553 /* to fix memory leak of not clearing obj->user */
2554 if (obj->boolval && obj->user != NULL)
2555 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002556#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002557 obj->nodesetval = NULL;
2558 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002559 return(ret);
2560}
2561
2562/**
2563 * xmlXPathPopExternal:
2564 * @ctxt: an XPath parser context
2565 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002566 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002567 * Check error with #xmlXPathCheckError.
2568 *
2569 * Returns the object
2570 */
2571void *
2572xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2573 xmlXPathObjectPtr obj;
2574 void * ret;
2575
Daniel Veillarda82b1822004-11-08 16:24:57 +00002576 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002577 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2578 return(NULL);
2579 }
2580 if (ctxt->value->type != XPATH_USERS) {
2581 xmlXPathSetTypeError(ctxt);
2582 return(NULL);
2583 }
2584 obj = valuePop(ctxt);
2585 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002586 obj->user = NULL;
2587 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002588 return(ret);
2589}
2590
Owen Taylor3473f882001-02-23 17:55:21 +00002591/*
2592 * Macros for accessing the content. Those should be used only by the parser,
2593 * and not exported.
2594 *
2595 * Dirty macros, i.e. one need to make assumption on the context to use them
2596 *
2597 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2598 * CUR returns the current xmlChar value, i.e. a 8 bit value
2599 * in ISO-Latin or UTF-8.
2600 * This should be used internally by the parser
2601 * only to compare to ASCII values otherwise it would break when
2602 * running with UTF-8 encoding.
2603 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2604 * to compare on ASCII based substring.
2605 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2606 * strings within the parser.
2607 * CURRENT Returns the current char value, with the full decoding of
2608 * UTF-8 if we are using this mode. It returns an int.
2609 * NEXT Skip to the next character, this does the proper decoding
2610 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2611 * It returns the pointer to the current xmlChar.
2612 */
2613
2614#define CUR (*ctxt->cur)
2615#define SKIP(val) ctxt->cur += (val)
2616#define NXT(val) ctxt->cur[(val)]
2617#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002618#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2619
2620#define COPY_BUF(l,b,i,v) \
2621 if (l == 1) b[i++] = (xmlChar) v; \
2622 else i += xmlCopyChar(l,&b[i],v)
2623
2624#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002625
2626#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002627 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002628
2629#define CURRENT (*ctxt->cur)
2630#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2631
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002632
2633#ifndef DBL_DIG
2634#define DBL_DIG 16
2635#endif
2636#ifndef DBL_EPSILON
2637#define DBL_EPSILON 1E-9
2638#endif
2639
2640#define UPPER_DOUBLE 1E9
2641#define LOWER_DOUBLE 1E-5
2642
2643#define INTEGER_DIGITS DBL_DIG
2644#define FRACTION_DIGITS (DBL_DIG + 1)
2645#define EXPONENT_DIGITS (3 + 2)
2646
2647/**
2648 * xmlXPathFormatNumber:
2649 * @number: number to format
2650 * @buffer: output buffer
2651 * @buffersize: size of output buffer
2652 *
2653 * Convert the number into a string representation.
2654 */
2655static void
2656xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2657{
Daniel Veillardcda96922001-08-21 10:56:31 +00002658 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002659 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002660 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002661 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002662 break;
2663 case -1:
2664 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002665 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002666 break;
2667 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002668 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002669 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002670 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002671 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002672 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002673 } else if (number == ((int) number)) {
2674 char work[30];
2675 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002676 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002677
2678 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002679 if (value == 0) {
2680 *ptr++ = '0';
2681 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002682 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002683 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002684 while ((*cur) && (ptr - buffer < buffersize)) {
2685 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002686 }
2687 }
2688 if (ptr - buffer < buffersize) {
2689 *ptr = 0;
2690 } else if (buffersize > 0) {
2691 ptr--;
2692 *ptr = 0;
2693 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002694 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002695 /* 3 is sign, decimal point, and terminating zero */
2696 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2697 int integer_place, fraction_place;
2698 char *ptr;
2699 char *after_fraction;
2700 double absolute_value;
2701 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002702
Bjorn Reese70a9da52001-04-21 16:57:29 +00002703 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002704
Bjorn Reese70a9da52001-04-21 16:57:29 +00002705 /*
2706 * First choose format - scientific or regular floating point.
2707 * In either case, result is in work, and after_fraction points
2708 * just past the fractional part.
2709 */
2710 if ( ((absolute_value > UPPER_DOUBLE) ||
2711 (absolute_value < LOWER_DOUBLE)) &&
2712 (absolute_value != 0.0) ) {
2713 /* Use scientific notation */
2714 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2715 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002716 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002717 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002718 while ((size > 0) && (work[size] != 'e')) size--;
2719 after_fraction = work + size;
2720
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002721 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002722 else {
2723 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002724 if (absolute_value > 0.0)
2725 integer_place = 1 + (int)log10(absolute_value);
2726 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002727 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002728 fraction_place = (integer_place > 0)
2729 ? DBL_DIG - integer_place
2730 : DBL_DIG;
2731 size = snprintf(work, sizeof(work), "%0.*f",
2732 fraction_place, number);
2733 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002734 }
2735
Bjorn Reese70a9da52001-04-21 16:57:29 +00002736 /* Remove fractional trailing zeroes */
2737 ptr = after_fraction;
2738 while (*(--ptr) == '0')
2739 ;
2740 if (*ptr != '.')
2741 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002742 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002743
2744 /* Finally copy result back to caller */
2745 size = strlen(work) + 1;
2746 if (size > buffersize) {
2747 work[buffersize - 1] = 0;
2748 size = buffersize;
2749 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002750 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002751 }
2752 break;
2753 }
2754}
2755
Owen Taylor3473f882001-02-23 17:55:21 +00002756
2757/************************************************************************
2758 * *
2759 * Routines to handle NodeSets *
2760 * *
2761 ************************************************************************/
2762
2763/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002764 * xmlXPathOrderDocElems:
2765 * @doc: an input document
2766 *
2767 * Call this routine to speed up XPath computation on static documents.
2768 * This stamps all the element nodes with the document order
2769 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002770 * field, the value stored is actually - the node number (starting at -1)
2771 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002772 *
William M. Brack08171912003-12-29 02:52:11 +00002773 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002774 * of error.
2775 */
2776long
2777xmlXPathOrderDocElems(xmlDocPtr doc) {
2778 long count = 0;
2779 xmlNodePtr cur;
2780
2781 if (doc == NULL)
2782 return(-1);
2783 cur = doc->children;
2784 while (cur != NULL) {
2785 if (cur->type == XML_ELEMENT_NODE) {
2786 cur->content = (void *) (-(++count));
2787 if (cur->children != NULL) {
2788 cur = cur->children;
2789 continue;
2790 }
2791 }
2792 if (cur->next != NULL) {
2793 cur = cur->next;
2794 continue;
2795 }
2796 do {
2797 cur = cur->parent;
2798 if (cur == NULL)
2799 break;
2800 if (cur == (xmlNodePtr) doc) {
2801 cur = NULL;
2802 break;
2803 }
2804 if (cur->next != NULL) {
2805 cur = cur->next;
2806 break;
2807 }
2808 } while (cur != NULL);
2809 }
2810 return(count);
2811}
2812
2813/**
Owen Taylor3473f882001-02-23 17:55:21 +00002814 * xmlXPathCmpNodes:
2815 * @node1: the first node
2816 * @node2: the second node
2817 *
2818 * Compare two nodes w.r.t document order
2819 *
2820 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002821 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002822 */
2823int
2824xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2825 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002826 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002827 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002828 xmlNodePtr cur, root;
2829
2830 if ((node1 == NULL) || (node2 == NULL))
2831 return(-2);
2832 /*
2833 * a couple of optimizations which will avoid computations in most cases
2834 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002835 if (node1->type == XML_ATTRIBUTE_NODE) {
2836 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002837 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002838 node1 = node1->parent;
2839 }
2840 if (node2->type == XML_ATTRIBUTE_NODE) {
2841 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002842 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002843 node2 = node2->parent;
2844 }
2845 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002846 if (attr1 == attr2) {
2847 /* not required, but we keep attributes in order */
2848 if (attr1 != 0) {
2849 cur = attrNode2->prev;
2850 while (cur != NULL) {
2851 if (cur == attrNode1)
2852 return (1);
2853 cur = cur->prev;
2854 }
2855 return (-1);
2856 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002857 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002858 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002859 if (attr2 == 1)
2860 return(1);
2861 return(-1);
2862 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002863 if ((node1->type == XML_NAMESPACE_DECL) ||
2864 (node2->type == XML_NAMESPACE_DECL))
2865 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002866 if (node1 == node2->prev)
2867 return(1);
2868 if (node1 == node2->next)
2869 return(-1);
2870
2871 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002872 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002873 */
2874 if ((node1->type == XML_ELEMENT_NODE) &&
2875 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002876 (0 > (long) node1->content) &&
2877 (0 > (long) node2->content) &&
2878 (node1->doc == node2->doc)) {
2879 long l1, l2;
2880
2881 l1 = -((long) node1->content);
2882 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002883 if (l1 < l2)
2884 return(1);
2885 if (l1 > l2)
2886 return(-1);
2887 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002888
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002889 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002890 * compute depth to root
2891 */
2892 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2893 if (cur == node1)
2894 return(1);
2895 depth2++;
2896 }
2897 root = cur;
2898 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2899 if (cur == node2)
2900 return(-1);
2901 depth1++;
2902 }
2903 /*
2904 * Distinct document (or distinct entities :-( ) case.
2905 */
2906 if (root != cur) {
2907 return(-2);
2908 }
2909 /*
2910 * get the nearest common ancestor.
2911 */
2912 while (depth1 > depth2) {
2913 depth1--;
2914 node1 = node1->parent;
2915 }
2916 while (depth2 > depth1) {
2917 depth2--;
2918 node2 = node2->parent;
2919 }
2920 while (node1->parent != node2->parent) {
2921 node1 = node1->parent;
2922 node2 = node2->parent;
2923 /* should not happen but just in case ... */
2924 if ((node1 == NULL) || (node2 == NULL))
2925 return(-2);
2926 }
2927 /*
2928 * Find who's first.
2929 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002930 if (node1 == node2->prev)
2931 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002932 if (node1 == node2->next)
2933 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002934 /*
2935 * Speedup using document order if availble.
2936 */
2937 if ((node1->type == XML_ELEMENT_NODE) &&
2938 (node2->type == XML_ELEMENT_NODE) &&
2939 (0 > (long) node1->content) &&
2940 (0 > (long) node2->content) &&
2941 (node1->doc == node2->doc)) {
2942 long l1, l2;
2943
2944 l1 = -((long) node1->content);
2945 l2 = -((long) node2->content);
2946 if (l1 < l2)
2947 return(1);
2948 if (l1 > l2)
2949 return(-1);
2950 }
2951
Owen Taylor3473f882001-02-23 17:55:21 +00002952 for (cur = node1->next;cur != NULL;cur = cur->next)
2953 if (cur == node2)
2954 return(1);
2955 return(-1); /* assume there is no sibling list corruption */
2956}
2957
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002958#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002959/**
2960 * xmlXPathCmpNodesExt:
2961 * @node1: the first node
2962 * @node2: the second node
2963 *
2964 * Compare two nodes w.r.t document order.
2965 * This one is optimized for handling of non-element nodes.
2966 *
2967 * Returns -2 in case of error 1 if first point < second point, 0 if
2968 * it's the same node, -1 otherwise
2969 */
2970static int
2971xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2972 int depth1, depth2;
2973 int misc = 0, precedence1 = 0, precedence2 = 0;
2974 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2975 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002976 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002977
2978 if ((node1 == NULL) || (node2 == NULL))
2979 return(-2);
2980
2981 if (node1 == node2)
2982 return(0);
2983
2984 /*
2985 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002986 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002987 switch (node1->type) {
2988 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002989 if (node2->type == XML_ELEMENT_NODE) {
2990 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2991 (0 > (long) node2->content) &&
2992 (node1->doc == node2->doc))
2993 {
2994 l1 = -((long) node1->content);
2995 l2 = -((long) node2->content);
2996 if (l1 < l2)
2997 return(1);
2998 if (l1 > l2)
2999 return(-1);
3000 } else
3001 goto turtle_comparison;
3002 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003003 break;
3004 case XML_ATTRIBUTE_NODE:
3005 precedence1 = 1; /* element is owner */
3006 miscNode1 = node1;
3007 node1 = node1->parent;
3008 misc = 1;
3009 break;
3010 case XML_TEXT_NODE:
3011 case XML_CDATA_SECTION_NODE:
3012 case XML_COMMENT_NODE:
3013 case XML_PI_NODE: {
3014 miscNode1 = node1;
3015 /*
3016 * Find nearest element node.
3017 */
3018 if (node1->prev != NULL) {
3019 do {
3020 node1 = node1->prev;
3021 if (node1->type == XML_ELEMENT_NODE) {
3022 precedence1 = 3; /* element in prev-sibl axis */
3023 break;
3024 }
3025 if (node1->prev == NULL) {
3026 precedence1 = 2; /* element is parent */
3027 /*
3028 * URGENT TODO: Are there any cases, where the
3029 * parent of such a node is not an element node?
3030 */
3031 node1 = node1->parent;
3032 break;
3033 }
3034 } while (1);
3035 } else {
3036 precedence1 = 2; /* element is parent */
3037 node1 = node1->parent;
3038 }
3039 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3040 /*
3041 * Fallback for whatever case.
3042 */
3043 node1 = miscNode1;
3044 precedence1 = 0;
3045 } else
3046 misc = 1;
3047 }
3048 break;
3049 case XML_NAMESPACE_DECL:
3050 /*
3051 * TODO: why do we return 1 for namespace nodes?
3052 */
3053 return(1);
3054 default:
3055 break;
3056 }
3057 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003058 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003059 break;
3060 case XML_ATTRIBUTE_NODE:
3061 precedence2 = 1; /* element is owner */
3062 miscNode2 = node2;
3063 node2 = node2->parent;
3064 misc = 1;
3065 break;
3066 case XML_TEXT_NODE:
3067 case XML_CDATA_SECTION_NODE:
3068 case XML_COMMENT_NODE:
3069 case XML_PI_NODE: {
3070 miscNode2 = node2;
3071 if (node2->prev != NULL) {
3072 do {
3073 node2 = node2->prev;
3074 if (node2->type == XML_ELEMENT_NODE) {
3075 precedence2 = 3; /* element in prev-sibl axis */
3076 break;
3077 }
3078 if (node2->prev == NULL) {
3079 precedence2 = 2; /* element is parent */
3080 node2 = node2->parent;
3081 break;
3082 }
3083 } while (1);
3084 } else {
3085 precedence2 = 2; /* element is parent */
3086 node2 = node2->parent;
3087 }
3088 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3089 (0 <= (long) node1->content))
3090 {
3091 node2 = miscNode2;
3092 precedence2 = 0;
3093 } else
3094 misc = 1;
3095 }
3096 break;
3097 case XML_NAMESPACE_DECL:
3098 return(1);
3099 default:
3100 break;
3101 }
3102 if (misc) {
3103 if (node1 == node2) {
3104 if (precedence1 == precedence2) {
3105 /*
3106 * The ugly case; but normally there aren't many
3107 * adjacent non-element nodes around.
3108 */
3109 cur = miscNode2->prev;
3110 while (cur != NULL) {
3111 if (cur == miscNode1)
3112 return(1);
3113 if (cur->type == XML_ELEMENT_NODE)
3114 return(-1);
3115 cur = cur->prev;
3116 }
3117 return (-1);
3118 } else {
3119 /*
3120 * Evaluate based on higher precedence wrt to the element.
3121 * TODO: This assumes attributes are sorted before content.
3122 * Is this 100% correct?
3123 */
3124 if (precedence1 < precedence2)
3125 return(1);
3126 else
3127 return(-1);
3128 }
3129 }
3130 /*
3131 * Special case: One of the helper-elements is contained by the other.
3132 * <foo>
3133 * <node2>
3134 * <node1>Text-1(precedence1 == 2)</node1>
3135 * </node2>
3136 * Text-6(precedence2 == 3)
3137 * </foo>
3138 */
3139 if ((precedence2 == 3) && (precedence1 > 1)) {
3140 cur = node1->parent;
3141 while (cur) {
3142 if (cur == node2)
3143 return(1);
3144 cur = cur->parent;
3145 }
3146 }
3147 if ((precedence1 == 3) && (precedence2 > 1)) {
3148 cur = node2->parent;
3149 while (cur) {
3150 if (cur == node1)
3151 return(-1);
3152 cur = cur->parent;
3153 }
3154 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003155 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003156
3157 /*
3158 * Speedup using document order if availble.
3159 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003160 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003161 (node2->type == XML_ELEMENT_NODE) &&
3162 (0 > (long) node1->content) &&
3163 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003164 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003165
3166 l1 = -((long) node1->content);
3167 l2 = -((long) node2->content);
3168 if (l1 < l2)
3169 return(1);
3170 if (l1 > l2)
3171 return(-1);
3172 }
3173
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003174turtle_comparison:
3175
3176 if (node1 == node2->prev)
3177 return(1);
3178 if (node1 == node2->next)
3179 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003180 /*
3181 * compute depth to root
3182 */
3183 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3184 if (cur == node1)
3185 return(1);
3186 depth2++;
3187 }
3188 root = cur;
3189 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3190 if (cur == node2)
3191 return(-1);
3192 depth1++;
3193 }
3194 /*
3195 * Distinct document (or distinct entities :-( ) case.
3196 */
3197 if (root != cur) {
3198 return(-2);
3199 }
3200 /*
3201 * get the nearest common ancestor.
3202 */
3203 while (depth1 > depth2) {
3204 depth1--;
3205 node1 = node1->parent;
3206 }
3207 while (depth2 > depth1) {
3208 depth2--;
3209 node2 = node2->parent;
3210 }
3211 while (node1->parent != node2->parent) {
3212 node1 = node1->parent;
3213 node2 = node2->parent;
3214 /* should not happen but just in case ... */
3215 if ((node1 == NULL) || (node2 == NULL))
3216 return(-2);
3217 }
3218 /*
3219 * Find who's first.
3220 */
3221 if (node1 == node2->prev)
3222 return(1);
3223 if (node1 == node2->next)
3224 return(-1);
3225 /*
3226 * Speedup using document order if availble.
3227 */
3228 if ((node1->type == XML_ELEMENT_NODE) &&
3229 (node2->type == XML_ELEMENT_NODE) &&
3230 (0 > (long) node1->content) &&
3231 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003232 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003233
3234 l1 = -((long) node1->content);
3235 l2 = -((long) node2->content);
3236 if (l1 < l2)
3237 return(1);
3238 if (l1 > l2)
3239 return(-1);
3240 }
3241
3242 for (cur = node1->next;cur != NULL;cur = cur->next)
3243 if (cur == node2)
3244 return(1);
3245 return(-1); /* assume there is no sibling list corruption */
3246}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003247#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003248
Owen Taylor3473f882001-02-23 17:55:21 +00003249/**
3250 * xmlXPathNodeSetSort:
3251 * @set: the node set
3252 *
3253 * Sort the node set in document order
3254 */
3255void
3256xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003257 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003258 xmlNodePtr tmp;
3259
3260 if (set == NULL)
3261 return;
3262
3263 /* Use Shell's sort to sort the node-set */
3264 len = set->nodeNr;
3265 for (incr = len / 2; incr > 0; incr /= 2) {
3266 for (i = incr; i < len; i++) {
3267 j = i - incr;
3268 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003269#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003270 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3271 set->nodeTab[j + incr]) == -1)
3272#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003273 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003274 set->nodeTab[j + incr]) == -1)
3275#endif
3276 {
Owen Taylor3473f882001-02-23 17:55:21 +00003277 tmp = set->nodeTab[j];
3278 set->nodeTab[j] = set->nodeTab[j + incr];
3279 set->nodeTab[j + incr] = tmp;
3280 j -= incr;
3281 } else
3282 break;
3283 }
3284 }
3285 }
3286}
3287
3288#define XML_NODESET_DEFAULT 10
3289/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003290 * xmlXPathNodeSetDupNs:
3291 * @node: the parent node of the namespace XPath node
3292 * @ns: the libxml namespace declaration node.
3293 *
3294 * Namespace node in libxml don't match the XPath semantic. In a node set
3295 * the namespace nodes are duplicated and the next pointer is set to the
3296 * parent node in the XPath semantic.
3297 *
3298 * Returns the newly created object.
3299 */
3300static xmlNodePtr
3301xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3302 xmlNsPtr cur;
3303
3304 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3305 return(NULL);
3306 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3307 return((xmlNodePtr) ns);
3308
3309 /*
3310 * Allocate a new Namespace and fill the fields.
3311 */
3312 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3313 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003314 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003315 return(NULL);
3316 }
3317 memset(cur, 0, sizeof(xmlNs));
3318 cur->type = XML_NAMESPACE_DECL;
3319 if (ns->href != NULL)
3320 cur->href = xmlStrdup(ns->href);
3321 if (ns->prefix != NULL)
3322 cur->prefix = xmlStrdup(ns->prefix);
3323 cur->next = (xmlNsPtr) node;
3324 return((xmlNodePtr) cur);
3325}
3326
3327/**
3328 * xmlXPathNodeSetFreeNs:
3329 * @ns: the XPath namespace node found in a nodeset.
3330 *
William M. Brack08171912003-12-29 02:52:11 +00003331 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003332 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003333 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003334 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003335void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003336xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3337 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3338 return;
3339
3340 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3341 if (ns->href != NULL)
3342 xmlFree((xmlChar *)ns->href);
3343 if (ns->prefix != NULL)
3344 xmlFree((xmlChar *)ns->prefix);
3345 xmlFree(ns);
3346 }
3347}
3348
3349/**
Owen Taylor3473f882001-02-23 17:55:21 +00003350 * xmlXPathNodeSetCreate:
3351 * @val: an initial xmlNodePtr, or NULL
3352 *
3353 * Create a new xmlNodeSetPtr of type double and of value @val
3354 *
3355 * Returns the newly created object.
3356 */
3357xmlNodeSetPtr
3358xmlXPathNodeSetCreate(xmlNodePtr val) {
3359 xmlNodeSetPtr ret;
3360
3361 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3362 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003363 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003364 return(NULL);
3365 }
3366 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3367 if (val != NULL) {
3368 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3369 sizeof(xmlNodePtr));
3370 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003371 xmlXPathErrMemory(NULL, "creating nodeset\n");
3372 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003373 return(NULL);
3374 }
3375 memset(ret->nodeTab, 0 ,
3376 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3377 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003378 if (val->type == XML_NAMESPACE_DECL) {
3379 xmlNsPtr ns = (xmlNsPtr) val;
3380
3381 ret->nodeTab[ret->nodeNr++] =
3382 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3383 } else
3384 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003385 }
3386 return(ret);
3387}
3388
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003389#if 0 /* Not used yet. */
Owen Taylor3473f882001-02-23 17:55:21 +00003390/**
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003391 * xmlXPathNodeSetCreateSize:
3392 * @val: an initial xmlNodePtr, or NULL
3393 * @size: the initial size of the node-sets
3394 *
3395 * Create a new xmlNodeSetPtr of type double and of value @val
3396 *
3397 * Returns the newly created object.
3398 */
3399static xmlNodeSetPtr
3400xmlXPathNodeSetCreateSize(int size)
3401{
3402 xmlNodeSetPtr ret;
3403
3404 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3405 if (ret == NULL) {
3406 xmlXPathErrMemory(NULL, "creating nodeset\n");
3407 return(NULL);
3408 }
3409 memset(ret, 0, (size_t) sizeof(xmlNodeSet));
3410 if (size > 0) {
3411 if (size < XML_NODESET_DEFAULT)
3412 size = XML_NODESET_DEFAULT;
3413 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3414 if (ret->nodeTab == NULL) {
3415 xmlXPathErrMemory(NULL, "creating nodeset\n");
3416 xmlFree(ret);
3417 return(NULL);
3418 }
3419 memset(ret->nodeTab, 0, size * (size_t) sizeof(xmlNodePtr));
3420 ret->nodeMax = size;
3421 }
3422 return(ret);
3423}
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003424#endif
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003425
3426/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003427 * xmlXPathNodeSetContains:
3428 * @cur: the node-set
3429 * @val: the node
3430 *
3431 * checks whether @cur contains @val
3432 *
3433 * Returns true (1) if @cur contains @val, false (0) otherwise
3434 */
3435int
3436xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3437 int i;
3438
Daniel Veillarda82b1822004-11-08 16:24:57 +00003439 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003440 if (val->type == XML_NAMESPACE_DECL) {
3441 for (i = 0; i < cur->nodeNr; i++) {
3442 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3443 xmlNsPtr ns1, ns2;
3444
3445 ns1 = (xmlNsPtr) val;
3446 ns2 = (xmlNsPtr) cur->nodeTab[i];
3447 if (ns1 == ns2)
3448 return(1);
3449 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3450 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3451 return(1);
3452 }
3453 }
3454 } else {
3455 for (i = 0; i < cur->nodeNr; i++) {
3456 if (cur->nodeTab[i] == val)
3457 return(1);
3458 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003459 }
3460 return(0);
3461}
3462
3463/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003464 * xmlXPathNodeSetAddNs:
3465 * @cur: the initial node set
3466 * @node: the hosting node
3467 * @ns: a the namespace node
3468 *
3469 * add a new namespace node to an existing NodeSet
3470 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003471void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003472xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3473 int i;
3474
Daniel Veillarda82b1822004-11-08 16:24:57 +00003475
3476 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3477 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003478 (node->type != XML_ELEMENT_NODE))
3479 return;
3480
William M. Brack08171912003-12-29 02:52:11 +00003481 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003482 /*
William M. Brack08171912003-12-29 02:52:11 +00003483 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003484 */
3485 for (i = 0;i < cur->nodeNr;i++) {
3486 if ((cur->nodeTab[i] != NULL) &&
3487 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003488 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003489 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3490 return;
3491 }
3492
3493 /*
3494 * grow the nodeTab if needed
3495 */
3496 if (cur->nodeMax == 0) {
3497 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3498 sizeof(xmlNodePtr));
3499 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003500 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003501 return;
3502 }
3503 memset(cur->nodeTab, 0 ,
3504 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3505 cur->nodeMax = XML_NODESET_DEFAULT;
3506 } else if (cur->nodeNr == cur->nodeMax) {
3507 xmlNodePtr *temp;
3508
3509 cur->nodeMax *= 2;
3510 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3511 sizeof(xmlNodePtr));
3512 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003513 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003514 return;
3515 }
3516 cur->nodeTab = temp;
3517 }
3518 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3519}
3520
3521/**
Owen Taylor3473f882001-02-23 17:55:21 +00003522 * xmlXPathNodeSetAdd:
3523 * @cur: the initial node set
3524 * @val: a new xmlNodePtr
3525 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003526 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003527 */
3528void
3529xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3530 int i;
3531
Daniel Veillarda82b1822004-11-08 16:24:57 +00003532 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003533
Daniel Veillardef0b4502003-03-24 13:57:34 +00003534#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003535 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3536 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003537#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003538
William M. Brack08171912003-12-29 02:52:11 +00003539 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003540 /*
William M. Brack08171912003-12-29 02:52:11 +00003541 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003542 */
3543 for (i = 0;i < cur->nodeNr;i++)
3544 if (cur->nodeTab[i] == val) return;
3545
3546 /*
3547 * grow the nodeTab if needed
3548 */
3549 if (cur->nodeMax == 0) {
3550 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3551 sizeof(xmlNodePtr));
3552 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003553 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003554 return;
3555 }
3556 memset(cur->nodeTab, 0 ,
3557 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3558 cur->nodeMax = XML_NODESET_DEFAULT;
3559 } else if (cur->nodeNr == cur->nodeMax) {
3560 xmlNodePtr *temp;
3561
3562 cur->nodeMax *= 2;
3563 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3564 sizeof(xmlNodePtr));
3565 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003566 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003567 return;
3568 }
3569 cur->nodeTab = temp;
3570 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003571 if (val->type == XML_NAMESPACE_DECL) {
3572 xmlNsPtr ns = (xmlNsPtr) val;
3573
3574 cur->nodeTab[cur->nodeNr++] =
3575 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3576 } else
3577 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003578}
3579
3580/**
3581 * xmlXPathNodeSetAddUnique:
3582 * @cur: the initial node set
3583 * @val: a new xmlNodePtr
3584 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003585 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003586 * when we are sure the node is not already in the set.
3587 */
3588void
3589xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003590 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003591
Daniel Veillardef0b4502003-03-24 13:57:34 +00003592#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003593 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3594 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003595#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003596
William M. Brack08171912003-12-29 02:52:11 +00003597 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003598 /*
3599 * grow the nodeTab if needed
3600 */
3601 if (cur->nodeMax == 0) {
3602 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3603 sizeof(xmlNodePtr));
3604 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003605 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003606 return;
3607 }
3608 memset(cur->nodeTab, 0 ,
3609 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3610 cur->nodeMax = XML_NODESET_DEFAULT;
3611 } else if (cur->nodeNr == cur->nodeMax) {
3612 xmlNodePtr *temp;
3613
3614 cur->nodeMax *= 2;
3615 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3616 sizeof(xmlNodePtr));
3617 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003618 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003619 return;
3620 }
3621 cur->nodeTab = temp;
3622 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003623 if (val->type == XML_NAMESPACE_DECL) {
3624 xmlNsPtr ns = (xmlNsPtr) val;
3625
3626 cur->nodeTab[cur->nodeNr++] =
3627 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3628 } else
3629 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003630}
3631
3632/**
3633 * xmlXPathNodeSetMerge:
3634 * @val1: the first NodeSet or NULL
3635 * @val2: the second NodeSet
3636 *
3637 * Merges two nodesets, all nodes from @val2 are added to @val1
3638 * if @val1 is NULL, a new set is created and copied from @val2
3639 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003640 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003641 */
3642xmlNodeSetPtr
3643xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003644 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003645 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003646
3647 if (val2 == NULL) return(val1);
3648 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003649 val1 = xmlXPathNodeSetCreate(NULL);
3650#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003651 /*
3652 * TODO: The optimization won't work in every case, since
3653 * those nasty namespace nodes need to be added with
3654 * xmlXPathNodeSetDupNs() to the set; thus a pure
3655 * memcpy is not possible.
3656 */
3657 /*
3658 * Optimization: Create an equally sized node-set
3659 * and memcpy the content.
3660 */
3661 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3662 if (val1 == NULL)
3663 return(NULL);
3664 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003665 if (val2->nodeNr == 1)
3666 *(val1->nodeTab) = *(val2->nodeTab);
3667 else {
3668 memcpy(val1->nodeTab, val2->nodeTab,
3669 val2->nodeNr * sizeof(xmlNodePtr));
3670 }
3671 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003672 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003673 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003674#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003675 }
3676
William M. Brack08171912003-12-29 02:52:11 +00003677 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003678 initNr = val1->nodeNr;
3679
3680 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003681 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003682 /*
William M. Brack08171912003-12-29 02:52:11 +00003683 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003684 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003685 skip = 0;
3686 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003687 n1 = val1->nodeTab[j];
3688 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003689 skip = 1;
3690 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003691 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3692 (n2->type == XML_NAMESPACE_DECL)) {
3693 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3694 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3695 ((xmlNsPtr) n2)->prefix)))
3696 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003697 skip = 1;
3698 break;
3699 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003700 }
3701 }
3702 if (skip)
3703 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003704
3705 /*
3706 * grow the nodeTab if needed
3707 */
3708 if (val1->nodeMax == 0) {
3709 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3710 sizeof(xmlNodePtr));
3711 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003712 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003713 return(NULL);
3714 }
3715 memset(val1->nodeTab, 0 ,
3716 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3717 val1->nodeMax = XML_NODESET_DEFAULT;
3718 } else if (val1->nodeNr == val1->nodeMax) {
3719 xmlNodePtr *temp;
3720
3721 val1->nodeMax *= 2;
3722 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3723 sizeof(xmlNodePtr));
3724 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003725 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003726 return(NULL);
3727 }
3728 val1->nodeTab = temp;
3729 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003730 if (n2->type == XML_NAMESPACE_DECL) {
3731 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003732
3733 val1->nodeTab[val1->nodeNr++] =
3734 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3735 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003736 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003737 }
3738
3739 return(val1);
3740}
3741
3742/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003743 * xmlXPathNodeSetMergeUnique:
3744 * @val1: the first NodeSet or NULL
3745 * @val2: the second NodeSet
3746 *
3747 * Merges two nodesets, all nodes from @val2 are added to @val1
3748 * if @val1 is NULL, a new set is created and copied from @val2
3749 *
3750 * Returns @val1 once extended or NULL in case of error.
3751 */
3752static xmlNodeSetPtr
3753xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003754 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003755
3756 if (val2 == NULL) return(val1);
3757 if (val1 == NULL) {
3758 val1 = xmlXPathNodeSetCreate(NULL);
3759 }
3760
William M. Brack08171912003-12-29 02:52:11 +00003761 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003762
3763 for (i = 0;i < val2->nodeNr;i++) {
3764 /*
3765 * grow the nodeTab if needed
3766 */
3767 if (val1->nodeMax == 0) {
3768 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3769 sizeof(xmlNodePtr));
3770 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003771 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003772 return(NULL);
3773 }
3774 memset(val1->nodeTab, 0 ,
3775 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3776 val1->nodeMax = XML_NODESET_DEFAULT;
3777 } else if (val1->nodeNr == val1->nodeMax) {
3778 xmlNodePtr *temp;
3779
3780 val1->nodeMax *= 2;
3781 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3782 sizeof(xmlNodePtr));
3783 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003784 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003785 return(NULL);
3786 }
3787 val1->nodeTab = temp;
3788 }
3789 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3790 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3791
3792 val1->nodeTab[val1->nodeNr++] =
3793 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3794 } else
3795 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3796 }
3797
3798 return(val1);
3799}
3800
3801/**
Owen Taylor3473f882001-02-23 17:55:21 +00003802 * xmlXPathNodeSetDel:
3803 * @cur: the initial node set
3804 * @val: an xmlNodePtr
3805 *
3806 * Removes an xmlNodePtr from an existing NodeSet
3807 */
3808void
3809xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3810 int i;
3811
3812 if (cur == NULL) return;
3813 if (val == NULL) return;
3814
3815 /*
William M. Brack08171912003-12-29 02:52:11 +00003816 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00003817 */
3818 for (i = 0;i < cur->nodeNr;i++)
3819 if (cur->nodeTab[i] == val) break;
3820
William M. Brack08171912003-12-29 02:52:11 +00003821 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00003822#ifdef DEBUG
3823 xmlGenericError(xmlGenericErrorContext,
3824 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
3825 val->name);
3826#endif
3827 return;
3828 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003829 if ((cur->nodeTab[i] != NULL) &&
3830 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3831 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003832 cur->nodeNr--;
3833 for (;i < cur->nodeNr;i++)
3834 cur->nodeTab[i] = cur->nodeTab[i + 1];
3835 cur->nodeTab[cur->nodeNr] = NULL;
3836}
3837
3838/**
3839 * xmlXPathNodeSetRemove:
3840 * @cur: the initial node set
3841 * @val: the index to remove
3842 *
3843 * Removes an entry from an existing NodeSet list.
3844 */
3845void
3846xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3847 if (cur == NULL) return;
3848 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003849 if ((cur->nodeTab[val] != NULL) &&
3850 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3851 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00003852 cur->nodeNr--;
3853 for (;val < cur->nodeNr;val++)
3854 cur->nodeTab[val] = cur->nodeTab[val + 1];
3855 cur->nodeTab[cur->nodeNr] = NULL;
3856}
3857
3858/**
3859 * xmlXPathFreeNodeSet:
3860 * @obj: the xmlNodeSetPtr to free
3861 *
3862 * Free the NodeSet compound (not the actual nodes !).
3863 */
3864void
3865xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3866 if (obj == NULL) return;
3867 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003868 int i;
3869
William M. Brack08171912003-12-29 02:52:11 +00003870 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003871 for (i = 0;i < obj->nodeNr;i++)
3872 if ((obj->nodeTab[i] != NULL) &&
3873 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3874 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003875 xmlFree(obj->nodeTab);
3876 }
Owen Taylor3473f882001-02-23 17:55:21 +00003877 xmlFree(obj);
3878}
3879
3880/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003881 * xmlXPathNodeSetClear:
3882 * @set: the xmlNodeSetPtr to free
3883 *
3884 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3885 * are feed), but does *not* free the list itself. Sets the length of the
3886 * list to 0.
3887 */
3888static void
3889xmlXPathNodeSetClear(xmlNodeSetPtr set)
3890{
3891 int i;
3892 xmlNodePtr node;
3893
3894 if ((set == NULL) || (set->nodeNr <= 0))
3895 return;
3896
3897 for (i = 0; i < set->nodeNr; i++) {
3898 node = set->nodeTab[i];
3899 if ((node != NULL) &&
3900 (node->type == XML_NAMESPACE_DECL))
3901 {
3902 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3903 }
3904 }
3905 set->nodeNr = 0;
3906}
3907
3908/**
Owen Taylor3473f882001-02-23 17:55:21 +00003909 * xmlXPathFreeValueTree:
3910 * @obj: the xmlNodeSetPtr to free
3911 *
3912 * Free the NodeSet compound and the actual tree, this is different
3913 * from xmlXPathFreeNodeSet()
3914 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003915static void
Owen Taylor3473f882001-02-23 17:55:21 +00003916xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3917 int i;
3918
3919 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003920
3921 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003922 for (i = 0;i < obj->nodeNr;i++) {
3923 if (obj->nodeTab[i] != NULL) {
3924 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3925 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3926 } else {
3927 xmlFreeNodeList(obj->nodeTab[i]);
3928 }
3929 }
3930 }
Owen Taylor3473f882001-02-23 17:55:21 +00003931 xmlFree(obj->nodeTab);
3932 }
Owen Taylor3473f882001-02-23 17:55:21 +00003933 xmlFree(obj);
3934}
3935
3936#if defined(DEBUG) || defined(DEBUG_STEP)
3937/**
3938 * xmlGenericErrorContextNodeSet:
3939 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00003940 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00003941 *
3942 * Quick display of a NodeSet
3943 */
3944void
3945xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
3946 int i;
3947
3948 if (output == NULL) output = xmlGenericErrorContext;
3949 if (obj == NULL) {
3950 fprintf(output, "NodeSet == NULL !\n");
3951 return;
3952 }
3953 if (obj->nodeNr == 0) {
3954 fprintf(output, "NodeSet is empty\n");
3955 return;
3956 }
3957 if (obj->nodeTab == NULL) {
3958 fprintf(output, " nodeTab == NULL !\n");
3959 return;
3960 }
3961 for (i = 0; i < obj->nodeNr; i++) {
3962 if (obj->nodeTab[i] == NULL) {
3963 fprintf(output, " NULL !\n");
3964 return;
3965 }
3966 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
3967 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
3968 fprintf(output, " /");
3969 else if (obj->nodeTab[i]->name == NULL)
3970 fprintf(output, " noname!");
3971 else fprintf(output, " %s", obj->nodeTab[i]->name);
3972 }
3973 fprintf(output, "\n");
3974}
3975#endif
3976
3977/**
3978 * xmlXPathNewNodeSet:
3979 * @val: the NodePtr value
3980 *
3981 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3982 * it with the single Node @val
3983 *
3984 * Returns the newly created object.
3985 */
3986xmlXPathObjectPtr
3987xmlXPathNewNodeSet(xmlNodePtr val) {
3988 xmlXPathObjectPtr ret;
3989
3990 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3991 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003992 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003993 return(NULL);
3994 }
3995 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3996 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00003997 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003998 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00003999 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004000#ifdef XP_DEBUG_OBJ_USAGE
4001 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4002#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004003 return(ret);
4004}
4005
4006/**
4007 * xmlXPathNewValueTree:
4008 * @val: the NodePtr value
4009 *
4010 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4011 * it with the tree root @val
4012 *
4013 * Returns the newly created object.
4014 */
4015xmlXPathObjectPtr
4016xmlXPathNewValueTree(xmlNodePtr val) {
4017 xmlXPathObjectPtr ret;
4018
4019 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4020 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004021 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004022 return(NULL);
4023 }
4024 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4025 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004026 ret->boolval = 1;
4027 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004028 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004029#ifdef XP_DEBUG_OBJ_USAGE
4030 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4031#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004032 return(ret);
4033}
4034
4035/**
4036 * xmlXPathNewNodeSetList:
4037 * @val: an existing NodeSet
4038 *
4039 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4040 * it with the Nodeset @val
4041 *
4042 * Returns the newly created object.
4043 */
4044xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004045xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4046{
Owen Taylor3473f882001-02-23 17:55:21 +00004047 xmlXPathObjectPtr ret;
4048 int i;
4049
4050 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004051 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004052 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004053 ret = xmlXPathNewNodeSet(NULL);
4054 else {
4055 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4056 for (i = 1; i < val->nodeNr; ++i)
4057 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4058 }
Owen Taylor3473f882001-02-23 17:55:21 +00004059
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004060 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004061}
4062
4063/**
4064 * xmlXPathWrapNodeSet:
4065 * @val: the NodePtr value
4066 *
4067 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4068 *
4069 * Returns the newly created object.
4070 */
4071xmlXPathObjectPtr
4072xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4073 xmlXPathObjectPtr ret;
4074
4075 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4076 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004077 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004078 return(NULL);
4079 }
4080 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4081 ret->type = XPATH_NODESET;
4082 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004083#ifdef XP_DEBUG_OBJ_USAGE
4084 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4085#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004086 return(ret);
4087}
4088
4089/**
4090 * xmlXPathFreeNodeSetList:
4091 * @obj: an existing NodeSetList object
4092 *
4093 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4094 * the list contrary to xmlXPathFreeObject().
4095 */
4096void
4097xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4098 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004099#ifdef XP_DEBUG_OBJ_USAGE
4100 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4101#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004102 xmlFree(obj);
4103}
4104
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004105/**
4106 * xmlXPathDifference:
4107 * @nodes1: a node-set
4108 * @nodes2: a node-set
4109 *
4110 * Implements the EXSLT - Sets difference() function:
4111 * node-set set:difference (node-set, node-set)
4112 *
4113 * Returns the difference between the two node sets, or nodes1 if
4114 * nodes2 is empty
4115 */
4116xmlNodeSetPtr
4117xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4118 xmlNodeSetPtr ret;
4119 int i, l1;
4120 xmlNodePtr cur;
4121
4122 if (xmlXPathNodeSetIsEmpty(nodes2))
4123 return(nodes1);
4124
4125 ret = xmlXPathNodeSetCreate(NULL);
4126 if (xmlXPathNodeSetIsEmpty(nodes1))
4127 return(ret);
4128
4129 l1 = xmlXPathNodeSetGetLength(nodes1);
4130
4131 for (i = 0; i < l1; i++) {
4132 cur = xmlXPathNodeSetItem(nodes1, i);
4133 if (!xmlXPathNodeSetContains(nodes2, cur))
4134 xmlXPathNodeSetAddUnique(ret, cur);
4135 }
4136 return(ret);
4137}
4138
4139/**
4140 * xmlXPathIntersection:
4141 * @nodes1: a node-set
4142 * @nodes2: a node-set
4143 *
4144 * Implements the EXSLT - Sets intersection() function:
4145 * node-set set:intersection (node-set, node-set)
4146 *
4147 * Returns a node set comprising the nodes that are within both the
4148 * node sets passed as arguments
4149 */
4150xmlNodeSetPtr
4151xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4152 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4153 int i, l1;
4154 xmlNodePtr cur;
4155
4156 if (xmlXPathNodeSetIsEmpty(nodes1))
4157 return(ret);
4158 if (xmlXPathNodeSetIsEmpty(nodes2))
4159 return(ret);
4160
4161 l1 = xmlXPathNodeSetGetLength(nodes1);
4162
4163 for (i = 0; i < l1; i++) {
4164 cur = xmlXPathNodeSetItem(nodes1, i);
4165 if (xmlXPathNodeSetContains(nodes2, cur))
4166 xmlXPathNodeSetAddUnique(ret, cur);
4167 }
4168 return(ret);
4169}
4170
4171/**
4172 * xmlXPathDistinctSorted:
4173 * @nodes: a node-set, sorted by document order
4174 *
4175 * Implements the EXSLT - Sets distinct() function:
4176 * node-set set:distinct (node-set)
4177 *
4178 * Returns a subset of the nodes contained in @nodes, or @nodes if
4179 * it is empty
4180 */
4181xmlNodeSetPtr
4182xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4183 xmlNodeSetPtr ret;
4184 xmlHashTablePtr hash;
4185 int i, l;
4186 xmlChar * strval;
4187 xmlNodePtr cur;
4188
4189 if (xmlXPathNodeSetIsEmpty(nodes))
4190 return(nodes);
4191
4192 ret = xmlXPathNodeSetCreate(NULL);
4193 l = xmlXPathNodeSetGetLength(nodes);
4194 hash = xmlHashCreate (l);
4195 for (i = 0; i < l; i++) {
4196 cur = xmlXPathNodeSetItem(nodes, i);
4197 strval = xmlXPathCastNodeToString(cur);
4198 if (xmlHashLookup(hash, strval) == NULL) {
4199 xmlHashAddEntry(hash, strval, strval);
4200 xmlXPathNodeSetAddUnique(ret, cur);
4201 } else {
4202 xmlFree(strval);
4203 }
4204 }
4205 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4206 return(ret);
4207}
4208
4209/**
4210 * xmlXPathDistinct:
4211 * @nodes: a node-set
4212 *
4213 * Implements the EXSLT - Sets distinct() function:
4214 * node-set set:distinct (node-set)
4215 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4216 * is called with the sorted node-set
4217 *
4218 * Returns a subset of the nodes contained in @nodes, or @nodes if
4219 * it is empty
4220 */
4221xmlNodeSetPtr
4222xmlXPathDistinct (xmlNodeSetPtr nodes) {
4223 if (xmlXPathNodeSetIsEmpty(nodes))
4224 return(nodes);
4225
4226 xmlXPathNodeSetSort(nodes);
4227 return(xmlXPathDistinctSorted(nodes));
4228}
4229
4230/**
4231 * xmlXPathHasSameNodes:
4232 * @nodes1: a node-set
4233 * @nodes2: a node-set
4234 *
4235 * Implements the EXSLT - Sets has-same-nodes function:
4236 * boolean set:has-same-node(node-set, node-set)
4237 *
4238 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4239 * otherwise
4240 */
4241int
4242xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4243 int i, l;
4244 xmlNodePtr cur;
4245
4246 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4247 xmlXPathNodeSetIsEmpty(nodes2))
4248 return(0);
4249
4250 l = xmlXPathNodeSetGetLength(nodes1);
4251 for (i = 0; i < l; i++) {
4252 cur = xmlXPathNodeSetItem(nodes1, i);
4253 if (xmlXPathNodeSetContains(nodes2, cur))
4254 return(1);
4255 }
4256 return(0);
4257}
4258
4259/**
4260 * xmlXPathNodeLeadingSorted:
4261 * @nodes: a node-set, sorted by document order
4262 * @node: a node
4263 *
4264 * Implements the EXSLT - Sets leading() function:
4265 * node-set set:leading (node-set, node-set)
4266 *
4267 * Returns the nodes in @nodes that precede @node in document order,
4268 * @nodes if @node is NULL or an empty node-set if @nodes
4269 * doesn't contain @node
4270 */
4271xmlNodeSetPtr
4272xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4273 int i, l;
4274 xmlNodePtr cur;
4275 xmlNodeSetPtr ret;
4276
4277 if (node == NULL)
4278 return(nodes);
4279
4280 ret = xmlXPathNodeSetCreate(NULL);
4281 if (xmlXPathNodeSetIsEmpty(nodes) ||
4282 (!xmlXPathNodeSetContains(nodes, node)))
4283 return(ret);
4284
4285 l = xmlXPathNodeSetGetLength(nodes);
4286 for (i = 0; i < l; i++) {
4287 cur = xmlXPathNodeSetItem(nodes, i);
4288 if (cur == node)
4289 break;
4290 xmlXPathNodeSetAddUnique(ret, cur);
4291 }
4292 return(ret);
4293}
4294
4295/**
4296 * xmlXPathNodeLeading:
4297 * @nodes: a node-set
4298 * @node: a node
4299 *
4300 * Implements the EXSLT - Sets leading() function:
4301 * node-set set:leading (node-set, node-set)
4302 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4303 * is called.
4304 *
4305 * Returns the nodes in @nodes that precede @node in document order,
4306 * @nodes if @node is NULL or an empty node-set if @nodes
4307 * doesn't contain @node
4308 */
4309xmlNodeSetPtr
4310xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4311 xmlXPathNodeSetSort(nodes);
4312 return(xmlXPathNodeLeadingSorted(nodes, node));
4313}
4314
4315/**
4316 * xmlXPathLeadingSorted:
4317 * @nodes1: a node-set, sorted by document order
4318 * @nodes2: a node-set, sorted by document order
4319 *
4320 * Implements the EXSLT - Sets leading() function:
4321 * node-set set:leading (node-set, node-set)
4322 *
4323 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4324 * in document order, @nodes1 if @nodes2 is NULL or empty or
4325 * an empty node-set if @nodes1 doesn't contain @nodes2
4326 */
4327xmlNodeSetPtr
4328xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4329 if (xmlXPathNodeSetIsEmpty(nodes2))
4330 return(nodes1);
4331 return(xmlXPathNodeLeadingSorted(nodes1,
4332 xmlXPathNodeSetItem(nodes2, 1)));
4333}
4334
4335/**
4336 * xmlXPathLeading:
4337 * @nodes1: a node-set
4338 * @nodes2: a node-set
4339 *
4340 * Implements the EXSLT - Sets leading() function:
4341 * node-set set:leading (node-set, node-set)
4342 * @nodes1 and @nodes2 are sorted by document order, then
4343 * #exslSetsLeadingSorted is called.
4344 *
4345 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4346 * in document order, @nodes1 if @nodes2 is NULL or empty or
4347 * an empty node-set if @nodes1 doesn't contain @nodes2
4348 */
4349xmlNodeSetPtr
4350xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4351 if (xmlXPathNodeSetIsEmpty(nodes2))
4352 return(nodes1);
4353 if (xmlXPathNodeSetIsEmpty(nodes1))
4354 return(xmlXPathNodeSetCreate(NULL));
4355 xmlXPathNodeSetSort(nodes1);
4356 xmlXPathNodeSetSort(nodes2);
4357 return(xmlXPathNodeLeadingSorted(nodes1,
4358 xmlXPathNodeSetItem(nodes2, 1)));
4359}
4360
4361/**
4362 * xmlXPathNodeTrailingSorted:
4363 * @nodes: a node-set, sorted by document order
4364 * @node: a node
4365 *
4366 * Implements the EXSLT - Sets trailing() function:
4367 * node-set set:trailing (node-set, node-set)
4368 *
4369 * Returns the nodes in @nodes that follow @node in document order,
4370 * @nodes if @node is NULL or an empty node-set if @nodes
4371 * doesn't contain @node
4372 */
4373xmlNodeSetPtr
4374xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4375 int i, l;
4376 xmlNodePtr cur;
4377 xmlNodeSetPtr ret;
4378
4379 if (node == NULL)
4380 return(nodes);
4381
4382 ret = xmlXPathNodeSetCreate(NULL);
4383 if (xmlXPathNodeSetIsEmpty(nodes) ||
4384 (!xmlXPathNodeSetContains(nodes, node)))
4385 return(ret);
4386
4387 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004388 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004389 cur = xmlXPathNodeSetItem(nodes, i);
4390 if (cur == node)
4391 break;
4392 xmlXPathNodeSetAddUnique(ret, cur);
4393 }
4394 return(ret);
4395}
4396
4397/**
4398 * xmlXPathNodeTrailing:
4399 * @nodes: a node-set
4400 * @node: a node
4401 *
4402 * Implements the EXSLT - Sets trailing() function:
4403 * node-set set:trailing (node-set, node-set)
4404 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4405 * is called.
4406 *
4407 * Returns the nodes in @nodes that follow @node in document order,
4408 * @nodes if @node is NULL or an empty node-set if @nodes
4409 * doesn't contain @node
4410 */
4411xmlNodeSetPtr
4412xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4413 xmlXPathNodeSetSort(nodes);
4414 return(xmlXPathNodeTrailingSorted(nodes, node));
4415}
4416
4417/**
4418 * xmlXPathTrailingSorted:
4419 * @nodes1: a node-set, sorted by document order
4420 * @nodes2: a node-set, sorted by document order
4421 *
4422 * Implements the EXSLT - Sets trailing() function:
4423 * node-set set:trailing (node-set, node-set)
4424 *
4425 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4426 * in document order, @nodes1 if @nodes2 is NULL or empty or
4427 * an empty node-set if @nodes1 doesn't contain @nodes2
4428 */
4429xmlNodeSetPtr
4430xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4431 if (xmlXPathNodeSetIsEmpty(nodes2))
4432 return(nodes1);
4433 return(xmlXPathNodeTrailingSorted(nodes1,
4434 xmlXPathNodeSetItem(nodes2, 0)));
4435}
4436
4437/**
4438 * xmlXPathTrailing:
4439 * @nodes1: a node-set
4440 * @nodes2: a node-set
4441 *
4442 * Implements the EXSLT - Sets trailing() function:
4443 * node-set set:trailing (node-set, node-set)
4444 * @nodes1 and @nodes2 are sorted by document order, then
4445 * #xmlXPathTrailingSorted is called.
4446 *
4447 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4448 * in document order, @nodes1 if @nodes2 is NULL or empty or
4449 * an empty node-set if @nodes1 doesn't contain @nodes2
4450 */
4451xmlNodeSetPtr
4452xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4453 if (xmlXPathNodeSetIsEmpty(nodes2))
4454 return(nodes1);
4455 if (xmlXPathNodeSetIsEmpty(nodes1))
4456 return(xmlXPathNodeSetCreate(NULL));
4457 xmlXPathNodeSetSort(nodes1);
4458 xmlXPathNodeSetSort(nodes2);
4459 return(xmlXPathNodeTrailingSorted(nodes1,
4460 xmlXPathNodeSetItem(nodes2, 0)));
4461}
4462
Owen Taylor3473f882001-02-23 17:55:21 +00004463/************************************************************************
4464 * *
4465 * Routines to handle extra functions *
4466 * *
4467 ************************************************************************/
4468
4469/**
4470 * xmlXPathRegisterFunc:
4471 * @ctxt: the XPath context
4472 * @name: the function name
4473 * @f: the function implementation or NULL
4474 *
4475 * Register a new function. If @f is NULL it unregisters the function
4476 *
4477 * Returns 0 in case of success, -1 in case of error
4478 */
4479int
4480xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4481 xmlXPathFunction f) {
4482 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4483}
4484
4485/**
4486 * xmlXPathRegisterFuncNS:
4487 * @ctxt: the XPath context
4488 * @name: the function name
4489 * @ns_uri: the function namespace URI
4490 * @f: the function implementation or NULL
4491 *
4492 * Register a new function. If @f is NULL it unregisters the function
4493 *
4494 * Returns 0 in case of success, -1 in case of error
4495 */
4496int
4497xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4498 const xmlChar *ns_uri, xmlXPathFunction f) {
4499 if (ctxt == NULL)
4500 return(-1);
4501 if (name == NULL)
4502 return(-1);
4503
4504 if (ctxt->funcHash == NULL)
4505 ctxt->funcHash = xmlHashCreate(0);
4506 if (ctxt->funcHash == NULL)
4507 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004508 if (f == NULL)
4509 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004510 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004511}
4512
4513/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004514 * xmlXPathRegisterFuncLookup:
4515 * @ctxt: the XPath context
4516 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004517 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004518 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004519 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004520 */
4521void
4522xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4523 xmlXPathFuncLookupFunc f,
4524 void *funcCtxt) {
4525 if (ctxt == NULL)
4526 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004527 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004528 ctxt->funcLookupData = funcCtxt;
4529}
4530
4531/**
Owen Taylor3473f882001-02-23 17:55:21 +00004532 * xmlXPathFunctionLookup:
4533 * @ctxt: the XPath context
4534 * @name: the function name
4535 *
4536 * Search in the Function array of the context for the given
4537 * function.
4538 *
4539 * Returns the xmlXPathFunction or NULL if not found
4540 */
4541xmlXPathFunction
4542xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004543 if (ctxt == NULL)
4544 return (NULL);
4545
4546 if (ctxt->funcLookupFunc != NULL) {
4547 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004548 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004549
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004550 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004551 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004552 if (ret != NULL)
4553 return(ret);
4554 }
Owen Taylor3473f882001-02-23 17:55:21 +00004555 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4556}
4557
4558/**
4559 * xmlXPathFunctionLookupNS:
4560 * @ctxt: the XPath context
4561 * @name: the function name
4562 * @ns_uri: the function namespace URI
4563 *
4564 * Search in the Function array of the context for the given
4565 * function.
4566 *
4567 * Returns the xmlXPathFunction or NULL if not found
4568 */
4569xmlXPathFunction
4570xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4571 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004572 xmlXPathFunction ret;
4573
Owen Taylor3473f882001-02-23 17:55:21 +00004574 if (ctxt == NULL)
4575 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004576 if (name == NULL)
4577 return(NULL);
4578
Thomas Broyerba4ad322001-07-26 16:55:21 +00004579 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004580 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004581
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004582 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004583 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004584 if (ret != NULL)
4585 return(ret);
4586 }
4587
4588 if (ctxt->funcHash == NULL)
4589 return(NULL);
4590
William M. Brackad0e67c2004-12-01 14:35:10 +00004591 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4592 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004593}
4594
4595/**
4596 * xmlXPathRegisteredFuncsCleanup:
4597 * @ctxt: the XPath context
4598 *
4599 * Cleanup the XPath context data associated to registered functions
4600 */
4601void
4602xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4603 if (ctxt == NULL)
4604 return;
4605
4606 xmlHashFree(ctxt->funcHash, NULL);
4607 ctxt->funcHash = NULL;
4608}
4609
4610/************************************************************************
4611 * *
William M. Brack08171912003-12-29 02:52:11 +00004612 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004613 * *
4614 ************************************************************************/
4615
4616/**
4617 * xmlXPathRegisterVariable:
4618 * @ctxt: the XPath context
4619 * @name: the variable name
4620 * @value: the variable value or NULL
4621 *
4622 * Register a new variable value. If @value is NULL it unregisters
4623 * the variable
4624 *
4625 * Returns 0 in case of success, -1 in case of error
4626 */
4627int
4628xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4629 xmlXPathObjectPtr value) {
4630 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4631}
4632
4633/**
4634 * xmlXPathRegisterVariableNS:
4635 * @ctxt: the XPath context
4636 * @name: the variable name
4637 * @ns_uri: the variable namespace URI
4638 * @value: the variable value or NULL
4639 *
4640 * Register a new variable value. If @value is NULL it unregisters
4641 * the variable
4642 *
4643 * Returns 0 in case of success, -1 in case of error
4644 */
4645int
4646xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4647 const xmlChar *ns_uri,
4648 xmlXPathObjectPtr value) {
4649 if (ctxt == NULL)
4650 return(-1);
4651 if (name == NULL)
4652 return(-1);
4653
4654 if (ctxt->varHash == NULL)
4655 ctxt->varHash = xmlHashCreate(0);
4656 if (ctxt->varHash == NULL)
4657 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004658 if (value == NULL)
4659 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4660 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004661 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4662 (void *) value,
4663 (xmlHashDeallocator)xmlXPathFreeObject));
4664}
4665
4666/**
4667 * xmlXPathRegisterVariableLookup:
4668 * @ctxt: the XPath context
4669 * @f: the lookup function
4670 * @data: the lookup data
4671 *
4672 * register an external mechanism to do variable lookup
4673 */
4674void
4675xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4676 xmlXPathVariableLookupFunc f, void *data) {
4677 if (ctxt == NULL)
4678 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004679 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004680 ctxt->varLookupData = data;
4681}
4682
4683/**
4684 * xmlXPathVariableLookup:
4685 * @ctxt: the XPath context
4686 * @name: the variable name
4687 *
4688 * Search in the Variable array of the context for the given
4689 * variable value.
4690 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004691 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004692 */
4693xmlXPathObjectPtr
4694xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4695 if (ctxt == NULL)
4696 return(NULL);
4697
4698 if (ctxt->varLookupFunc != NULL) {
4699 xmlXPathObjectPtr ret;
4700
4701 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4702 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004703 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004704 }
4705 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4706}
4707
4708/**
4709 * xmlXPathVariableLookupNS:
4710 * @ctxt: the XPath context
4711 * @name: the variable name
4712 * @ns_uri: the variable namespace URI
4713 *
4714 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004715 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004716 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004717 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004718 */
4719xmlXPathObjectPtr
4720xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4721 const xmlChar *ns_uri) {
4722 if (ctxt == NULL)
4723 return(NULL);
4724
4725 if (ctxt->varLookupFunc != NULL) {
4726 xmlXPathObjectPtr ret;
4727
4728 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4729 (ctxt->varLookupData, name, ns_uri);
4730 if (ret != NULL) return(ret);
4731 }
4732
4733 if (ctxt->varHash == NULL)
4734 return(NULL);
4735 if (name == NULL)
4736 return(NULL);
4737
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004738 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004739 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004740}
4741
4742/**
4743 * xmlXPathRegisteredVariablesCleanup:
4744 * @ctxt: the XPath context
4745 *
4746 * Cleanup the XPath context data associated to registered variables
4747 */
4748void
4749xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4750 if (ctxt == NULL)
4751 return;
4752
Daniel Veillard76d66f42001-05-16 21:05:17 +00004753 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004754 ctxt->varHash = NULL;
4755}
4756
4757/**
4758 * xmlXPathRegisterNs:
4759 * @ctxt: the XPath context
4760 * @prefix: the namespace prefix
4761 * @ns_uri: the namespace name
4762 *
4763 * Register a new namespace. If @ns_uri is NULL it unregisters
4764 * the namespace
4765 *
4766 * Returns 0 in case of success, -1 in case of error
4767 */
4768int
4769xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4770 const xmlChar *ns_uri) {
4771 if (ctxt == NULL)
4772 return(-1);
4773 if (prefix == NULL)
4774 return(-1);
4775
4776 if (ctxt->nsHash == NULL)
4777 ctxt->nsHash = xmlHashCreate(10);
4778 if (ctxt->nsHash == NULL)
4779 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004780 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004781 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004782 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004783 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004784 (xmlHashDeallocator)xmlFree));
4785}
4786
4787/**
4788 * xmlXPathNsLookup:
4789 * @ctxt: the XPath context
4790 * @prefix: the namespace prefix value
4791 *
4792 * Search in the namespace declaration array of the context for the given
4793 * namespace name associated to the given prefix
4794 *
4795 * Returns the value or NULL if not found
4796 */
4797const xmlChar *
4798xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4799 if (ctxt == NULL)
4800 return(NULL);
4801 if (prefix == NULL)
4802 return(NULL);
4803
4804#ifdef XML_XML_NAMESPACE
4805 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4806 return(XML_XML_NAMESPACE);
4807#endif
4808
Daniel Veillardc8f620b2001-04-30 20:31:33 +00004809 if (ctxt->namespaces != NULL) {
4810 int i;
4811
4812 for (i = 0;i < ctxt->nsNr;i++) {
4813 if ((ctxt->namespaces[i] != NULL) &&
4814 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4815 return(ctxt->namespaces[i]->href);
4816 }
4817 }
Owen Taylor3473f882001-02-23 17:55:21 +00004818
4819 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4820}
4821
4822/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004823 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00004824 * @ctxt: the XPath context
4825 *
4826 * Cleanup the XPath context data associated to registered variables
4827 */
4828void
4829xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4830 if (ctxt == NULL)
4831 return;
4832
Daniel Veillard42766c02002-08-22 20:52:17 +00004833 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00004834 ctxt->nsHash = NULL;
4835}
4836
4837/************************************************************************
4838 * *
4839 * Routines to handle Values *
4840 * *
4841 ************************************************************************/
4842
William M. Brack08171912003-12-29 02:52:11 +00004843/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00004844
4845/**
4846 * xmlXPathNewFloat:
4847 * @val: the double value
4848 *
4849 * Create a new xmlXPathObjectPtr of type double and of value @val
4850 *
4851 * Returns the newly created object.
4852 */
4853xmlXPathObjectPtr
4854xmlXPathNewFloat(double 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 float 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_NUMBER;
4864 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004865#ifdef XP_DEBUG_OBJ_USAGE
4866 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
4867#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004868 return(ret);
4869}
4870
4871/**
4872 * xmlXPathNewBoolean:
4873 * @val: the boolean value
4874 *
4875 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4876 *
4877 * Returns the newly created object.
4878 */
4879xmlXPathObjectPtr
4880xmlXPathNewBoolean(int 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 boolean 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_BOOLEAN;
4890 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004891#ifdef XP_DEBUG_OBJ_USAGE
4892 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
4893#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004894 return(ret);
4895}
4896
4897/**
4898 * xmlXPathNewString:
4899 * @val: the xmlChar * value
4900 *
4901 * Create a new xmlXPathObjectPtr of type string and of value @val
4902 *
4903 * Returns the newly created object.
4904 */
4905xmlXPathObjectPtr
4906xmlXPathNewString(const xmlChar *val) {
4907 xmlXPathObjectPtr ret;
4908
4909 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4910 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004911 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004912 return(NULL);
4913 }
4914 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4915 ret->type = XPATH_STRING;
4916 if (val != NULL)
4917 ret->stringval = xmlStrdup(val);
4918 else
4919 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004920#ifdef XP_DEBUG_OBJ_USAGE
4921 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4922#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004923 return(ret);
4924}
4925
4926/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004927 * xmlXPathWrapString:
4928 * @val: the xmlChar * value
4929 *
4930 * Wraps the @val string into an XPath object.
4931 *
4932 * Returns the newly created object.
4933 */
4934xmlXPathObjectPtr
4935xmlXPathWrapString (xmlChar *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");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004941 return(NULL);
4942 }
4943 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4944 ret->type = XPATH_STRING;
4945 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004946#ifdef XP_DEBUG_OBJ_USAGE
4947 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4948#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004949 return(ret);
4950}
4951
4952/**
Owen Taylor3473f882001-02-23 17:55:21 +00004953 * xmlXPathNewCString:
4954 * @val: the char * value
4955 *
4956 * Create a new xmlXPathObjectPtr of type string and of value @val
4957 *
4958 * Returns the newly created object.
4959 */
4960xmlXPathObjectPtr
4961xmlXPathNewCString(const char *val) {
4962 xmlXPathObjectPtr ret;
4963
4964 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4965 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004966 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004967 return(NULL);
4968 }
4969 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4970 ret->type = XPATH_STRING;
4971 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004972#ifdef XP_DEBUG_OBJ_USAGE
4973 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4974#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004975 return(ret);
4976}
4977
4978/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004979 * xmlXPathWrapCString:
4980 * @val: the char * value
4981 *
4982 * Wraps a string into an XPath object.
4983 *
4984 * Returns the newly created object.
4985 */
4986xmlXPathObjectPtr
4987xmlXPathWrapCString (char * val) {
4988 return(xmlXPathWrapString((xmlChar *)(val)));
4989}
4990
4991/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004992 * xmlXPathWrapExternal:
4993 * @val: the user data
4994 *
4995 * Wraps the @val data into an XPath object.
4996 *
4997 * Returns the newly created object.
4998 */
4999xmlXPathObjectPtr
5000xmlXPathWrapExternal (void *val) {
5001 xmlXPathObjectPtr ret;
5002
5003 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5004 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005005 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005006 return(NULL);
5007 }
5008 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5009 ret->type = XPATH_USERS;
5010 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005011#ifdef XP_DEBUG_OBJ_USAGE
5012 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5013#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00005014 return(ret);
5015}
5016
5017/**
Owen Taylor3473f882001-02-23 17:55:21 +00005018 * xmlXPathObjectCopy:
5019 * @val: the original object
5020 *
5021 * allocate a new copy of a given object
5022 *
5023 * Returns the newly created object.
5024 */
5025xmlXPathObjectPtr
5026xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5027 xmlXPathObjectPtr ret;
5028
5029 if (val == NULL)
5030 return(NULL);
5031
5032 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5033 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005034 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005035 return(NULL);
5036 }
5037 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005038#ifdef XP_DEBUG_OBJ_USAGE
5039 xmlXPathDebugObjUsageRequested(NULL, val->type);
5040#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005041 switch (val->type) {
5042 case XPATH_BOOLEAN:
5043 case XPATH_NUMBER:
5044 case XPATH_POINT:
5045 case XPATH_RANGE:
5046 break;
5047 case XPATH_STRING:
5048 ret->stringval = xmlStrdup(val->stringval);
5049 break;
5050 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005051#if 0
5052/*
5053 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5054 this previous handling is no longer correct, and can cause some serious
5055 problems (ref. bug 145547)
5056*/
Owen Taylor3473f882001-02-23 17:55:21 +00005057 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005058 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005059 xmlNodePtr cur, tmp;
5060 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005061
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005062 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005063 top = xmlNewDoc(NULL);
5064 top->name = (char *)
5065 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005066 ret->user = top;
5067 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005068 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005069 cur = val->nodesetval->nodeTab[0]->children;
5070 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005071 tmp = xmlDocCopyNode(cur, top, 1);
5072 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005073 cur = cur->next;
5074 }
5075 }
William M. Bracke9449c52004-07-11 14:41:20 +00005076
Daniel Veillard9adc0462003-03-24 18:39:54 +00005077 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005078 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005079 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005080 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005081 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005082#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005083 case XPATH_NODESET:
5084 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005085 /* Do not deallocate the copied tree value */
5086 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005087 break;
5088 case XPATH_LOCATIONSET:
5089#ifdef LIBXML_XPTR_ENABLED
5090 {
5091 xmlLocationSetPtr loc = val->user;
5092 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5093 break;
5094 }
5095#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005096 case XPATH_USERS:
5097 ret->user = val->user;
5098 break;
5099 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005100 xmlGenericError(xmlGenericErrorContext,
5101 "xmlXPathObjectCopy: unsupported type %d\n",
5102 val->type);
5103 break;
5104 }
5105 return(ret);
5106}
5107
5108/**
5109 * xmlXPathFreeObject:
5110 * @obj: the object to free
5111 *
5112 * Free up an xmlXPathObjectPtr object.
5113 */
5114void
5115xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5116 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005117 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005118 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005119#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005120 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005121 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005122 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005123 } else
5124#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005125 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005126 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005127 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005128 } else {
5129 if (obj->nodesetval != NULL)
5130 xmlXPathFreeNodeSet(obj->nodesetval);
5131 }
Owen Taylor3473f882001-02-23 17:55:21 +00005132#ifdef LIBXML_XPTR_ENABLED
5133 } else if (obj->type == XPATH_LOCATIONSET) {
5134 if (obj->user != NULL)
5135 xmlXPtrFreeLocationSet(obj->user);
5136#endif
5137 } else if (obj->type == XPATH_STRING) {
5138 if (obj->stringval != NULL)
5139 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005140 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005141#ifdef XP_DEBUG_OBJ_USAGE
5142 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5143#endif
5144 xmlFree(obj);
5145}
Owen Taylor3473f882001-02-23 17:55:21 +00005146
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005147/**
5148 * xmlXPathReleaseObject:
5149 * @obj: the xmlXPathObjectPtr to free or to cache
5150 *
5151 * Depending on the state of the cache this frees the given
5152 * XPath object or stores it in the cache.
5153 */
5154static void
5155xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5156{
5157#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5158 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5159 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5160
5161#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5162
5163 if (obj == NULL)
5164 return;
5165 if ((ctxt == NULL) || (ctxt->objCache == NULL)) {
5166 xmlXPathFreeObject(obj);
5167 } else {
5168 xmlXPathObjectCachePtr cache =
5169 (xmlXPathObjectCachePtr) ctxt->objCache;
5170
5171 switch (obj->type) {
5172 case XPATH_NODESET:
5173 case XPATH_XSLT_TREE:
5174 if (obj->nodesetval != NULL) {
5175 if (obj->boolval) {
5176 /*
5177 * It looks like the @boolval is used for
5178 * evaluation if this an XSLT Result Tree Fragment.
5179 * TODO: Check if this assumption is correct.
5180 */
5181 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5182 xmlXPathFreeValueTree(obj->nodesetval);
5183 obj->nodesetval = NULL;
5184 } else if ((obj->nodesetval->nodeMax <= 40) &&
5185 (XP_CACHE_WANTS(cache->nodesetObjs,
5186 cache->maxNodeset)))
5187 {
5188 XP_CACHE_ADD(cache->nodesetObjs, obj);
5189 goto obj_cached;
5190 } else {
5191 xmlXPathFreeNodeSet(obj->nodesetval);
5192 obj->nodesetval = NULL;
5193 }
5194 }
5195 break;
5196 case XPATH_STRING:
5197 if (obj->stringval != NULL)
5198 xmlFree(obj->stringval);
5199
5200 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5201 XP_CACHE_ADD(cache->stringObjs, obj);
5202 goto obj_cached;
5203 }
5204 break;
5205 case XPATH_BOOLEAN:
5206 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5207 XP_CACHE_ADD(cache->booleanObjs, obj);
5208 goto obj_cached;
5209 }
5210 break;
5211 case XPATH_NUMBER:
5212 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5213 XP_CACHE_ADD(cache->numberObjs, obj);
5214 goto obj_cached;
5215 }
5216 break;
5217#ifdef LIBXML_XPTR_ENABLED
5218 case XPATH_LOCATIONSET:
5219 if (obj->user != NULL) {
5220 xmlXPtrFreeLocationSet(obj->user);
5221 }
5222 goto free_obj;
5223#endif
5224 default:
5225 goto free_obj;
5226 }
5227
5228 /*
5229 * Fallback to adding to the misc-objects slot.
5230 */
5231 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5232 XP_CACHE_ADD(cache->miscObjs, obj);
5233 } else
5234 goto free_obj;
5235
5236obj_cached:
5237
5238#ifdef XP_DEBUG_OBJ_USAGE
5239 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5240#endif
5241
5242 if (obj->nodesetval != NULL) {
5243 xmlNodeSetPtr tmpset = obj->nodesetval;
5244
5245 /*
5246 * TODO: Due to those nasty ns-nodes, we need to traverse
5247 * the list and free the ns-nodes.
5248 * URGENT TODO: Check if it's actually slowing things down.
5249 * Maybe we shouldn't try to preserve the list.
5250 */
5251 if (tmpset->nodeNr > 1) {
5252 int i;
5253 xmlNodePtr node;
5254
5255 for (i = 0; i < tmpset->nodeNr; i++) {
5256 node = tmpset->nodeTab[i];
5257 if ((node != NULL) &&
5258 (node->type == XML_NAMESPACE_DECL))
5259 {
5260 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5261 }
5262 }
5263 } else if (tmpset->nodeNr == 1) {
5264 if ((tmpset->nodeTab[0] != NULL) &&
5265 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5266 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5267 }
5268 tmpset->nodeNr = 0;
5269 memset(obj, 0, sizeof(xmlXPathObject));
5270 obj->nodesetval = tmpset;
5271 } else
5272 memset(obj, 0, sizeof(xmlXPathObject));
5273
5274 return;
5275
5276free_obj:
5277 /*
5278 * Cache is full; free the object.
5279 */
5280 if (obj->nodesetval != NULL)
5281 xmlXPathFreeNodeSet(obj->nodesetval);
5282#ifdef XP_DEBUG_OBJ_USAGE
5283 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5284#endif
5285 xmlFree(obj);
5286 }
5287 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005288}
5289
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005290
5291/************************************************************************
5292 * *
5293 * Type Casting Routines *
5294 * *
5295 ************************************************************************/
5296
5297/**
5298 * xmlXPathCastBooleanToString:
5299 * @val: a boolean
5300 *
5301 * Converts a boolean to its string value.
5302 *
5303 * Returns a newly allocated string.
5304 */
5305xmlChar *
5306xmlXPathCastBooleanToString (int val) {
5307 xmlChar *ret;
5308 if (val)
5309 ret = xmlStrdup((const xmlChar *) "true");
5310 else
5311 ret = xmlStrdup((const xmlChar *) "false");
5312 return(ret);
5313}
5314
5315/**
5316 * xmlXPathCastNumberToString:
5317 * @val: a number
5318 *
5319 * Converts a number to its string value.
5320 *
5321 * Returns a newly allocated string.
5322 */
5323xmlChar *
5324xmlXPathCastNumberToString (double val) {
5325 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005326 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005327 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005328 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005329 break;
5330 case -1:
5331 ret = xmlStrdup((const xmlChar *) "-Infinity");
5332 break;
5333 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005334 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005335 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005336 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5337 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005338 } else {
5339 /* could be improved */
5340 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005341 xmlXPathFormatNumber(val, buf, 99);
5342 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005343 ret = xmlStrdup((const xmlChar *) buf);
5344 }
5345 }
5346 return(ret);
5347}
5348
5349/**
5350 * xmlXPathCastNodeToString:
5351 * @node: a node
5352 *
5353 * Converts a node to its string value.
5354 *
5355 * Returns a newly allocated string.
5356 */
5357xmlChar *
5358xmlXPathCastNodeToString (xmlNodePtr node) {
5359 return(xmlNodeGetContent(node));
5360}
5361
5362/**
5363 * xmlXPathCastNodeSetToString:
5364 * @ns: a node-set
5365 *
5366 * Converts a node-set to its string value.
5367 *
5368 * Returns a newly allocated string.
5369 */
5370xmlChar *
5371xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5372 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5373 return(xmlStrdup((const xmlChar *) ""));
5374
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005375 if (ns->nodeNr > 1)
5376 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005377 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5378}
5379
5380/**
5381 * xmlXPathCastToString:
5382 * @val: an XPath object
5383 *
5384 * Converts an existing object to its string() equivalent
5385 *
5386 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005387 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005388 * string object).
5389 */
5390xmlChar *
5391xmlXPathCastToString(xmlXPathObjectPtr val) {
5392 xmlChar *ret = NULL;
5393
5394 if (val == NULL)
5395 return(xmlStrdup((const xmlChar *) ""));
5396 switch (val->type) {
5397 case XPATH_UNDEFINED:
5398#ifdef DEBUG_EXPR
5399 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5400#endif
5401 ret = xmlStrdup((const xmlChar *) "");
5402 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005403 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005404 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005405 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5406 break;
5407 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005408 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005409 case XPATH_BOOLEAN:
5410 ret = xmlXPathCastBooleanToString(val->boolval);
5411 break;
5412 case XPATH_NUMBER: {
5413 ret = xmlXPathCastNumberToString(val->floatval);
5414 break;
5415 }
5416 case XPATH_USERS:
5417 case XPATH_POINT:
5418 case XPATH_RANGE:
5419 case XPATH_LOCATIONSET:
5420 TODO
5421 ret = xmlStrdup((const xmlChar *) "");
5422 break;
5423 }
5424 return(ret);
5425}
5426
5427/**
5428 * xmlXPathConvertString:
5429 * @val: an XPath object
5430 *
5431 * Converts an existing object to its string() equivalent
5432 *
5433 * Returns the new object, the old one is freed (or the operation
5434 * is done directly on @val)
5435 */
5436xmlXPathObjectPtr
5437xmlXPathConvertString(xmlXPathObjectPtr val) {
5438 xmlChar *res = NULL;
5439
5440 if (val == NULL)
5441 return(xmlXPathNewCString(""));
5442
5443 switch (val->type) {
5444 case XPATH_UNDEFINED:
5445#ifdef DEBUG_EXPR
5446 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5447#endif
5448 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005449 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005450 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005451 res = xmlXPathCastNodeSetToString(val->nodesetval);
5452 break;
5453 case XPATH_STRING:
5454 return(val);
5455 case XPATH_BOOLEAN:
5456 res = xmlXPathCastBooleanToString(val->boolval);
5457 break;
5458 case XPATH_NUMBER:
5459 res = xmlXPathCastNumberToString(val->floatval);
5460 break;
5461 case XPATH_USERS:
5462 case XPATH_POINT:
5463 case XPATH_RANGE:
5464 case XPATH_LOCATIONSET:
5465 TODO;
5466 break;
5467 }
5468 xmlXPathFreeObject(val);
5469 if (res == NULL)
5470 return(xmlXPathNewCString(""));
5471 return(xmlXPathWrapString(res));
5472}
5473
5474/**
5475 * xmlXPathCastBooleanToNumber:
5476 * @val: a boolean
5477 *
5478 * Converts a boolean to its number value
5479 *
5480 * Returns the number value
5481 */
5482double
5483xmlXPathCastBooleanToNumber(int val) {
5484 if (val)
5485 return(1.0);
5486 return(0.0);
5487}
5488
5489/**
5490 * xmlXPathCastStringToNumber:
5491 * @val: a string
5492 *
5493 * Converts a string to its number value
5494 *
5495 * Returns the number value
5496 */
5497double
5498xmlXPathCastStringToNumber(const xmlChar * val) {
5499 return(xmlXPathStringEvalNumber(val));
5500}
5501
5502/**
5503 * xmlXPathCastNodeToNumber:
5504 * @node: a node
5505 *
5506 * Converts a node to its number value
5507 *
5508 * Returns the number value
5509 */
5510double
5511xmlXPathCastNodeToNumber (xmlNodePtr node) {
5512 xmlChar *strval;
5513 double ret;
5514
5515 if (node == NULL)
5516 return(xmlXPathNAN);
5517 strval = xmlXPathCastNodeToString(node);
5518 if (strval == NULL)
5519 return(xmlXPathNAN);
5520 ret = xmlXPathCastStringToNumber(strval);
5521 xmlFree(strval);
5522
5523 return(ret);
5524}
5525
5526/**
5527 * xmlXPathCastNodeSetToNumber:
5528 * @ns: a node-set
5529 *
5530 * Converts a node-set to its number value
5531 *
5532 * Returns the number value
5533 */
5534double
5535xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5536 xmlChar *str;
5537 double ret;
5538
5539 if (ns == NULL)
5540 return(xmlXPathNAN);
5541 str = xmlXPathCastNodeSetToString(ns);
5542 ret = xmlXPathCastStringToNumber(str);
5543 xmlFree(str);
5544 return(ret);
5545}
5546
5547/**
5548 * xmlXPathCastToNumber:
5549 * @val: an XPath object
5550 *
5551 * Converts an XPath object to its number value
5552 *
5553 * Returns the number value
5554 */
5555double
5556xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5557 double ret = 0.0;
5558
5559 if (val == NULL)
5560 return(xmlXPathNAN);
5561 switch (val->type) {
5562 case XPATH_UNDEFINED:
5563#ifdef DEGUB_EXPR
5564 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5565#endif
5566 ret = xmlXPathNAN;
5567 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005568 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005569 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005570 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5571 break;
5572 case XPATH_STRING:
5573 ret = xmlXPathCastStringToNumber(val->stringval);
5574 break;
5575 case XPATH_NUMBER:
5576 ret = val->floatval;
5577 break;
5578 case XPATH_BOOLEAN:
5579 ret = xmlXPathCastBooleanToNumber(val->boolval);
5580 break;
5581 case XPATH_USERS:
5582 case XPATH_POINT:
5583 case XPATH_RANGE:
5584 case XPATH_LOCATIONSET:
5585 TODO;
5586 ret = xmlXPathNAN;
5587 break;
5588 }
5589 return(ret);
5590}
5591
5592/**
5593 * xmlXPathConvertNumber:
5594 * @val: an XPath object
5595 *
5596 * Converts an existing object to its number() equivalent
5597 *
5598 * Returns the new object, the old one is freed (or the operation
5599 * is done directly on @val)
5600 */
5601xmlXPathObjectPtr
5602xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5603 xmlXPathObjectPtr ret;
5604
5605 if (val == NULL)
5606 return(xmlXPathNewFloat(0.0));
5607 if (val->type == XPATH_NUMBER)
5608 return(val);
5609 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5610 xmlXPathFreeObject(val);
5611 return(ret);
5612}
5613
5614/**
5615 * xmlXPathCastNumberToBoolean:
5616 * @val: a number
5617 *
5618 * Converts a number to its boolean value
5619 *
5620 * Returns the boolean value
5621 */
5622int
5623xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005624 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005625 return(0);
5626 return(1);
5627}
5628
5629/**
5630 * xmlXPathCastStringToBoolean:
5631 * @val: a string
5632 *
5633 * Converts a string to its boolean value
5634 *
5635 * Returns the boolean value
5636 */
5637int
5638xmlXPathCastStringToBoolean (const xmlChar *val) {
5639 if ((val == NULL) || (xmlStrlen(val) == 0))
5640 return(0);
5641 return(1);
5642}
5643
5644/**
5645 * xmlXPathCastNodeSetToBoolean:
5646 * @ns: a node-set
5647 *
5648 * Converts a node-set to its boolean value
5649 *
5650 * Returns the boolean value
5651 */
5652int
5653xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5654 if ((ns == NULL) || (ns->nodeNr == 0))
5655 return(0);
5656 return(1);
5657}
5658
5659/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005660 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005661 * @val: an XPath object
5662 *
5663 * Converts an XPath object to its boolean value
5664 *
5665 * Returns the boolean value
5666 */
5667int
5668xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5669 int ret = 0;
5670
5671 if (val == NULL)
5672 return(0);
5673 switch (val->type) {
5674 case XPATH_UNDEFINED:
5675#ifdef DEBUG_EXPR
5676 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5677#endif
5678 ret = 0;
5679 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005680 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005681 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005682 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5683 break;
5684 case XPATH_STRING:
5685 ret = xmlXPathCastStringToBoolean(val->stringval);
5686 break;
5687 case XPATH_NUMBER:
5688 ret = xmlXPathCastNumberToBoolean(val->floatval);
5689 break;
5690 case XPATH_BOOLEAN:
5691 ret = val->boolval;
5692 break;
5693 case XPATH_USERS:
5694 case XPATH_POINT:
5695 case XPATH_RANGE:
5696 case XPATH_LOCATIONSET:
5697 TODO;
5698 ret = 0;
5699 break;
5700 }
5701 return(ret);
5702}
5703
5704
5705/**
5706 * xmlXPathConvertBoolean:
5707 * @val: an XPath object
5708 *
5709 * Converts an existing object to its boolean() equivalent
5710 *
5711 * Returns the new object, the old one is freed (or the operation
5712 * is done directly on @val)
5713 */
5714xmlXPathObjectPtr
5715xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5716 xmlXPathObjectPtr ret;
5717
5718 if (val == NULL)
5719 return(xmlXPathNewBoolean(0));
5720 if (val->type == XPATH_BOOLEAN)
5721 return(val);
5722 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5723 xmlXPathFreeObject(val);
5724 return(ret);
5725}
5726
Owen Taylor3473f882001-02-23 17:55:21 +00005727/************************************************************************
5728 * *
5729 * Routines to handle XPath contexts *
5730 * *
5731 ************************************************************************/
5732
5733/**
5734 * xmlXPathNewContext:
5735 * @doc: the XML document
5736 *
5737 * Create a new xmlXPathContext
5738 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005739 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005740 */
5741xmlXPathContextPtr
5742xmlXPathNewContext(xmlDocPtr doc) {
5743 xmlXPathContextPtr ret;
5744
5745 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5746 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005747 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005748 return(NULL);
5749 }
5750 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5751 ret->doc = doc;
5752 ret->node = NULL;
5753
5754 ret->varHash = NULL;
5755
5756 ret->nb_types = 0;
5757 ret->max_types = 0;
5758 ret->types = NULL;
5759
5760 ret->funcHash = xmlHashCreate(0);
5761
5762 ret->nb_axis = 0;
5763 ret->max_axis = 0;
5764 ret->axis = NULL;
5765
5766 ret->nsHash = NULL;
5767 ret->user = NULL;
5768
5769 ret->contextSize = -1;
5770 ret->proximityPosition = -1;
5771
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005772#ifdef XP_DEFAULT_CACHE_ON
5773 if (xmlXPathContextSetObjectCache(ret, 1, -1, 0) == -1) {
5774 xmlXPathFreeContext(ret);
5775 return(NULL);
5776 }
5777#endif
5778
5779 xmlXPathRegisterAllFunctions(ret);
5780
Owen Taylor3473f882001-02-23 17:55:21 +00005781 return(ret);
5782}
5783
5784/**
5785 * xmlXPathFreeContext:
5786 * @ctxt: the context to free
5787 *
5788 * Free up an xmlXPathContext
5789 */
5790void
5791xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005792 if (ctxt == NULL) return;
5793
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005794 if (ctxt->objCache != NULL)
5795 xmlXPathFreeObjectCache((xmlXPathObjectCachePtr) ctxt->objCache);
Owen Taylor3473f882001-02-23 17:55:21 +00005796 xmlXPathRegisteredNsCleanup(ctxt);
5797 xmlXPathRegisteredFuncsCleanup(ctxt);
5798 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005799 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00005800 xmlFree(ctxt);
5801}
5802
5803/************************************************************************
5804 * *
5805 * Routines to handle XPath parser contexts *
5806 * *
5807 ************************************************************************/
5808
5809#define CHECK_CTXT(ctxt) \
5810 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00005811 __xmlRaiseError(NULL, NULL, NULL, \
5812 NULL, NULL, XML_FROM_XPATH, \
5813 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5814 __FILE__, __LINE__, \
5815 NULL, NULL, NULL, 0, 0, \
5816 "NULL context pointer\n"); \
5817 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00005818 } \
5819
5820
5821#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00005822 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
5823 (ctxt->doc->children == NULL)) { \
5824 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00005825 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00005826 }
Owen Taylor3473f882001-02-23 17:55:21 +00005827
5828
5829/**
5830 * xmlXPathNewParserContext:
5831 * @str: the XPath expression
5832 * @ctxt: the XPath context
5833 *
5834 * Create a new xmlXPathParserContext
5835 *
5836 * Returns the xmlXPathParserContext just allocated.
5837 */
5838xmlXPathParserContextPtr
5839xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5840 xmlXPathParserContextPtr ret;
5841
5842 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5843 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005844 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005845 return(NULL);
5846 }
5847 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5848 ret->cur = ret->base = str;
5849 ret->context = ctxt;
5850
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005851 ret->comp = xmlXPathNewCompExpr();
5852 if (ret->comp == NULL) {
5853 xmlFree(ret->valueTab);
5854 xmlFree(ret);
5855 return(NULL);
5856 }
Daniel Veillard4773df22004-01-23 13:15:13 +00005857 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5858 ret->comp->dict = ctxt->dict;
5859 xmlDictReference(ret->comp->dict);
5860 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005861
5862 return(ret);
5863}
5864
5865/**
5866 * xmlXPathCompParserContext:
5867 * @comp: the XPath compiled expression
5868 * @ctxt: the XPath context
5869 *
5870 * Create a new xmlXPathParserContext when processing a compiled expression
5871 *
5872 * Returns the xmlXPathParserContext just allocated.
5873 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005874static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005875xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5876 xmlXPathParserContextPtr ret;
5877
5878 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5879 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005880 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005881 return(NULL);
5882 }
5883 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5884
Owen Taylor3473f882001-02-23 17:55:21 +00005885 /* Allocate the value stack */
5886 ret->valueTab = (xmlXPathObjectPtr *)
5887 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005888 if (ret->valueTab == NULL) {
5889 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005890 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005891 return(NULL);
5892 }
Owen Taylor3473f882001-02-23 17:55:21 +00005893 ret->valueNr = 0;
5894 ret->valueMax = 10;
5895 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005896
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005897 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005898 ret->comp = comp;
5899
Owen Taylor3473f882001-02-23 17:55:21 +00005900 return(ret);
5901}
5902
5903/**
5904 * xmlXPathFreeParserContext:
5905 * @ctxt: the context to free
5906 *
5907 * Free up an xmlXPathParserContext
5908 */
5909void
5910xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5911 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005912 xmlFree(ctxt->valueTab);
5913 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00005914 if (ctxt->comp != NULL) {
5915#ifdef XPATH_STREAMING
5916 if (ctxt->comp->stream != NULL) {
5917 xmlFreePatternList(ctxt->comp->stream);
5918 ctxt->comp->stream = NULL;
5919 }
5920#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005921 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00005922 }
Owen Taylor3473f882001-02-23 17:55:21 +00005923 xmlFree(ctxt);
5924}
5925
5926/************************************************************************
5927 * *
5928 * The implicit core function library *
5929 * *
5930 ************************************************************************/
5931
Owen Taylor3473f882001-02-23 17:55:21 +00005932/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005933 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00005934 * @node: a node pointer
5935 *
5936 * Function computing the beginning of the string value of the node,
5937 * used to speed up comparisons
5938 *
5939 * Returns an int usable as a hash
5940 */
5941static unsigned int
5942xmlXPathNodeValHash(xmlNodePtr node) {
5943 int len = 2;
5944 const xmlChar * string = NULL;
5945 xmlNodePtr tmp = NULL;
5946 unsigned int ret = 0;
5947
5948 if (node == NULL)
5949 return(0);
5950
Daniel Veillard9adc0462003-03-24 18:39:54 +00005951 if (node->type == XML_DOCUMENT_NODE) {
5952 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5953 if (tmp == NULL)
5954 node = node->children;
5955 else
5956 node = tmp;
5957
5958 if (node == NULL)
5959 return(0);
5960 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005961
5962 switch (node->type) {
5963 case XML_COMMENT_NODE:
5964 case XML_PI_NODE:
5965 case XML_CDATA_SECTION_NODE:
5966 case XML_TEXT_NODE:
5967 string = node->content;
5968 if (string == NULL)
5969 return(0);
5970 if (string[0] == 0)
5971 return(0);
5972 return(((unsigned int) string[0]) +
5973 (((unsigned int) string[1]) << 8));
5974 case XML_NAMESPACE_DECL:
5975 string = ((xmlNsPtr)node)->href;
5976 if (string == NULL)
5977 return(0);
5978 if (string[0] == 0)
5979 return(0);
5980 return(((unsigned int) string[0]) +
5981 (((unsigned int) string[1]) << 8));
5982 case XML_ATTRIBUTE_NODE:
5983 tmp = ((xmlAttrPtr) node)->children;
5984 break;
5985 case XML_ELEMENT_NODE:
5986 tmp = node->children;
5987 break;
5988 default:
5989 return(0);
5990 }
5991 while (tmp != NULL) {
5992 switch (tmp->type) {
5993 case XML_COMMENT_NODE:
5994 case XML_PI_NODE:
5995 case XML_CDATA_SECTION_NODE:
5996 case XML_TEXT_NODE:
5997 string = tmp->content;
5998 break;
5999 case XML_NAMESPACE_DECL:
6000 string = ((xmlNsPtr)tmp)->href;
6001 break;
6002 default:
6003 break;
6004 }
6005 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006006 if (len == 1) {
6007 return(ret + (((unsigned int) string[0]) << 8));
6008 }
6009 if (string[1] == 0) {
6010 len = 1;
6011 ret = (unsigned int) string[0];
6012 } else {
6013 return(((unsigned int) string[0]) +
6014 (((unsigned int) string[1]) << 8));
6015 }
6016 }
6017 /*
6018 * Skip to next node
6019 */
6020 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6021 if (tmp->children->type != XML_ENTITY_DECL) {
6022 tmp = tmp->children;
6023 continue;
6024 }
6025 }
6026 if (tmp == node)
6027 break;
6028
6029 if (tmp->next != NULL) {
6030 tmp = tmp->next;
6031 continue;
6032 }
6033
6034 do {
6035 tmp = tmp->parent;
6036 if (tmp == NULL)
6037 break;
6038 if (tmp == node) {
6039 tmp = NULL;
6040 break;
6041 }
6042 if (tmp->next != NULL) {
6043 tmp = tmp->next;
6044 break;
6045 }
6046 } while (tmp != NULL);
6047 }
6048 return(ret);
6049}
6050
6051/**
6052 * xmlXPathStringHash:
6053 * @string: a string
6054 *
6055 * Function computing the beginning of the string value of the node,
6056 * used to speed up comparisons
6057 *
6058 * Returns an int usable as a hash
6059 */
6060static unsigned int
6061xmlXPathStringHash(const xmlChar * string) {
6062 if (string == NULL)
6063 return((unsigned int) 0);
6064 if (string[0] == 0)
6065 return(0);
6066 return(((unsigned int) string[0]) +
6067 (((unsigned int) string[1]) << 8));
6068}
6069
6070/**
Owen Taylor3473f882001-02-23 17:55:21 +00006071 * xmlXPathCompareNodeSetFloat:
6072 * @ctxt: the XPath Parser context
6073 * @inf: less than (1) or greater than (0)
6074 * @strict: is the comparison strict
6075 * @arg: the node set
6076 * @f: the value
6077 *
6078 * Implement the compare operation between a nodeset and a number
6079 * @ns < @val (1, 1, ...
6080 * @ns <= @val (1, 0, ...
6081 * @ns > @val (0, 1, ...
6082 * @ns >= @val (0, 0, ...
6083 *
6084 * If one object to be compared is a node-set and the other is a number,
6085 * then the comparison will be true if and only if there is a node in the
6086 * node-set such that the result of performing the comparison on the number
6087 * to be compared and on the result of converting the string-value of that
6088 * node to a number using the number function is true.
6089 *
6090 * Returns 0 or 1 depending on the results of the test.
6091 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006092static int
Owen Taylor3473f882001-02-23 17:55:21 +00006093xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6094 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6095 int i, ret = 0;
6096 xmlNodeSetPtr ns;
6097 xmlChar *str2;
6098
6099 if ((f == NULL) || (arg == NULL) ||
6100 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006101 xmlXPathReleaseObject(ctxt->context, arg);
6102 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006103 return(0);
6104 }
6105 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006106 if (ns != NULL) {
6107 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006108 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006109 if (str2 != NULL) {
6110 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006111 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006112 xmlFree(str2);
6113 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006114 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006115 ret = xmlXPathCompareValues(ctxt, inf, strict);
6116 if (ret)
6117 break;
6118 }
6119 }
Owen Taylor3473f882001-02-23 17:55:21 +00006120 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006121 xmlXPathReleaseObject(ctxt->context, arg);
6122 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006123 return(ret);
6124}
6125
6126/**
6127 * xmlXPathCompareNodeSetString:
6128 * @ctxt: the XPath Parser context
6129 * @inf: less than (1) or greater than (0)
6130 * @strict: is the comparison strict
6131 * @arg: the node set
6132 * @s: the value
6133 *
6134 * Implement the compare operation between a nodeset and a string
6135 * @ns < @val (1, 1, ...
6136 * @ns <= @val (1, 0, ...
6137 * @ns > @val (0, 1, ...
6138 * @ns >= @val (0, 0, ...
6139 *
6140 * If one object to be compared is a node-set and the other is a string,
6141 * then the comparison will be true if and only if there is a node in
6142 * the node-set such that the result of performing the comparison on the
6143 * string-value of the node and the other string is true.
6144 *
6145 * Returns 0 or 1 depending on the results of the test.
6146 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006147static int
Owen Taylor3473f882001-02-23 17:55:21 +00006148xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6149 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6150 int i, ret = 0;
6151 xmlNodeSetPtr ns;
6152 xmlChar *str2;
6153
6154 if ((s == NULL) || (arg == NULL) ||
6155 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006156 xmlXPathReleaseObject(ctxt->context, arg);
6157 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006158 return(0);
6159 }
6160 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006161 if (ns != NULL) {
6162 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006163 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006164 if (str2 != NULL) {
6165 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006166 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006167 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006168 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006169 ret = xmlXPathCompareValues(ctxt, inf, strict);
6170 if (ret)
6171 break;
6172 }
6173 }
Owen Taylor3473f882001-02-23 17:55:21 +00006174 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006175 xmlXPathReleaseObject(ctxt->context, arg);
6176 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006177 return(ret);
6178}
6179
6180/**
6181 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006182 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006183 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006184 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006185 * @arg2: the second node set object
6186 *
6187 * Implement the compare operation on nodesets:
6188 *
6189 * If both objects to be compared are node-sets, then the comparison
6190 * will be true if and only if there is a node in the first node-set
6191 * and a node in the second node-set such that the result of performing
6192 * the comparison on the string-values of the two nodes is true.
6193 * ....
6194 * When neither object to be compared is a node-set and the operator
6195 * is <=, <, >= or >, then the objects are compared by converting both
6196 * objects to numbers and comparing the numbers according to IEEE 754.
6197 * ....
6198 * The number function converts its argument to a number as follows:
6199 * - a string that consists of optional whitespace followed by an
6200 * optional minus sign followed by a Number followed by whitespace
6201 * is converted to the IEEE 754 number that is nearest (according
6202 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6203 * represented by the string; any other string is converted to NaN
6204 *
6205 * Conclusion all nodes need to be converted first to their string value
6206 * and then the comparison must be done when possible
6207 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006208static int
6209xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006210 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6211 int i, j, init = 0;
6212 double val1;
6213 double *values2;
6214 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006215 xmlNodeSetPtr ns1;
6216 xmlNodeSetPtr ns2;
6217
6218 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006219 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6220 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006221 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006222 }
Owen Taylor3473f882001-02-23 17:55:21 +00006223 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006224 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6225 xmlXPathFreeObject(arg1);
6226 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006227 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006228 }
Owen Taylor3473f882001-02-23 17:55:21 +00006229
6230 ns1 = arg1->nodesetval;
6231 ns2 = arg2->nodesetval;
6232
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006233 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006234 xmlXPathFreeObject(arg1);
6235 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006236 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006237 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006238 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006239 xmlXPathFreeObject(arg1);
6240 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006241 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006242 }
Owen Taylor3473f882001-02-23 17:55:21 +00006243
6244 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6245 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006246 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006247 xmlXPathFreeObject(arg1);
6248 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006249 return(0);
6250 }
6251 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006252 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006253 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006254 continue;
6255 for (j = 0;j < ns2->nodeNr;j++) {
6256 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006257 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006258 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006259 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006260 continue;
6261 if (inf && strict)
6262 ret = (val1 < values2[j]);
6263 else if (inf && !strict)
6264 ret = (val1 <= values2[j]);
6265 else if (!inf && strict)
6266 ret = (val1 > values2[j]);
6267 else if (!inf && !strict)
6268 ret = (val1 >= values2[j]);
6269 if (ret)
6270 break;
6271 }
6272 if (ret)
6273 break;
6274 init = 1;
6275 }
6276 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006277 xmlXPathFreeObject(arg1);
6278 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006279 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006280}
6281
6282/**
6283 * xmlXPathCompareNodeSetValue:
6284 * @ctxt: the XPath Parser context
6285 * @inf: less than (1) or greater than (0)
6286 * @strict: is the comparison strict
6287 * @arg: the node set
6288 * @val: the value
6289 *
6290 * Implement the compare operation between a nodeset and a value
6291 * @ns < @val (1, 1, ...
6292 * @ns <= @val (1, 0, ...
6293 * @ns > @val (0, 1, ...
6294 * @ns >= @val (0, 0, ...
6295 *
6296 * If one object to be compared is a node-set and the other is a boolean,
6297 * then the comparison will be true if and only if the result of performing
6298 * the comparison on the boolean and on the result of converting
6299 * the node-set to a boolean using the boolean function is true.
6300 *
6301 * Returns 0 or 1 depending on the results of the test.
6302 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006303static int
Owen Taylor3473f882001-02-23 17:55:21 +00006304xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6305 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6306 if ((val == NULL) || (arg == NULL) ||
6307 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6308 return(0);
6309
6310 switch(val->type) {
6311 case XPATH_NUMBER:
6312 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6313 case XPATH_NODESET:
6314 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006315 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006316 case XPATH_STRING:
6317 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6318 case XPATH_BOOLEAN:
6319 valuePush(ctxt, arg);
6320 xmlXPathBooleanFunction(ctxt, 1);
6321 valuePush(ctxt, val);
6322 return(xmlXPathCompareValues(ctxt, inf, strict));
6323 default:
6324 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006325 }
6326 return(0);
6327}
6328
6329/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006330 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006331 * @arg: the nodeset object argument
6332 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006333 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006334 *
6335 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6336 * If one object to be compared is a node-set and the other is a string,
6337 * then the comparison will be true if and only if there is a node in
6338 * the node-set such that the result of performing the comparison on the
6339 * string-value of the node and the other string is true.
6340 *
6341 * Returns 0 or 1 depending on the results of the test.
6342 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006343static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006344xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006345{
Owen Taylor3473f882001-02-23 17:55:21 +00006346 int i;
6347 xmlNodeSetPtr ns;
6348 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006349 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006350
6351 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006352 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6353 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006354 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006355 /*
6356 * A NULL nodeset compared with a string is always false
6357 * (since there is no node equal, and no node not equal)
6358 */
6359 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006360 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006361 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006362 for (i = 0; i < ns->nodeNr; i++) {
6363 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6364 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6365 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6366 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006367 if (neq)
6368 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006369 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006370 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6371 if (neq)
6372 continue;
6373 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006374 } else if (neq) {
6375 if (str2 != NULL)
6376 xmlFree(str2);
6377 return (1);
6378 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006379 if (str2 != NULL)
6380 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006381 } else if (neq)
6382 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006383 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006384 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006385}
6386
6387/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006388 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006389 * @arg: the nodeset object argument
6390 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006391 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006392 *
6393 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6394 * If one object to be compared is a node-set and the other is a number,
6395 * then the comparison will be true if and only if there is a node in
6396 * the node-set such that the result of performing the comparison on the
6397 * number to be compared and on the result of converting the string-value
6398 * of that node to a number using the number function is true.
6399 *
6400 * Returns 0 or 1 depending on the results of the test.
6401 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006402static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006403xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6404 xmlXPathObjectPtr arg, double f, int neq) {
6405 int i, ret=0;
6406 xmlNodeSetPtr ns;
6407 xmlChar *str2;
6408 xmlXPathObjectPtr val;
6409 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006410
6411 if ((arg == NULL) ||
6412 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6413 return(0);
6414
William M. Brack0c022ad2002-07-12 00:56:01 +00006415 ns = arg->nodesetval;
6416 if (ns != NULL) {
6417 for (i=0;i<ns->nodeNr;i++) {
6418 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6419 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006420 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006421 xmlFree(str2);
6422 xmlXPathNumberFunction(ctxt, 1);
6423 val = valuePop(ctxt);
6424 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006425 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006426 if (!xmlXPathIsNaN(v)) {
6427 if ((!neq) && (v==f)) {
6428 ret = 1;
6429 break;
6430 } else if ((neq) && (v!=f)) {
6431 ret = 1;
6432 break;
6433 }
William M. Brack32f0f712005-07-14 07:00:33 +00006434 } else { /* NaN is unequal to any value */
6435 if (neq)
6436 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006437 }
6438 }
6439 }
6440 }
6441
6442 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006443}
6444
6445
6446/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006447 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006448 * @arg1: first nodeset object argument
6449 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006450 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006451 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006452 * Implement the equal / not equal operation on XPath nodesets:
6453 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006454 * If both objects to be compared are node-sets, then the comparison
6455 * will be true if and only if there is a node in the first node-set and
6456 * a node in the second node-set such that the result of performing the
6457 * comparison on the string-values of the two nodes is true.
6458 *
6459 * (needless to say, this is a costly operation)
6460 *
6461 * Returns 0 or 1 depending on the results of the test.
6462 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006463static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006464xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006465 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006466 unsigned int *hashs1;
6467 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006468 xmlChar **values1;
6469 xmlChar **values2;
6470 int ret = 0;
6471 xmlNodeSetPtr ns1;
6472 xmlNodeSetPtr ns2;
6473
6474 if ((arg1 == NULL) ||
6475 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6476 return(0);
6477 if ((arg2 == NULL) ||
6478 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6479 return(0);
6480
6481 ns1 = arg1->nodesetval;
6482 ns2 = arg2->nodesetval;
6483
Daniel Veillard911f49a2001-04-07 15:39:35 +00006484 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006485 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006486 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006487 return(0);
6488
6489 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006490 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006491 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006492 if (neq == 0)
6493 for (i = 0;i < ns1->nodeNr;i++)
6494 for (j = 0;j < ns2->nodeNr;j++)
6495 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6496 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006497
6498 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006499 if (values1 == NULL) {
6500 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006501 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006502 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006503 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6504 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006505 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006506 xmlFree(values1);
6507 return(0);
6508 }
Owen Taylor3473f882001-02-23 17:55:21 +00006509 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6510 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6511 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006512 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006513 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006514 xmlFree(values1);
6515 return(0);
6516 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006517 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6518 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006519 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006520 xmlFree(hashs1);
6521 xmlFree(values1);
6522 xmlFree(values2);
6523 return(0);
6524 }
Owen Taylor3473f882001-02-23 17:55:21 +00006525 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6526 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006527 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006528 for (j = 0;j < ns2->nodeNr;j++) {
6529 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006530 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006531 if (hashs1[i] != hashs2[j]) {
6532 if (neq) {
6533 ret = 1;
6534 break;
6535 }
6536 }
6537 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006538 if (values1[i] == NULL)
6539 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6540 if (values2[j] == NULL)
6541 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006542 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006543 if (ret)
6544 break;
6545 }
Owen Taylor3473f882001-02-23 17:55:21 +00006546 }
6547 if (ret)
6548 break;
6549 }
6550 for (i = 0;i < ns1->nodeNr;i++)
6551 if (values1[i] != NULL)
6552 xmlFree(values1[i]);
6553 for (j = 0;j < ns2->nodeNr;j++)
6554 if (values2[j] != NULL)
6555 xmlFree(values2[j]);
6556 xmlFree(values1);
6557 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006558 xmlFree(hashs1);
6559 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006560 return(ret);
6561}
6562
William M. Brack0c022ad2002-07-12 00:56:01 +00006563static int
6564xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6565 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006566 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006567 /*
6568 *At this point we are assured neither arg1 nor arg2
6569 *is a nodeset, so we can just pick the appropriate routine.
6570 */
Owen Taylor3473f882001-02-23 17:55:21 +00006571 switch (arg1->type) {
6572 case XPATH_UNDEFINED:
6573#ifdef DEBUG_EXPR
6574 xmlGenericError(xmlGenericErrorContext,
6575 "Equal: undefined\n");
6576#endif
6577 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006578 case XPATH_BOOLEAN:
6579 switch (arg2->type) {
6580 case XPATH_UNDEFINED:
6581#ifdef DEBUG_EXPR
6582 xmlGenericError(xmlGenericErrorContext,
6583 "Equal: undefined\n");
6584#endif
6585 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006586 case XPATH_BOOLEAN:
6587#ifdef DEBUG_EXPR
6588 xmlGenericError(xmlGenericErrorContext,
6589 "Equal: %d boolean %d \n",
6590 arg1->boolval, arg2->boolval);
6591#endif
6592 ret = (arg1->boolval == arg2->boolval);
6593 break;
6594 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006595 ret = (arg1->boolval ==
6596 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006597 break;
6598 case XPATH_STRING:
6599 if ((arg2->stringval == NULL) ||
6600 (arg2->stringval[0] == 0)) ret = 0;
6601 else
6602 ret = 1;
6603 ret = (arg1->boolval == ret);
6604 break;
6605 case XPATH_USERS:
6606 case XPATH_POINT:
6607 case XPATH_RANGE:
6608 case XPATH_LOCATIONSET:
6609 TODO
6610 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006611 case XPATH_NODESET:
6612 case XPATH_XSLT_TREE:
6613 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006614 }
6615 break;
6616 case XPATH_NUMBER:
6617 switch (arg2->type) {
6618 case XPATH_UNDEFINED:
6619#ifdef DEBUG_EXPR
6620 xmlGenericError(xmlGenericErrorContext,
6621 "Equal: undefined\n");
6622#endif
6623 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006624 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006625 ret = (arg2->boolval==
6626 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006627 break;
6628 case XPATH_STRING:
6629 valuePush(ctxt, arg2);
6630 xmlXPathNumberFunction(ctxt, 1);
6631 arg2 = valuePop(ctxt);
6632 /* no break on purpose */
6633 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006634 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006635 if (xmlXPathIsNaN(arg1->floatval) ||
6636 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006637 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006638 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6639 if (xmlXPathIsInf(arg2->floatval) == 1)
6640 ret = 1;
6641 else
6642 ret = 0;
6643 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6644 if (xmlXPathIsInf(arg2->floatval) == -1)
6645 ret = 1;
6646 else
6647 ret = 0;
6648 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6649 if (xmlXPathIsInf(arg1->floatval) == 1)
6650 ret = 1;
6651 else
6652 ret = 0;
6653 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6654 if (xmlXPathIsInf(arg1->floatval) == -1)
6655 ret = 1;
6656 else
6657 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006658 } else {
6659 ret = (arg1->floatval == arg2->floatval);
6660 }
Owen Taylor3473f882001-02-23 17:55:21 +00006661 break;
6662 case XPATH_USERS:
6663 case XPATH_POINT:
6664 case XPATH_RANGE:
6665 case XPATH_LOCATIONSET:
6666 TODO
6667 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006668 case XPATH_NODESET:
6669 case XPATH_XSLT_TREE:
6670 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006671 }
6672 break;
6673 case XPATH_STRING:
6674 switch (arg2->type) {
6675 case XPATH_UNDEFINED:
6676#ifdef DEBUG_EXPR
6677 xmlGenericError(xmlGenericErrorContext,
6678 "Equal: undefined\n");
6679#endif
6680 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006681 case XPATH_BOOLEAN:
6682 if ((arg1->stringval == NULL) ||
6683 (arg1->stringval[0] == 0)) ret = 0;
6684 else
6685 ret = 1;
6686 ret = (arg2->boolval == ret);
6687 break;
6688 case XPATH_STRING:
6689 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6690 break;
6691 case XPATH_NUMBER:
6692 valuePush(ctxt, arg1);
6693 xmlXPathNumberFunction(ctxt, 1);
6694 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006695 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006696 if (xmlXPathIsNaN(arg1->floatval) ||
6697 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006698 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006699 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6700 if (xmlXPathIsInf(arg2->floatval) == 1)
6701 ret = 1;
6702 else
6703 ret = 0;
6704 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6705 if (xmlXPathIsInf(arg2->floatval) == -1)
6706 ret = 1;
6707 else
6708 ret = 0;
6709 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6710 if (xmlXPathIsInf(arg1->floatval) == 1)
6711 ret = 1;
6712 else
6713 ret = 0;
6714 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6715 if (xmlXPathIsInf(arg1->floatval) == -1)
6716 ret = 1;
6717 else
6718 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006719 } else {
6720 ret = (arg1->floatval == arg2->floatval);
6721 }
Owen Taylor3473f882001-02-23 17:55:21 +00006722 break;
6723 case XPATH_USERS:
6724 case XPATH_POINT:
6725 case XPATH_RANGE:
6726 case XPATH_LOCATIONSET:
6727 TODO
6728 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006729 case XPATH_NODESET:
6730 case XPATH_XSLT_TREE:
6731 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006732 }
6733 break;
6734 case XPATH_USERS:
6735 case XPATH_POINT:
6736 case XPATH_RANGE:
6737 case XPATH_LOCATIONSET:
6738 TODO
6739 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006740 case XPATH_NODESET:
6741 case XPATH_XSLT_TREE:
6742 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006743 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006744 xmlXPathReleaseObject(ctxt->context, arg1);
6745 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006746 return(ret);
6747}
6748
William M. Brack0c022ad2002-07-12 00:56:01 +00006749/**
6750 * xmlXPathEqualValues:
6751 * @ctxt: the XPath Parser context
6752 *
6753 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6754 *
6755 * Returns 0 or 1 depending on the results of the test.
6756 */
6757int
6758xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6759 xmlXPathObjectPtr arg1, arg2, argtmp;
6760 int ret = 0;
6761
Daniel Veillard6128c012004-11-08 17:16:15 +00006762 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006763 arg2 = valuePop(ctxt);
6764 arg1 = valuePop(ctxt);
6765 if ((arg1 == NULL) || (arg2 == NULL)) {
6766 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006767 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006768 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006769 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006770 XP_ERROR0(XPATH_INVALID_OPERAND);
6771 }
6772
6773 if (arg1 == arg2) {
6774#ifdef DEBUG_EXPR
6775 xmlGenericError(xmlGenericErrorContext,
6776 "Equal: by pointer\n");
6777#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00006778 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006779 return(1);
6780 }
6781
6782 /*
6783 *If either argument is a nodeset, it's a 'special case'
6784 */
6785 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6786 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6787 /*
6788 *Hack it to assure arg1 is the nodeset
6789 */
6790 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6791 argtmp = arg2;
6792 arg2 = arg1;
6793 arg1 = argtmp;
6794 }
6795 switch (arg2->type) {
6796 case XPATH_UNDEFINED:
6797#ifdef DEBUG_EXPR
6798 xmlGenericError(xmlGenericErrorContext,
6799 "Equal: undefined\n");
6800#endif
6801 break;
6802 case XPATH_NODESET:
6803 case XPATH_XSLT_TREE:
6804 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6805 break;
6806 case XPATH_BOOLEAN:
6807 if ((arg1->nodesetval == NULL) ||
6808 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6809 else
6810 ret = 1;
6811 ret = (ret == arg2->boolval);
6812 break;
6813 case XPATH_NUMBER:
6814 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6815 break;
6816 case XPATH_STRING:
6817 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6818 break;
6819 case XPATH_USERS:
6820 case XPATH_POINT:
6821 case XPATH_RANGE:
6822 case XPATH_LOCATIONSET:
6823 TODO
6824 break;
6825 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006826 xmlXPathReleaseObject(ctxt->context, arg1);
6827 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006828 return(ret);
6829 }
6830
6831 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6832}
6833
6834/**
6835 * xmlXPathNotEqualValues:
6836 * @ctxt: the XPath Parser context
6837 *
6838 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6839 *
6840 * Returns 0 or 1 depending on the results of the test.
6841 */
6842int
6843xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6844 xmlXPathObjectPtr arg1, arg2, argtmp;
6845 int ret = 0;
6846
Daniel Veillard6128c012004-11-08 17:16:15 +00006847 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006848 arg2 = valuePop(ctxt);
6849 arg1 = valuePop(ctxt);
6850 if ((arg1 == NULL) || (arg2 == NULL)) {
6851 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006852 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006853 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006854 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006855 XP_ERROR0(XPATH_INVALID_OPERAND);
6856 }
6857
6858 if (arg1 == arg2) {
6859#ifdef DEBUG_EXPR
6860 xmlGenericError(xmlGenericErrorContext,
6861 "NotEqual: by pointer\n");
6862#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006863 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006864 return(0);
6865 }
6866
6867 /*
6868 *If either argument is a nodeset, it's a 'special case'
6869 */
6870 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6871 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6872 /*
6873 *Hack it to assure arg1 is the nodeset
6874 */
6875 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6876 argtmp = arg2;
6877 arg2 = arg1;
6878 arg1 = argtmp;
6879 }
6880 switch (arg2->type) {
6881 case XPATH_UNDEFINED:
6882#ifdef DEBUG_EXPR
6883 xmlGenericError(xmlGenericErrorContext,
6884 "NotEqual: undefined\n");
6885#endif
6886 break;
6887 case XPATH_NODESET:
6888 case XPATH_XSLT_TREE:
6889 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6890 break;
6891 case XPATH_BOOLEAN:
6892 if ((arg1->nodesetval == NULL) ||
6893 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6894 else
6895 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00006896 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00006897 break;
6898 case XPATH_NUMBER:
6899 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6900 break;
6901 case XPATH_STRING:
6902 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6903 break;
6904 case XPATH_USERS:
6905 case XPATH_POINT:
6906 case XPATH_RANGE:
6907 case XPATH_LOCATIONSET:
6908 TODO
6909 break;
6910 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006911 xmlXPathReleaseObject(ctxt->context, arg1);
6912 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006913 return(ret);
6914 }
6915
6916 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6917}
Owen Taylor3473f882001-02-23 17:55:21 +00006918
6919/**
6920 * xmlXPathCompareValues:
6921 * @ctxt: the XPath Parser context
6922 * @inf: less than (1) or greater than (0)
6923 * @strict: is the comparison strict
6924 *
6925 * Implement the compare operation on XPath objects:
6926 * @arg1 < @arg2 (1, 1, ...
6927 * @arg1 <= @arg2 (1, 0, ...
6928 * @arg1 > @arg2 (0, 1, ...
6929 * @arg1 >= @arg2 (0, 0, ...
6930 *
6931 * When neither object to be compared is a node-set and the operator is
6932 * <=, <, >=, >, then the objects are compared by converted both objects
6933 * to numbers and comparing the numbers according to IEEE 754. The <
6934 * comparison will be true if and only if the first number is less than the
6935 * second number. The <= comparison will be true if and only if the first
6936 * number is less than or equal to the second number. The > comparison
6937 * will be true if and only if the first number is greater than the second
6938 * number. The >= comparison will be true if and only if the first number
6939 * is greater than or equal to the second number.
6940 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006941 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00006942 */
6943int
6944xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006945 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006946 xmlXPathObjectPtr arg1, arg2;
6947
Daniel Veillard6128c012004-11-08 17:16:15 +00006948 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006949 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006950 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00006951 if ((arg1 == NULL) || (arg2 == NULL)) {
6952 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006953 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006954 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006955 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006956 XP_ERROR0(XPATH_INVALID_OPERAND);
6957 }
6958
William M. Brack0c022ad2002-07-12 00:56:01 +00006959 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6960 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00006961 /*
6962 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6963 * are not freed from within this routine; they will be freed from the
6964 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6965 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006966 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6967 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006968 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006969 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00006970 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006971 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6972 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006973 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006974 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6975 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00006976 }
6977 }
6978 return(ret);
6979 }
6980
6981 if (arg1->type != XPATH_NUMBER) {
6982 valuePush(ctxt, arg1);
6983 xmlXPathNumberFunction(ctxt, 1);
6984 arg1 = valuePop(ctxt);
6985 }
6986 if (arg1->type != XPATH_NUMBER) {
6987 xmlXPathFreeObject(arg1);
6988 xmlXPathFreeObject(arg2);
6989 XP_ERROR0(XPATH_INVALID_OPERAND);
6990 }
6991 if (arg2->type != XPATH_NUMBER) {
6992 valuePush(ctxt, arg2);
6993 xmlXPathNumberFunction(ctxt, 1);
6994 arg2 = valuePop(ctxt);
6995 }
6996 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006997 xmlXPathReleaseObject(ctxt->context, arg1);
6998 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006999 XP_ERROR0(XPATH_INVALID_OPERAND);
7000 }
7001 /*
7002 * Add tests for infinity and nan
7003 * => feedback on 3.4 for Inf and NaN
7004 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007005 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00007006 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007007 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00007008 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00007009 arg1i=xmlXPathIsInf(arg1->floatval);
7010 arg2i=xmlXPathIsInf(arg2->floatval);
7011 if (inf && strict) {
7012 if ((arg1i == -1 && arg2i != -1) ||
7013 (arg2i == 1 && arg1i != 1)) {
7014 ret = 1;
7015 } else if (arg1i == 0 && arg2i == 0) {
7016 ret = (arg1->floatval < arg2->floatval);
7017 } else {
7018 ret = 0;
7019 }
7020 }
7021 else if (inf && !strict) {
7022 if (arg1i == -1 || arg2i == 1) {
7023 ret = 1;
7024 } else if (arg1i == 0 && arg2i == 0) {
7025 ret = (arg1->floatval <= arg2->floatval);
7026 } else {
7027 ret = 0;
7028 }
7029 }
7030 else if (!inf && strict) {
7031 if ((arg1i == 1 && arg2i != 1) ||
7032 (arg2i == -1 && arg1i != -1)) {
7033 ret = 1;
7034 } else if (arg1i == 0 && arg2i == 0) {
7035 ret = (arg1->floatval > arg2->floatval);
7036 } else {
7037 ret = 0;
7038 }
7039 }
7040 else if (!inf && !strict) {
7041 if (arg1i == 1 || arg2i == -1) {
7042 ret = 1;
7043 } else if (arg1i == 0 && arg2i == 0) {
7044 ret = (arg1->floatval >= arg2->floatval);
7045 } else {
7046 ret = 0;
7047 }
7048 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007049 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007050 xmlXPathReleaseObject(ctxt->context, arg1);
7051 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007052 return(ret);
7053}
7054
7055/**
7056 * xmlXPathValueFlipSign:
7057 * @ctxt: the XPath Parser context
7058 *
7059 * Implement the unary - operation on an XPath object
7060 * The numeric operators convert their operands to numbers as if
7061 * by calling the number function.
7062 */
7063void
7064xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007065 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007066 CAST_TO_NUMBER;
7067 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007068 if (xmlXPathIsNaN(ctxt->value->floatval))
7069 ctxt->value->floatval=xmlXPathNAN;
7070 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7071 ctxt->value->floatval=xmlXPathNINF;
7072 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7073 ctxt->value->floatval=xmlXPathPINF;
7074 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007075 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7076 ctxt->value->floatval = xmlXPathNZERO;
7077 else
7078 ctxt->value->floatval = 0;
7079 }
7080 else
7081 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007082}
7083
7084/**
7085 * xmlXPathAddValues:
7086 * @ctxt: the XPath Parser context
7087 *
7088 * Implement the add operation on XPath objects:
7089 * The numeric operators convert their operands to numbers as if
7090 * by calling the number function.
7091 */
7092void
7093xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7094 xmlXPathObjectPtr arg;
7095 double val;
7096
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007097 arg = valuePop(ctxt);
7098 if (arg == NULL)
7099 XP_ERROR(XPATH_INVALID_OPERAND);
7100 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007101 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007102 CAST_TO_NUMBER;
7103 CHECK_TYPE(XPATH_NUMBER);
7104 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007105}
7106
7107/**
7108 * xmlXPathSubValues:
7109 * @ctxt: the XPath Parser context
7110 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007111 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007112 * The numeric operators convert their operands to numbers as if
7113 * by calling the number function.
7114 */
7115void
7116xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7117 xmlXPathObjectPtr arg;
7118 double val;
7119
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007120 arg = valuePop(ctxt);
7121 if (arg == NULL)
7122 XP_ERROR(XPATH_INVALID_OPERAND);
7123 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007124 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007125 CAST_TO_NUMBER;
7126 CHECK_TYPE(XPATH_NUMBER);
7127 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007128}
7129
7130/**
7131 * xmlXPathMultValues:
7132 * @ctxt: the XPath Parser context
7133 *
7134 * Implement the multiply operation on XPath objects:
7135 * The numeric operators convert their operands to numbers as if
7136 * by calling the number function.
7137 */
7138void
7139xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7140 xmlXPathObjectPtr arg;
7141 double val;
7142
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007143 arg = valuePop(ctxt);
7144 if (arg == NULL)
7145 XP_ERROR(XPATH_INVALID_OPERAND);
7146 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007147 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007148 CAST_TO_NUMBER;
7149 CHECK_TYPE(XPATH_NUMBER);
7150 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007151}
7152
7153/**
7154 * xmlXPathDivValues:
7155 * @ctxt: the XPath Parser context
7156 *
7157 * Implement the div operation on XPath objects @arg1 / @arg2:
7158 * The numeric operators convert their operands to numbers as if
7159 * by calling the number function.
7160 */
7161void
7162xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7163 xmlXPathObjectPtr arg;
7164 double val;
7165
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007166 arg = valuePop(ctxt);
7167 if (arg == NULL)
7168 XP_ERROR(XPATH_INVALID_OPERAND);
7169 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007170 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007171 CAST_TO_NUMBER;
7172 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007173 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7174 ctxt->value->floatval = xmlXPathNAN;
7175 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007176 if (ctxt->value->floatval == 0)
7177 ctxt->value->floatval = xmlXPathNAN;
7178 else if (ctxt->value->floatval > 0)
7179 ctxt->value->floatval = xmlXPathNINF;
7180 else if (ctxt->value->floatval < 0)
7181 ctxt->value->floatval = xmlXPathPINF;
7182 }
7183 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007184 if (ctxt->value->floatval == 0)
7185 ctxt->value->floatval = xmlXPathNAN;
7186 else if (ctxt->value->floatval > 0)
7187 ctxt->value->floatval = xmlXPathPINF;
7188 else if (ctxt->value->floatval < 0)
7189 ctxt->value->floatval = xmlXPathNINF;
7190 } else
7191 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007192}
7193
7194/**
7195 * xmlXPathModValues:
7196 * @ctxt: the XPath Parser context
7197 *
7198 * Implement the mod operation on XPath objects: @arg1 / @arg2
7199 * The numeric operators convert their operands to numbers as if
7200 * by calling the number function.
7201 */
7202void
7203xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7204 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007205 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007206
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007207 arg = valuePop(ctxt);
7208 if (arg == NULL)
7209 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007210 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007211 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007212 CAST_TO_NUMBER;
7213 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007214 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007215 if (arg2 == 0)
7216 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007217 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007218 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007219 }
Owen Taylor3473f882001-02-23 17:55:21 +00007220}
7221
7222/************************************************************************
7223 * *
7224 * The traversal functions *
7225 * *
7226 ************************************************************************/
7227
Owen Taylor3473f882001-02-23 17:55:21 +00007228/*
7229 * A traversal function enumerates nodes along an axis.
7230 * Initially it must be called with NULL, and it indicates
7231 * termination on the axis by returning NULL.
7232 */
7233typedef xmlNodePtr (*xmlXPathTraversalFunction)
7234 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7235
7236/**
7237 * xmlXPathNextSelf:
7238 * @ctxt: the XPath Parser context
7239 * @cur: the current node in the traversal
7240 *
7241 * Traversal function for the "self" direction
7242 * The self axis contains just the context node itself
7243 *
7244 * Returns the next element following that axis
7245 */
7246xmlNodePtr
7247xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007248 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007249 if (cur == NULL)
7250 return(ctxt->context->node);
7251 return(NULL);
7252}
7253
7254/**
7255 * xmlXPathNextChild:
7256 * @ctxt: the XPath Parser context
7257 * @cur: the current node in the traversal
7258 *
7259 * Traversal function for the "child" direction
7260 * The child axis contains the children of the context node in document order.
7261 *
7262 * Returns the next element following that axis
7263 */
7264xmlNodePtr
7265xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007266 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007267 if (cur == NULL) {
7268 if (ctxt->context->node == NULL) return(NULL);
7269 switch (ctxt->context->node->type) {
7270 case XML_ELEMENT_NODE:
7271 case XML_TEXT_NODE:
7272 case XML_CDATA_SECTION_NODE:
7273 case XML_ENTITY_REF_NODE:
7274 case XML_ENTITY_NODE:
7275 case XML_PI_NODE:
7276 case XML_COMMENT_NODE:
7277 case XML_NOTATION_NODE:
7278 case XML_DTD_NODE:
7279 return(ctxt->context->node->children);
7280 case XML_DOCUMENT_NODE:
7281 case XML_DOCUMENT_TYPE_NODE:
7282 case XML_DOCUMENT_FRAG_NODE:
7283 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007284#ifdef LIBXML_DOCB_ENABLED
7285 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007286#endif
7287 return(((xmlDocPtr) ctxt->context->node)->children);
7288 case XML_ELEMENT_DECL:
7289 case XML_ATTRIBUTE_DECL:
7290 case XML_ENTITY_DECL:
7291 case XML_ATTRIBUTE_NODE:
7292 case XML_NAMESPACE_DECL:
7293 case XML_XINCLUDE_START:
7294 case XML_XINCLUDE_END:
7295 return(NULL);
7296 }
7297 return(NULL);
7298 }
7299 if ((cur->type == XML_DOCUMENT_NODE) ||
7300 (cur->type == XML_HTML_DOCUMENT_NODE))
7301 return(NULL);
7302 return(cur->next);
7303}
7304
7305/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007306 * xmlXPathNextChildElement:
7307 * @ctxt: the XPath Parser context
7308 * @cur: the current node in the traversal
7309 *
7310 * Traversal function for the "child" direction and nodes of type element.
7311 * The child axis contains the children of the context node in document order.
7312 *
7313 * Returns the next element following that axis
7314 */
7315static xmlNodePtr
7316xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7317 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7318 if (cur == NULL) {
7319 cur = ctxt->context->node;
7320 if (cur == NULL) return(NULL);
7321 /*
7322 * Get the first element child.
7323 */
7324 switch (cur->type) {
7325 case XML_ELEMENT_NODE:
7326 case XML_DOCUMENT_FRAG_NODE:
7327 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7328 case XML_ENTITY_NODE:
7329 cur = cur->children;
7330 if (cur != NULL) {
7331 if (cur->type == XML_ELEMENT_NODE)
7332 return(cur);
7333 do {
7334 cur = cur->next;
7335 } while ((cur != NULL) &&
7336 (cur->type != XML_ELEMENT_NODE));
7337 return(cur);
7338 }
7339 return(NULL);
7340 case XML_DOCUMENT_NODE:
7341 case XML_HTML_DOCUMENT_NODE:
7342#ifdef LIBXML_DOCB_ENABLED
7343 case XML_DOCB_DOCUMENT_NODE:
7344#endif
7345 return(xmlDocGetRootElement((xmlDocPtr) cur));
7346 default:
7347 return(NULL);
7348 }
7349 return(NULL);
7350 }
7351 /*
7352 * Get the next sibling element node.
7353 */
7354 switch (cur->type) {
7355 case XML_ELEMENT_NODE:
7356 case XML_TEXT_NODE:
7357 case XML_ENTITY_REF_NODE:
7358 case XML_ENTITY_NODE:
7359 case XML_CDATA_SECTION_NODE:
7360 case XML_PI_NODE:
7361 case XML_COMMENT_NODE:
7362 case XML_XINCLUDE_END:
7363 break;
7364 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7365 default:
7366 return(NULL);
7367 }
7368 if (cur->next != NULL) {
7369 if (cur->next->type == XML_ELEMENT_NODE)
7370 return(cur->next);
7371 cur = cur->next;
7372 do {
7373 cur = cur->next;
7374 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7375 return(cur);
7376 }
7377 return(NULL);
7378}
7379
7380/**
Owen Taylor3473f882001-02-23 17:55:21 +00007381 * xmlXPathNextDescendant:
7382 * @ctxt: the XPath Parser context
7383 * @cur: the current node in the traversal
7384 *
7385 * Traversal function for the "descendant" direction
7386 * the descendant axis contains the descendants of the context node in document
7387 * order; a descendant is a child or a child of a child and so on.
7388 *
7389 * Returns the next element following that axis
7390 */
7391xmlNodePtr
7392xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007393 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007394 if (cur == NULL) {
7395 if (ctxt->context->node == NULL)
7396 return(NULL);
7397 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7398 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7399 return(NULL);
7400
7401 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7402 return(ctxt->context->doc->children);
7403 return(ctxt->context->node->children);
7404 }
7405
Daniel Veillard567e1b42001-08-01 15:53:47 +00007406 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007407 /*
7408 * Do not descend on entities declarations
7409 */
7410 if (cur->children->type != XML_ENTITY_DECL) {
7411 cur = cur->children;
7412 /*
7413 * Skip DTDs
7414 */
7415 if (cur->type != XML_DTD_NODE)
7416 return(cur);
7417 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007418 }
7419
7420 if (cur == ctxt->context->node) return(NULL);
7421
Daniel Veillard68e9e742002-11-16 15:35:11 +00007422 while (cur->next != NULL) {
7423 cur = cur->next;
7424 if ((cur->type != XML_ENTITY_DECL) &&
7425 (cur->type != XML_DTD_NODE))
7426 return(cur);
7427 }
Owen Taylor3473f882001-02-23 17:55:21 +00007428
7429 do {
7430 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007431 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007432 if (cur == ctxt->context->node) return(NULL);
7433 if (cur->next != NULL) {
7434 cur = cur->next;
7435 return(cur);
7436 }
7437 } while (cur != NULL);
7438 return(cur);
7439}
7440
7441/**
7442 * xmlXPathNextDescendantOrSelf:
7443 * @ctxt: the XPath Parser context
7444 * @cur: the current node in the traversal
7445 *
7446 * Traversal function for the "descendant-or-self" direction
7447 * the descendant-or-self axis contains the context node and the descendants
7448 * of the context node in document order; thus the context node is the first
7449 * node on the axis, and the first child of the context node is the second node
7450 * on the axis
7451 *
7452 * Returns the next element following that axis
7453 */
7454xmlNodePtr
7455xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007456 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007457 if (cur == NULL) {
7458 if (ctxt->context->node == NULL)
7459 return(NULL);
7460 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7461 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7462 return(NULL);
7463 return(ctxt->context->node);
7464 }
7465
7466 return(xmlXPathNextDescendant(ctxt, cur));
7467}
7468
7469/**
7470 * xmlXPathNextParent:
7471 * @ctxt: the XPath Parser context
7472 * @cur: the current node in the traversal
7473 *
7474 * Traversal function for the "parent" direction
7475 * The parent axis contains the parent of the context node, if there is one.
7476 *
7477 * Returns the next element following that axis
7478 */
7479xmlNodePtr
7480xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007481 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007482 /*
7483 * the parent of an attribute or namespace node is the element
7484 * to which the attribute or namespace node is attached
7485 * Namespace handling !!!
7486 */
7487 if (cur == NULL) {
7488 if (ctxt->context->node == NULL) return(NULL);
7489 switch (ctxt->context->node->type) {
7490 case XML_ELEMENT_NODE:
7491 case XML_TEXT_NODE:
7492 case XML_CDATA_SECTION_NODE:
7493 case XML_ENTITY_REF_NODE:
7494 case XML_ENTITY_NODE:
7495 case XML_PI_NODE:
7496 case XML_COMMENT_NODE:
7497 case XML_NOTATION_NODE:
7498 case XML_DTD_NODE:
7499 case XML_ELEMENT_DECL:
7500 case XML_ATTRIBUTE_DECL:
7501 case XML_XINCLUDE_START:
7502 case XML_XINCLUDE_END:
7503 case XML_ENTITY_DECL:
7504 if (ctxt->context->node->parent == NULL)
7505 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007506 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007507 ((ctxt->context->node->parent->name[0] == ' ') ||
7508 (xmlStrEqual(ctxt->context->node->parent->name,
7509 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007510 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007511 return(ctxt->context->node->parent);
7512 case XML_ATTRIBUTE_NODE: {
7513 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7514
7515 return(att->parent);
7516 }
7517 case XML_DOCUMENT_NODE:
7518 case XML_DOCUMENT_TYPE_NODE:
7519 case XML_DOCUMENT_FRAG_NODE:
7520 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007521#ifdef LIBXML_DOCB_ENABLED
7522 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007523#endif
7524 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007525 case XML_NAMESPACE_DECL: {
7526 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7527
7528 if ((ns->next != NULL) &&
7529 (ns->next->type != XML_NAMESPACE_DECL))
7530 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007531 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007532 }
Owen Taylor3473f882001-02-23 17:55:21 +00007533 }
7534 }
7535 return(NULL);
7536}
7537
7538/**
7539 * xmlXPathNextAncestor:
7540 * @ctxt: the XPath Parser context
7541 * @cur: the current node in the traversal
7542 *
7543 * Traversal function for the "ancestor" direction
7544 * the ancestor axis contains the ancestors of the context node; the ancestors
7545 * of the context node consist of the parent of context node and the parent's
7546 * parent and so on; the nodes are ordered in reverse document order; thus the
7547 * parent is the first node on the axis, and the parent's parent is the second
7548 * node on the axis
7549 *
7550 * Returns the next element following that axis
7551 */
7552xmlNodePtr
7553xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007554 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007555 /*
7556 * the parent of an attribute or namespace node is the element
7557 * to which the attribute or namespace node is attached
7558 * !!!!!!!!!!!!!
7559 */
7560 if (cur == NULL) {
7561 if (ctxt->context->node == NULL) return(NULL);
7562 switch (ctxt->context->node->type) {
7563 case XML_ELEMENT_NODE:
7564 case XML_TEXT_NODE:
7565 case XML_CDATA_SECTION_NODE:
7566 case XML_ENTITY_REF_NODE:
7567 case XML_ENTITY_NODE:
7568 case XML_PI_NODE:
7569 case XML_COMMENT_NODE:
7570 case XML_DTD_NODE:
7571 case XML_ELEMENT_DECL:
7572 case XML_ATTRIBUTE_DECL:
7573 case XML_ENTITY_DECL:
7574 case XML_NOTATION_NODE:
7575 case XML_XINCLUDE_START:
7576 case XML_XINCLUDE_END:
7577 if (ctxt->context->node->parent == NULL)
7578 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007579 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007580 ((ctxt->context->node->parent->name[0] == ' ') ||
7581 (xmlStrEqual(ctxt->context->node->parent->name,
7582 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007583 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007584 return(ctxt->context->node->parent);
7585 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007586 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007587
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007588 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007589 }
7590 case XML_DOCUMENT_NODE:
7591 case XML_DOCUMENT_TYPE_NODE:
7592 case XML_DOCUMENT_FRAG_NODE:
7593 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007594#ifdef LIBXML_DOCB_ENABLED
7595 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007596#endif
7597 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007598 case XML_NAMESPACE_DECL: {
7599 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7600
7601 if ((ns->next != NULL) &&
7602 (ns->next->type != XML_NAMESPACE_DECL))
7603 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007604 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007605 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007606 }
Owen Taylor3473f882001-02-23 17:55:21 +00007607 }
7608 return(NULL);
7609 }
7610 if (cur == ctxt->context->doc->children)
7611 return((xmlNodePtr) ctxt->context->doc);
7612 if (cur == (xmlNodePtr) ctxt->context->doc)
7613 return(NULL);
7614 switch (cur->type) {
7615 case XML_ELEMENT_NODE:
7616 case XML_TEXT_NODE:
7617 case XML_CDATA_SECTION_NODE:
7618 case XML_ENTITY_REF_NODE:
7619 case XML_ENTITY_NODE:
7620 case XML_PI_NODE:
7621 case XML_COMMENT_NODE:
7622 case XML_NOTATION_NODE:
7623 case XML_DTD_NODE:
7624 case XML_ELEMENT_DECL:
7625 case XML_ATTRIBUTE_DECL:
7626 case XML_ENTITY_DECL:
7627 case XML_XINCLUDE_START:
7628 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007629 if (cur->parent == NULL)
7630 return(NULL);
7631 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007632 ((cur->parent->name[0] == ' ') ||
7633 (xmlStrEqual(cur->parent->name,
7634 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007635 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007636 return(cur->parent);
7637 case XML_ATTRIBUTE_NODE: {
7638 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7639
7640 return(att->parent);
7641 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007642 case XML_NAMESPACE_DECL: {
7643 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7644
7645 if ((ns->next != NULL) &&
7646 (ns->next->type != XML_NAMESPACE_DECL))
7647 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007648 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007649 return(NULL);
7650 }
Owen Taylor3473f882001-02-23 17:55:21 +00007651 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);
Owen Taylor3473f882001-02-23 17:55:21 +00007659 }
7660 return(NULL);
7661}
7662
7663/**
7664 * xmlXPathNextAncestorOrSelf:
7665 * @ctxt: the XPath Parser context
7666 * @cur: the current node in the traversal
7667 *
7668 * Traversal function for the "ancestor-or-self" direction
7669 * he ancestor-or-self axis contains the context node and ancestors of
7670 * the context node in reverse document order; thus the context node is
7671 * the first node on the axis, and the context node's parent the second;
7672 * parent here is defined the same as with the parent axis.
7673 *
7674 * Returns the next element following that axis
7675 */
7676xmlNodePtr
7677xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007678 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007679 if (cur == NULL)
7680 return(ctxt->context->node);
7681 return(xmlXPathNextAncestor(ctxt, cur));
7682}
7683
7684/**
7685 * xmlXPathNextFollowingSibling:
7686 * @ctxt: the XPath Parser context
7687 * @cur: the current node in the traversal
7688 *
7689 * Traversal function for the "following-sibling" direction
7690 * The following-sibling axis contains the following siblings of the context
7691 * node in document order.
7692 *
7693 * Returns the next element following that axis
7694 */
7695xmlNodePtr
7696xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007697 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007698 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7699 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7700 return(NULL);
7701 if (cur == (xmlNodePtr) ctxt->context->doc)
7702 return(NULL);
7703 if (cur == NULL)
7704 return(ctxt->context->node->next);
7705 return(cur->next);
7706}
7707
7708/**
7709 * xmlXPathNextPrecedingSibling:
7710 * @ctxt: the XPath Parser context
7711 * @cur: the current node in the traversal
7712 *
7713 * Traversal function for the "preceding-sibling" direction
7714 * The preceding-sibling axis contains the preceding siblings of the context
7715 * node in reverse document order; the first preceding sibling is first on the
7716 * axis; the sibling preceding that node is the second on the axis and so on.
7717 *
7718 * Returns the next element following that axis
7719 */
7720xmlNodePtr
7721xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007722 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007723 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7724 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7725 return(NULL);
7726 if (cur == (xmlNodePtr) ctxt->context->doc)
7727 return(NULL);
7728 if (cur == NULL)
7729 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007730 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7731 cur = cur->prev;
7732 if (cur == NULL)
7733 return(ctxt->context->node->prev);
7734 }
Owen Taylor3473f882001-02-23 17:55:21 +00007735 return(cur->prev);
7736}
7737
7738/**
7739 * xmlXPathNextFollowing:
7740 * @ctxt: the XPath Parser context
7741 * @cur: the current node in the traversal
7742 *
7743 * Traversal function for the "following" direction
7744 * The following axis contains all nodes in the same document as the context
7745 * node that are after the context node in document order, excluding any
7746 * descendants and excluding attribute nodes and namespace nodes; the nodes
7747 * are ordered in document order
7748 *
7749 * Returns the next element following that axis
7750 */
7751xmlNodePtr
7752xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007753 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007754 if (cur != NULL && cur->children != NULL)
7755 return cur->children ;
7756 if (cur == NULL) cur = ctxt->context->node;
7757 if (cur == NULL) return(NULL) ; /* ERROR */
7758 if (cur->next != NULL) return(cur->next) ;
7759 do {
7760 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007761 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007762 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7763 if (cur->next != NULL) return(cur->next);
7764 } while (cur != NULL);
7765 return(cur);
7766}
7767
7768/*
7769 * xmlXPathIsAncestor:
7770 * @ancestor: the ancestor node
7771 * @node: the current node
7772 *
7773 * Check that @ancestor is a @node's ancestor
7774 *
7775 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7776 */
7777static int
7778xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7779 if ((ancestor == NULL) || (node == NULL)) return(0);
7780 /* nodes need to be in the same document */
7781 if (ancestor->doc != node->doc) return(0);
7782 /* avoid searching if ancestor or node is the root node */
7783 if (ancestor == (xmlNodePtr) node->doc) return(1);
7784 if (node == (xmlNodePtr) ancestor->doc) return(0);
7785 while (node->parent != NULL) {
7786 if (node->parent == ancestor)
7787 return(1);
7788 node = node->parent;
7789 }
7790 return(0);
7791}
7792
7793/**
7794 * xmlXPathNextPreceding:
7795 * @ctxt: the XPath Parser context
7796 * @cur: the current node in the traversal
7797 *
7798 * Traversal function for the "preceding" direction
7799 * the preceding axis contains all nodes in the same document as the context
7800 * node that are before the context node in document order, excluding any
7801 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7802 * ordered in reverse document order
7803 *
7804 * Returns the next element following that axis
7805 */
7806xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00007807xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7808{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007809 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007810 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007811 cur = ctxt->context->node;
7812 if (cur == NULL)
7813 return (NULL);
7814 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7815 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00007816 do {
7817 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007818 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7819 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007820 }
7821
7822 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007823 if (cur == NULL)
7824 return (NULL);
7825 if (cur == ctxt->context->doc->children)
7826 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007827 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007828 return (cur);
7829}
7830
7831/**
7832 * xmlXPathNextPrecedingInternal:
7833 * @ctxt: the XPath Parser context
7834 * @cur: the current node in the traversal
7835 *
7836 * Traversal function for the "preceding" direction
7837 * the preceding axis contains all nodes in the same document as the context
7838 * node that are before the context node in document order, excluding any
7839 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7840 * ordered in reverse document order
7841 * This is a faster implementation but internal only since it requires a
7842 * state kept in the parser context: ctxt->ancestor.
7843 *
7844 * Returns the next element following that axis
7845 */
7846static xmlNodePtr
7847xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7848 xmlNodePtr cur)
7849{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007850 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007851 if (cur == NULL) {
7852 cur = ctxt->context->node;
7853 if (cur == NULL)
7854 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00007855 if (cur->type == XML_NAMESPACE_DECL)
7856 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007857 ctxt->ancestor = cur->parent;
7858 }
7859 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7860 cur = cur->prev;
7861 while (cur->prev == NULL) {
7862 cur = cur->parent;
7863 if (cur == NULL)
7864 return (NULL);
7865 if (cur == ctxt->context->doc->children)
7866 return (NULL);
7867 if (cur != ctxt->ancestor)
7868 return (cur);
7869 ctxt->ancestor = cur->parent;
7870 }
7871 cur = cur->prev;
7872 while (cur->last != NULL)
7873 cur = cur->last;
7874 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007875}
7876
7877/**
7878 * xmlXPathNextNamespace:
7879 * @ctxt: the XPath Parser context
7880 * @cur: the current attribute in the traversal
7881 *
7882 * Traversal function for the "namespace" direction
7883 * the namespace axis contains the namespace nodes of the context node;
7884 * the order of nodes on this axis is implementation-defined; the axis will
7885 * be empty unless the context node is an element
7886 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007887 * We keep the XML namespace node at the end of the list.
7888 *
Owen Taylor3473f882001-02-23 17:55:21 +00007889 * Returns the next element following that axis
7890 */
7891xmlNodePtr
7892xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007893 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007894 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00007895 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007896 if (ctxt->context->tmpNsList != NULL)
7897 xmlFree(ctxt->context->tmpNsList);
7898 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00007899 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007900 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007901 if (ctxt->context->tmpNsList != NULL) {
7902 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7903 ctxt->context->tmpNsNr++;
7904 }
7905 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007906 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007907 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00007908 if (ctxt->context->tmpNsNr > 0) {
7909 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7910 } else {
7911 if (ctxt->context->tmpNsList != NULL)
7912 xmlFree(ctxt->context->tmpNsList);
7913 ctxt->context->tmpNsList = NULL;
7914 return(NULL);
7915 }
Owen Taylor3473f882001-02-23 17:55:21 +00007916}
7917
7918/**
7919 * xmlXPathNextAttribute:
7920 * @ctxt: the XPath Parser context
7921 * @cur: the current attribute in the traversal
7922 *
7923 * Traversal function for the "attribute" direction
7924 * TODO: support DTD inherited default attributes
7925 *
7926 * Returns the next element following that axis
7927 */
7928xmlNodePtr
7929xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007930 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00007931 if (ctxt->context->node == NULL)
7932 return(NULL);
7933 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7934 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007935 if (cur == NULL) {
7936 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7937 return(NULL);
7938 return((xmlNodePtr)ctxt->context->node->properties);
7939 }
7940 return((xmlNodePtr)cur->next);
7941}
7942
7943/************************************************************************
7944 * *
7945 * NodeTest Functions *
7946 * *
7947 ************************************************************************/
7948
Owen Taylor3473f882001-02-23 17:55:21 +00007949#define IS_FUNCTION 200
7950
Owen Taylor3473f882001-02-23 17:55:21 +00007951
7952/************************************************************************
7953 * *
7954 * Implicit tree core function library *
7955 * *
7956 ************************************************************************/
7957
7958/**
7959 * xmlXPathRoot:
7960 * @ctxt: the XPath Parser context
7961 *
7962 * Initialize the context to the root of the document
7963 */
7964void
7965xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007966 if ((ctxt == NULL) || (ctxt->context == NULL))
7967 return;
Owen Taylor3473f882001-02-23 17:55:21 +00007968 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007969 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7970 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00007971}
7972
7973/************************************************************************
7974 * *
7975 * The explicit core function library *
7976 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7977 * *
7978 ************************************************************************/
7979
7980
7981/**
7982 * xmlXPathLastFunction:
7983 * @ctxt: the XPath Parser context
7984 * @nargs: the number of arguments
7985 *
7986 * Implement the last() XPath function
7987 * number last()
7988 * The last function returns the number of nodes in the context node list.
7989 */
7990void
7991xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7992 CHECK_ARITY(0);
7993 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007994 valuePush(ctxt,
7995 xmlXPathCacheNewFloat(ctxt->context,
7996 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00007997#ifdef DEBUG_EXPR
7998 xmlGenericError(xmlGenericErrorContext,
7999 "last() : %d\n", ctxt->context->contextSize);
8000#endif
8001 } else {
8002 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8003 }
8004}
8005
8006/**
8007 * xmlXPathPositionFunction:
8008 * @ctxt: the XPath Parser context
8009 * @nargs: the number of arguments
8010 *
8011 * Implement the position() XPath function
8012 * number position()
8013 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008014 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008015 * will be equal to last().
8016 */
8017void
8018xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8019 CHECK_ARITY(0);
8020 if (ctxt->context->proximityPosition >= 0) {
8021 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008022 xmlXPathCacheNewFloat(ctxt->context,
8023 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008024#ifdef DEBUG_EXPR
8025 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8026 ctxt->context->proximityPosition);
8027#endif
8028 } else {
8029 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8030 }
8031}
8032
8033/**
8034 * xmlXPathCountFunction:
8035 * @ctxt: the XPath Parser context
8036 * @nargs: the number of arguments
8037 *
8038 * Implement the count() XPath function
8039 * number count(node-set)
8040 */
8041void
8042xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8043 xmlXPathObjectPtr cur;
8044
8045 CHECK_ARITY(1);
8046 if ((ctxt->value == NULL) ||
8047 ((ctxt->value->type != XPATH_NODESET) &&
8048 (ctxt->value->type != XPATH_XSLT_TREE)))
8049 XP_ERROR(XPATH_INVALID_TYPE);
8050 cur = valuePop(ctxt);
8051
Daniel Veillard911f49a2001-04-07 15:39:35 +00008052 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008053 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008054 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008055 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8056 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008057 } else {
8058 if ((cur->nodesetval->nodeNr != 1) ||
8059 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008060 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008061 } else {
8062 xmlNodePtr tmp;
8063 int i = 0;
8064
8065 tmp = cur->nodesetval->nodeTab[0];
8066 if (tmp != NULL) {
8067 tmp = tmp->children;
8068 while (tmp != NULL) {
8069 tmp = tmp->next;
8070 i++;
8071 }
8072 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008073 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008074 }
8075 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008076 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008077}
8078
8079/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008080 * xmlXPathGetElementsByIds:
8081 * @doc: the document
8082 * @ids: a whitespace separated list of IDs
8083 *
8084 * Selects elements by their unique ID.
8085 *
8086 * Returns a node-set of selected elements.
8087 */
8088static xmlNodeSetPtr
8089xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8090 xmlNodeSetPtr ret;
8091 const xmlChar *cur = ids;
8092 xmlChar *ID;
8093 xmlAttrPtr attr;
8094 xmlNodePtr elem = NULL;
8095
Daniel Veillard7a985a12003-07-06 17:57:42 +00008096 if (ids == NULL) return(NULL);
8097
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008098 ret = xmlXPathNodeSetCreate(NULL);
8099
William M. Brack76e95df2003-10-18 16:20:14 +00008100 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008101 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008102 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008103 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008104
8105 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008106 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008107 /*
8108 * We used to check the fact that the value passed
8109 * was an NCName, but this generated much troubles for
8110 * me and Aleksey Sanin, people blatantly violated that
8111 * constaint, like Visa3D spec.
8112 * if (xmlValidateNCName(ID, 1) == 0)
8113 */
8114 attr = xmlGetID(doc, ID);
8115 if (attr != NULL) {
8116 if (attr->type == XML_ATTRIBUTE_NODE)
8117 elem = attr->parent;
8118 else if (attr->type == XML_ELEMENT_NODE)
8119 elem = (xmlNodePtr) attr;
8120 else
8121 elem = NULL;
8122 if (elem != NULL)
8123 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008124 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008125 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008126 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008127
William M. Brack76e95df2003-10-18 16:20:14 +00008128 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008129 ids = cur;
8130 }
8131 return(ret);
8132}
8133
8134/**
Owen Taylor3473f882001-02-23 17:55:21 +00008135 * xmlXPathIdFunction:
8136 * @ctxt: the XPath Parser context
8137 * @nargs: the number of arguments
8138 *
8139 * Implement the id() XPath function
8140 * node-set id(object)
8141 * The id function selects elements by their unique ID
8142 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8143 * then the result is the union of the result of applying id to the
8144 * string value of each of the nodes in the argument node-set. When the
8145 * argument to id is of any other type, the argument is converted to a
8146 * string as if by a call to the string function; the string is split
8147 * into a whitespace-separated list of tokens (whitespace is any sequence
8148 * of characters matching the production S); the result is a node-set
8149 * containing the elements in the same document as the context node that
8150 * have a unique ID equal to any of the tokens in the list.
8151 */
8152void
8153xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008154 xmlChar *tokens;
8155 xmlNodeSetPtr ret;
8156 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008157
8158 CHECK_ARITY(1);
8159 obj = valuePop(ctxt);
8160 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008161 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008162 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008163 int i;
8164
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008165 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008166
Daniel Veillard911f49a2001-04-07 15:39:35 +00008167 if (obj->nodesetval != NULL) {
8168 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008169 tokens =
8170 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8171 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8172 ret = xmlXPathNodeSetMerge(ret, ns);
8173 xmlXPathFreeNodeSet(ns);
8174 if (tokens != NULL)
8175 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008176 }
Owen Taylor3473f882001-02-23 17:55:21 +00008177 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008178 xmlXPathReleaseObject(ctxt->context, obj);
8179 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008180 return;
8181 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008182 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008183 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008184 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8185 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008186 return;
8187}
8188
8189/**
8190 * xmlXPathLocalNameFunction:
8191 * @ctxt: the XPath Parser context
8192 * @nargs: the number of arguments
8193 *
8194 * Implement the local-name() XPath function
8195 * string local-name(node-set?)
8196 * The local-name function returns a string containing the local part
8197 * of the name of the node in the argument node-set that is first in
8198 * document order. If the node-set is empty or the first node has no
8199 * name, an empty string is returned. If the argument is omitted it
8200 * defaults to the context node.
8201 */
8202void
8203xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8204 xmlXPathObjectPtr cur;
8205
Daniel Veillarda82b1822004-11-08 16:24:57 +00008206 if (ctxt == NULL) return;
8207
Owen Taylor3473f882001-02-23 17:55:21 +00008208 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008209 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8210 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008211 nargs = 1;
8212 }
8213
8214 CHECK_ARITY(1);
8215 if ((ctxt->value == NULL) ||
8216 ((ctxt->value->type != XPATH_NODESET) &&
8217 (ctxt->value->type != XPATH_XSLT_TREE)))
8218 XP_ERROR(XPATH_INVALID_TYPE);
8219 cur = valuePop(ctxt);
8220
Daniel Veillard911f49a2001-04-07 15:39:35 +00008221 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008222 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008223 } else {
8224 int i = 0; /* Should be first in document order !!!!! */
8225 switch (cur->nodesetval->nodeTab[i]->type) {
8226 case XML_ELEMENT_NODE:
8227 case XML_ATTRIBUTE_NODE:
8228 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008229 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008230 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008231 else
8232 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008233 xmlXPathCacheNewString(ctxt->context,
8234 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008235 break;
8236 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008237 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008238 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8239 break;
8240 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008241 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008242 }
8243 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008244 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008245}
8246
8247/**
8248 * xmlXPathNamespaceURIFunction:
8249 * @ctxt: the XPath Parser context
8250 * @nargs: the number of arguments
8251 *
8252 * Implement the namespace-uri() XPath function
8253 * string namespace-uri(node-set?)
8254 * The namespace-uri function returns a string containing the
8255 * namespace URI of the expanded name of the node in the argument
8256 * node-set that is first in document order. If the node-set is empty,
8257 * the first node has no name, or the expanded name has no namespace
8258 * URI, an empty string is returned. If the argument is omitted it
8259 * defaults to the context node.
8260 */
8261void
8262xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8263 xmlXPathObjectPtr cur;
8264
Daniel Veillarda82b1822004-11-08 16:24:57 +00008265 if (ctxt == NULL) return;
8266
Owen Taylor3473f882001-02-23 17:55:21 +00008267 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008268 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8269 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008270 nargs = 1;
8271 }
8272 CHECK_ARITY(1);
8273 if ((ctxt->value == NULL) ||
8274 ((ctxt->value->type != XPATH_NODESET) &&
8275 (ctxt->value->type != XPATH_XSLT_TREE)))
8276 XP_ERROR(XPATH_INVALID_TYPE);
8277 cur = valuePop(ctxt);
8278
Daniel Veillard911f49a2001-04-07 15:39:35 +00008279 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008280 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008281 } else {
8282 int i = 0; /* Should be first in document order !!!!! */
8283 switch (cur->nodesetval->nodeTab[i]->type) {
8284 case XML_ELEMENT_NODE:
8285 case XML_ATTRIBUTE_NODE:
8286 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008287 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008288 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008289 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008290 cur->nodesetval->nodeTab[i]->ns->href));
8291 break;
8292 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008293 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008294 }
8295 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008296 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008297}
8298
8299/**
8300 * xmlXPathNameFunction:
8301 * @ctxt: the XPath Parser context
8302 * @nargs: the number of arguments
8303 *
8304 * Implement the name() XPath function
8305 * string name(node-set?)
8306 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008307 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008308 * order. The QName must represent the name with respect to the namespace
8309 * declarations in effect on the node whose name is being represented.
8310 * Typically, this will be the form in which the name occurred in the XML
8311 * source. This need not be the case if there are namespace declarations
8312 * in effect on the node that associate multiple prefixes with the same
8313 * namespace. However, an implementation may include information about
8314 * the original prefix in its representation of nodes; in this case, an
8315 * implementation can ensure that the returned string is always the same
8316 * as the QName used in the XML source. If the argument it omitted it
8317 * defaults to the context node.
8318 * Libxml keep the original prefix so the "real qualified name" used is
8319 * returned.
8320 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008321static void
Daniel Veillard04383752001-07-08 14:27:15 +00008322xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8323{
Owen Taylor3473f882001-02-23 17:55:21 +00008324 xmlXPathObjectPtr cur;
8325
8326 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008327 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8328 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008329 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008330 }
8331
8332 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008333 if ((ctxt->value == NULL) ||
8334 ((ctxt->value->type != XPATH_NODESET) &&
8335 (ctxt->value->type != XPATH_XSLT_TREE)))
8336 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008337 cur = valuePop(ctxt);
8338
Daniel Veillard911f49a2001-04-07 15:39:35 +00008339 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008340 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008341 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008342 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008343
Daniel Veillard04383752001-07-08 14:27:15 +00008344 switch (cur->nodesetval->nodeTab[i]->type) {
8345 case XML_ELEMENT_NODE:
8346 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008347 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008348 valuePush(ctxt,
8349 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008350 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8351 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008352 valuePush(ctxt,
8353 xmlXPathCacheNewString(ctxt->context,
8354 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008355 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008356 xmlChar *fullname;
8357
8358 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8359 cur->nodesetval->nodeTab[i]->ns->prefix,
8360 NULL, 0);
8361 if (fullname == cur->nodesetval->nodeTab[i]->name)
8362 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8363 if (fullname == NULL) {
8364 XP_ERROR(XPATH_MEMORY_ERROR);
8365 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008366 valuePush(ctxt, xmlXPathCacheWrapString(
8367 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008368 }
8369 break;
8370 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008371 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8372 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008373 xmlXPathLocalNameFunction(ctxt, 1);
8374 }
Owen Taylor3473f882001-02-23 17:55:21 +00008375 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008376 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008377}
8378
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008379
8380/**
Owen Taylor3473f882001-02-23 17:55:21 +00008381 * xmlXPathStringFunction:
8382 * @ctxt: the XPath Parser context
8383 * @nargs: the number of arguments
8384 *
8385 * Implement the string() XPath function
8386 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008387 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008388 * - A node-set is converted to a string by returning the value of
8389 * the node in the node-set that is first in document order.
8390 * If the node-set is empty, an empty string is returned.
8391 * - A number is converted to a string as follows
8392 * + NaN is converted to the string NaN
8393 * + positive zero is converted to the string 0
8394 * + negative zero is converted to the string 0
8395 * + positive infinity is converted to the string Infinity
8396 * + negative infinity is converted to the string -Infinity
8397 * + if the number is an integer, the number is represented in
8398 * decimal form as a Number with no decimal point and no leading
8399 * zeros, preceded by a minus sign (-) if the number is negative
8400 * + otherwise, the number is represented in decimal form as a
8401 * Number including a decimal point with at least one digit
8402 * before the decimal point and at least one digit after the
8403 * decimal point, preceded by a minus sign (-) if the number
8404 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008405 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008406 * before the decimal point; beyond the one required digit
8407 * after the decimal point there must be as many, but only as
8408 * many, more digits as are needed to uniquely distinguish the
8409 * number from all other IEEE 754 numeric values.
8410 * - The boolean false value is converted to the string false.
8411 * The boolean true value is converted to the string true.
8412 *
8413 * If the argument is omitted, it defaults to a node-set with the
8414 * context node as its only member.
8415 */
8416void
8417xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8418 xmlXPathObjectPtr cur;
8419
Daniel Veillarda82b1822004-11-08 16:24:57 +00008420 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008421 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008422 valuePush(ctxt,
8423 xmlXPathCacheWrapString(ctxt->context,
8424 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008425 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008426 }
8427
8428 CHECK_ARITY(1);
8429 cur = valuePop(ctxt);
8430 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008431 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008432}
8433
8434/**
8435 * xmlXPathStringLengthFunction:
8436 * @ctxt: the XPath Parser context
8437 * @nargs: the number of arguments
8438 *
8439 * Implement the string-length() XPath function
8440 * number string-length(string?)
8441 * The string-length returns the number of characters in the string
8442 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8443 * the context node converted to a string, in other words the value
8444 * of the context node.
8445 */
8446void
8447xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8448 xmlXPathObjectPtr cur;
8449
8450 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008451 if ((ctxt == NULL) || (ctxt->context == NULL))
8452 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008453 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008454 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008455 } else {
8456 xmlChar *content;
8457
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008458 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008459 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8460 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008461 xmlFree(content);
8462 }
8463 return;
8464 }
8465 CHECK_ARITY(1);
8466 CAST_TO_STRING;
8467 CHECK_TYPE(XPATH_STRING);
8468 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008469 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8470 xmlUTF8Strlen(cur->stringval)));
8471 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008472}
8473
8474/**
8475 * xmlXPathConcatFunction:
8476 * @ctxt: the XPath Parser context
8477 * @nargs: the number of arguments
8478 *
8479 * Implement the concat() XPath function
8480 * string concat(string, string, string*)
8481 * The concat function returns the concatenation of its arguments.
8482 */
8483void
8484xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8485 xmlXPathObjectPtr cur, newobj;
8486 xmlChar *tmp;
8487
Daniel Veillarda82b1822004-11-08 16:24:57 +00008488 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008489 if (nargs < 2) {
8490 CHECK_ARITY(2);
8491 }
8492
8493 CAST_TO_STRING;
8494 cur = valuePop(ctxt);
8495 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008496 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008497 return;
8498 }
8499 nargs--;
8500
8501 while (nargs > 0) {
8502 CAST_TO_STRING;
8503 newobj = valuePop(ctxt);
8504 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008505 xmlXPathReleaseObject(ctxt->context, newobj);
8506 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008507 XP_ERROR(XPATH_INVALID_TYPE);
8508 }
8509 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8510 newobj->stringval = cur->stringval;
8511 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008512 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008513 nargs--;
8514 }
8515 valuePush(ctxt, cur);
8516}
8517
8518/**
8519 * xmlXPathContainsFunction:
8520 * @ctxt: the XPath Parser context
8521 * @nargs: the number of arguments
8522 *
8523 * Implement the contains() XPath function
8524 * boolean contains(string, string)
8525 * The contains function returns true if the first argument string
8526 * contains the second argument string, and otherwise returns false.
8527 */
8528void
8529xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8530 xmlXPathObjectPtr hay, needle;
8531
8532 CHECK_ARITY(2);
8533 CAST_TO_STRING;
8534 CHECK_TYPE(XPATH_STRING);
8535 needle = valuePop(ctxt);
8536 CAST_TO_STRING;
8537 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008538
Owen Taylor3473f882001-02-23 17:55:21 +00008539 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008540 xmlXPathReleaseObject(ctxt->context, hay);
8541 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008542 XP_ERROR(XPATH_INVALID_TYPE);
8543 }
8544 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008545 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008546 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008547 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8548 xmlXPathReleaseObject(ctxt->context, hay);
8549 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008550}
8551
8552/**
8553 * xmlXPathStartsWithFunction:
8554 * @ctxt: the XPath Parser context
8555 * @nargs: the number of arguments
8556 *
8557 * Implement the starts-with() XPath function
8558 * boolean starts-with(string, string)
8559 * The starts-with function returns true if the first argument string
8560 * starts with the second argument string, and otherwise returns false.
8561 */
8562void
8563xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8564 xmlXPathObjectPtr hay, needle;
8565 int n;
8566
8567 CHECK_ARITY(2);
8568 CAST_TO_STRING;
8569 CHECK_TYPE(XPATH_STRING);
8570 needle = valuePop(ctxt);
8571 CAST_TO_STRING;
8572 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008573
Owen Taylor3473f882001-02-23 17:55:21 +00008574 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008575 xmlXPathReleaseObject(ctxt->context, hay);
8576 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008577 XP_ERROR(XPATH_INVALID_TYPE);
8578 }
8579 n = xmlStrlen(needle->stringval);
8580 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008581 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008582 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008583 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8584 xmlXPathReleaseObject(ctxt->context, hay);
8585 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008586}
8587
8588/**
8589 * xmlXPathSubstringFunction:
8590 * @ctxt: the XPath Parser context
8591 * @nargs: the number of arguments
8592 *
8593 * Implement the substring() XPath function
8594 * string substring(string, number, number?)
8595 * The substring function returns the substring of the first argument
8596 * starting at the position specified in the second argument with
8597 * length specified in the third argument. For example,
8598 * substring("12345",2,3) returns "234". If the third argument is not
8599 * specified, it returns the substring starting at the position specified
8600 * in the second argument and continuing to the end of the string. For
8601 * example, substring("12345",2) returns "2345". More precisely, each
8602 * character in the string (see [3.6 Strings]) is considered to have a
8603 * numeric position: the position of the first character is 1, the position
8604 * of the second character is 2 and so on. The returned substring contains
8605 * those characters for which the position of the character is greater than
8606 * or equal to the second argument and, if the third argument is specified,
8607 * less than the sum of the second and third arguments; the comparisons
8608 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8609 * - substring("12345", 1.5, 2.6) returns "234"
8610 * - substring("12345", 0, 3) returns "12"
8611 * - substring("12345", 0 div 0, 3) returns ""
8612 * - substring("12345", 1, 0 div 0) returns ""
8613 * - substring("12345", -42, 1 div 0) returns "12345"
8614 * - substring("12345", -1 div 0, 1 div 0) returns ""
8615 */
8616void
8617xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8618 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008619 double le=0, in;
8620 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008621 xmlChar *ret;
8622
Owen Taylor3473f882001-02-23 17:55:21 +00008623 if (nargs < 2) {
8624 CHECK_ARITY(2);
8625 }
8626 if (nargs > 3) {
8627 CHECK_ARITY(3);
8628 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008629 /*
8630 * take care of possible last (position) argument
8631 */
Owen Taylor3473f882001-02-23 17:55:21 +00008632 if (nargs == 3) {
8633 CAST_TO_NUMBER;
8634 CHECK_TYPE(XPATH_NUMBER);
8635 len = valuePop(ctxt);
8636 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008637 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008638 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008639
Owen Taylor3473f882001-02-23 17:55:21 +00008640 CAST_TO_NUMBER;
8641 CHECK_TYPE(XPATH_NUMBER);
8642 start = valuePop(ctxt);
8643 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008644 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008645 CAST_TO_STRING;
8646 CHECK_TYPE(XPATH_STRING);
8647 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008648 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008649
Daniel Veillard97ac1312001-05-30 19:14:17 +00008650 /*
8651 * If last pos not present, calculate last position
8652 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008653 if (nargs != 3) {
8654 le = (double)m;
8655 if (in < 1.0)
8656 in = 1.0;
8657 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008658
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008659 /* Need to check for the special cases where either
8660 * the index is NaN, the length is NaN, or both
8661 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008662 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008663 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008664 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008665 * To meet the requirements of the spec, the arguments
8666 * must be converted to integer format before
8667 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008668 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008669 * First we go to integer form, rounding up
8670 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008671 */
8672 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008673 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008674
Daniel Veillard9e412302002-06-10 15:59:44 +00008675 if (xmlXPathIsInf(le) == 1) {
8676 l = m;
8677 if (i < 1)
8678 i = 1;
8679 }
8680 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8681 l = 0;
8682 else {
8683 l = (int) le;
8684 if (((double)l)+0.5 <= le) l++;
8685 }
8686
8687 /* Now we normalize inidices */
8688 i -= 1;
8689 l += i;
8690 if (i < 0)
8691 i = 0;
8692 if (l > m)
8693 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00008694
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008695 /* number of chars to copy */
8696 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00008697
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008698 ret = xmlUTF8Strsub(str->stringval, i, l);
8699 }
8700 else {
8701 ret = NULL;
8702 }
Owen Taylor3473f882001-02-23 17:55:21 +00008703 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008704 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008705 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008706 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008707 xmlFree(ret);
8708 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008709 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00008710}
8711
8712/**
8713 * xmlXPathSubstringBeforeFunction:
8714 * @ctxt: the XPath Parser context
8715 * @nargs: the number of arguments
8716 *
8717 * Implement the substring-before() XPath function
8718 * string substring-before(string, string)
8719 * The substring-before function returns the substring of the first
8720 * argument string that precedes the first occurrence of the second
8721 * argument string in the first argument string, or the empty string
8722 * if the first argument string does not contain the second argument
8723 * string. For example, substring-before("1999/04/01","/") returns 1999.
8724 */
8725void
8726xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8727 xmlXPathObjectPtr str;
8728 xmlXPathObjectPtr find;
8729 xmlBufferPtr target;
8730 const xmlChar *point;
8731 int offset;
8732
8733 CHECK_ARITY(2);
8734 CAST_TO_STRING;
8735 find = valuePop(ctxt);
8736 CAST_TO_STRING;
8737 str = valuePop(ctxt);
8738
8739 target = xmlBufferCreate();
8740 if (target) {
8741 point = xmlStrstr(str->stringval, find->stringval);
8742 if (point) {
8743 offset = (int)(point - str->stringval);
8744 xmlBufferAdd(target, str->stringval, offset);
8745 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008746 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8747 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008748 xmlBufferFree(target);
8749 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008750 xmlXPathReleaseObject(ctxt->context, str);
8751 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008752}
8753
8754/**
8755 * xmlXPathSubstringAfterFunction:
8756 * @ctxt: the XPath Parser context
8757 * @nargs: the number of arguments
8758 *
8759 * Implement the substring-after() XPath function
8760 * string substring-after(string, string)
8761 * The substring-after function returns the substring of the first
8762 * argument string that follows the first occurrence of the second
8763 * argument string in the first argument string, or the empty stringi
8764 * if the first argument string does not contain the second argument
8765 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8766 * and substring-after("1999/04/01","19") returns 99/04/01.
8767 */
8768void
8769xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8770 xmlXPathObjectPtr str;
8771 xmlXPathObjectPtr find;
8772 xmlBufferPtr target;
8773 const xmlChar *point;
8774 int offset;
8775
8776 CHECK_ARITY(2);
8777 CAST_TO_STRING;
8778 find = valuePop(ctxt);
8779 CAST_TO_STRING;
8780 str = valuePop(ctxt);
8781
8782 target = xmlBufferCreate();
8783 if (target) {
8784 point = xmlStrstr(str->stringval, find->stringval);
8785 if (point) {
8786 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
8787 xmlBufferAdd(target, &str->stringval[offset],
8788 xmlStrlen(str->stringval) - offset);
8789 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008790 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8791 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008792 xmlBufferFree(target);
8793 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008794 xmlXPathReleaseObject(ctxt->context, str);
8795 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008796}
8797
8798/**
8799 * xmlXPathNormalizeFunction:
8800 * @ctxt: the XPath Parser context
8801 * @nargs: the number of arguments
8802 *
8803 * Implement the normalize-space() XPath function
8804 * string normalize-space(string?)
8805 * The normalize-space function returns the argument string with white
8806 * space normalized by stripping leading and trailing whitespace
8807 * and replacing sequences of whitespace characters by a single
8808 * space. Whitespace characters are the same allowed by the S production
8809 * in XML. If the argument is omitted, it defaults to the context
8810 * node converted to a string, in other words the value of the context node.
8811 */
8812void
8813xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8814 xmlXPathObjectPtr obj = NULL;
8815 xmlChar *source = NULL;
8816 xmlBufferPtr target;
8817 xmlChar blank;
8818
Daniel Veillarda82b1822004-11-08 16:24:57 +00008819 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008820 if (nargs == 0) {
8821 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008822 valuePush(ctxt,
8823 xmlXPathCacheWrapString(ctxt->context,
8824 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00008825 nargs = 1;
8826 }
8827
8828 CHECK_ARITY(1);
8829 CAST_TO_STRING;
8830 CHECK_TYPE(XPATH_STRING);
8831 obj = valuePop(ctxt);
8832 source = obj->stringval;
8833
8834 target = xmlBufferCreate();
8835 if (target && source) {
8836
8837 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00008838 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00008839 source++;
8840
8841 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8842 blank = 0;
8843 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00008844 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008845 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00008846 } else {
8847 if (blank) {
8848 xmlBufferAdd(target, &blank, 1);
8849 blank = 0;
8850 }
8851 xmlBufferAdd(target, source, 1);
8852 }
8853 source++;
8854 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008855 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8856 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008857 xmlBufferFree(target);
8858 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008859 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008860}
8861
8862/**
8863 * xmlXPathTranslateFunction:
8864 * @ctxt: the XPath Parser context
8865 * @nargs: the number of arguments
8866 *
8867 * Implement the translate() XPath function
8868 * string translate(string, string, string)
8869 * The translate function returns the first argument string with
8870 * occurrences of characters in the second argument string replaced
8871 * by the character at the corresponding position in the third argument
8872 * string. For example, translate("bar","abc","ABC") returns the string
8873 * BAr. If there is a character in the second argument string with no
8874 * character at a corresponding position in the third argument string
8875 * (because the second argument string is longer than the third argument
8876 * string), then occurrences of that character in the first argument
8877 * string are removed. For example, translate("--aaa--","abc-","ABC")
8878 * returns "AAA". If a character occurs more than once in second
8879 * argument string, then the first occurrence determines the replacement
8880 * character. If the third argument string is longer than the second
8881 * argument string, then excess characters are ignored.
8882 */
8883void
8884xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00008885 xmlXPathObjectPtr str;
8886 xmlXPathObjectPtr from;
8887 xmlXPathObjectPtr to;
8888 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008889 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008890 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00008891 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008892 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00008893
Daniel Veillarde043ee12001-04-16 14:08:07 +00008894 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00008895
Daniel Veillarde043ee12001-04-16 14:08:07 +00008896 CAST_TO_STRING;
8897 to = valuePop(ctxt);
8898 CAST_TO_STRING;
8899 from = valuePop(ctxt);
8900 CAST_TO_STRING;
8901 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008902
Daniel Veillarde043ee12001-04-16 14:08:07 +00008903 target = xmlBufferCreate();
8904 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008905 max = xmlUTF8Strlen(to->stringval);
8906 for (cptr = str->stringval; (ch=*cptr); ) {
8907 offset = xmlUTF8Strloc(from->stringval, cptr);
8908 if (offset >= 0) {
8909 if (offset < max) {
8910 point = xmlUTF8Strpos(to->stringval, offset);
8911 if (point)
8912 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
8913 }
8914 } else
8915 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8916
8917 /* Step to next character in input */
8918 cptr++;
8919 if ( ch & 0x80 ) {
8920 /* if not simple ascii, verify proper format */
8921 if ( (ch & 0xc0) != 0xc0 ) {
8922 xmlGenericError(xmlGenericErrorContext,
8923 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8924 break;
8925 }
8926 /* then skip over remaining bytes for this char */
8927 while ( (ch <<= 1) & 0x80 )
8928 if ( (*cptr++ & 0xc0) != 0x80 ) {
8929 xmlGenericError(xmlGenericErrorContext,
8930 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8931 break;
8932 }
8933 if (ch & 0x80) /* must have had error encountered */
8934 break;
8935 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00008936 }
Owen Taylor3473f882001-02-23 17:55:21 +00008937 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008938 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8939 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00008940 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008941 xmlXPathReleaseObject(ctxt->context, str);
8942 xmlXPathReleaseObject(ctxt->context, from);
8943 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00008944}
8945
8946/**
8947 * xmlXPathBooleanFunction:
8948 * @ctxt: the XPath Parser context
8949 * @nargs: the number of arguments
8950 *
8951 * Implement the boolean() XPath function
8952 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00008953 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008954 * - a number is true if and only if it is neither positive or
8955 * negative zero nor NaN
8956 * - a node-set is true if and only if it is non-empty
8957 * - a string is true if and only if its length is non-zero
8958 */
8959void
8960xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8961 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00008962
8963 CHECK_ARITY(1);
8964 cur = valuePop(ctxt);
8965 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008966 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008967 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008968}
8969
8970/**
8971 * xmlXPathNotFunction:
8972 * @ctxt: the XPath Parser context
8973 * @nargs: the number of arguments
8974 *
8975 * Implement the not() XPath function
8976 * boolean not(boolean)
8977 * The not function returns true if its argument is false,
8978 * and false otherwise.
8979 */
8980void
8981xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8982 CHECK_ARITY(1);
8983 CAST_TO_BOOLEAN;
8984 CHECK_TYPE(XPATH_BOOLEAN);
8985 ctxt->value->boolval = ! ctxt->value->boolval;
8986}
8987
8988/**
8989 * xmlXPathTrueFunction:
8990 * @ctxt: the XPath Parser context
8991 * @nargs: the number of arguments
8992 *
8993 * Implement the true() XPath function
8994 * boolean true()
8995 */
8996void
8997xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8998 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008999 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009000}
9001
9002/**
9003 * xmlXPathFalseFunction:
9004 * @ctxt: the XPath Parser context
9005 * @nargs: the number of arguments
9006 *
9007 * Implement the false() XPath function
9008 * boolean false()
9009 */
9010void
9011xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009013 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009014}
9015
9016/**
9017 * xmlXPathLangFunction:
9018 * @ctxt: the XPath Parser context
9019 * @nargs: the number of arguments
9020 *
9021 * Implement the lang() XPath function
9022 * boolean lang(string)
9023 * The lang function returns true or false depending on whether the
9024 * language of the context node as specified by xml:lang attributes
9025 * is the same as or is a sublanguage of the language specified by
9026 * the argument string. The language of the context node is determined
9027 * by the value of the xml:lang attribute on the context node, or, if
9028 * the context node has no xml:lang attribute, by the value of the
9029 * xml:lang attribute on the nearest ancestor of the context node that
9030 * has an xml:lang attribute. If there is no such attribute, then lang
9031 * returns false. If there is such an attribute, then lang returns
9032 * true if the attribute value is equal to the argument ignoring case,
9033 * or if there is some suffix starting with - such that the attribute
9034 * value is equal to the argument ignoring that suffix of the attribute
9035 * value and ignoring case.
9036 */
9037void
9038xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009039 xmlXPathObjectPtr val = NULL;
9040 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009041 const xmlChar *lang;
9042 int ret = 0;
9043 int i;
9044
9045 CHECK_ARITY(1);
9046 CAST_TO_STRING;
9047 CHECK_TYPE(XPATH_STRING);
9048 val = valuePop(ctxt);
9049 lang = val->stringval;
9050 theLang = xmlNodeGetLang(ctxt->context->node);
9051 if ((theLang != NULL) && (lang != NULL)) {
9052 for (i = 0;lang[i] != 0;i++)
9053 if (toupper(lang[i]) != toupper(theLang[i]))
9054 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009055 if ((theLang[i] == 0) || (theLang[i] == '-'))
9056 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009057 }
9058not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009059 if (theLang != NULL)
9060 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009061
9062 xmlXPathReleaseObject(ctxt->context, val);
9063 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009064}
9065
9066/**
9067 * xmlXPathNumberFunction:
9068 * @ctxt: the XPath Parser context
9069 * @nargs: the number of arguments
9070 *
9071 * Implement the number() XPath function
9072 * number number(object?)
9073 */
9074void
9075xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9076 xmlXPathObjectPtr cur;
9077 double res;
9078
Daniel Veillarda82b1822004-11-08 16:24:57 +00009079 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009080 if (nargs == 0) {
9081 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009082 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009083 } else {
9084 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9085
9086 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009087 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009088 xmlFree(content);
9089 }
9090 return;
9091 }
9092
9093 CHECK_ARITY(1);
9094 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009095 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009096}
9097
9098/**
9099 * xmlXPathSumFunction:
9100 * @ctxt: the XPath Parser context
9101 * @nargs: the number of arguments
9102 *
9103 * Implement the sum() XPath function
9104 * number sum(node-set)
9105 * The sum function returns the sum of the values of the nodes in
9106 * the argument node-set.
9107 */
9108void
9109xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9110 xmlXPathObjectPtr cur;
9111 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009112 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009113
9114 CHECK_ARITY(1);
9115 if ((ctxt->value == NULL) ||
9116 ((ctxt->value->type != XPATH_NODESET) &&
9117 (ctxt->value->type != XPATH_XSLT_TREE)))
9118 XP_ERROR(XPATH_INVALID_TYPE);
9119 cur = valuePop(ctxt);
9120
William M. Brack08171912003-12-29 02:52:11 +00009121 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009122 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9123 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009124 }
9125 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009126 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9127 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009128}
9129
William M. Brack3d426662005-04-19 14:40:28 +00009130/*
9131 * To assure working code on multiple platforms, we want to only depend
9132 * upon the characteristic truncation of converting a floating point value
9133 * to an integer. Unfortunately, because of the different storage sizes
9134 * of our internal floating point value (double) and integer (int), we
9135 * can't directly convert (see bug 301162). This macro is a messy
9136 * 'workaround'
9137 */
9138#define XTRUNC(f, v) \
9139 f = fmod((v), INT_MAX); \
9140 f = (v) - (f) + (double)((int)(f));
9141
Owen Taylor3473f882001-02-23 17:55:21 +00009142/**
9143 * xmlXPathFloorFunction:
9144 * @ctxt: the XPath Parser context
9145 * @nargs: the number of arguments
9146 *
9147 * Implement the floor() XPath function
9148 * number floor(number)
9149 * The floor function returns the largest (closest to positive infinity)
9150 * number that is not greater than the argument and that is an integer.
9151 */
9152void
9153xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009154 double f;
9155
Owen Taylor3473f882001-02-23 17:55:21 +00009156 CHECK_ARITY(1);
9157 CAST_TO_NUMBER;
9158 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009159
William M. Brack3d426662005-04-19 14:40:28 +00009160 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009161 if (f != ctxt->value->floatval) {
9162 if (ctxt->value->floatval > 0)
9163 ctxt->value->floatval = f;
9164 else
9165 ctxt->value->floatval = f - 1;
9166 }
Owen Taylor3473f882001-02-23 17:55:21 +00009167}
9168
9169/**
9170 * xmlXPathCeilingFunction:
9171 * @ctxt: the XPath Parser context
9172 * @nargs: the number of arguments
9173 *
9174 * Implement the ceiling() XPath function
9175 * number ceiling(number)
9176 * The ceiling function returns the smallest (closest to negative infinity)
9177 * number that is not less than the argument and that is an integer.
9178 */
9179void
9180xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9181 double f;
9182
9183 CHECK_ARITY(1);
9184 CAST_TO_NUMBER;
9185 CHECK_TYPE(XPATH_NUMBER);
9186
9187#if 0
9188 ctxt->value->floatval = ceil(ctxt->value->floatval);
9189#else
William M. Brack3d426662005-04-19 14:40:28 +00009190 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009191 if (f != ctxt->value->floatval) {
9192 if (ctxt->value->floatval > 0)
9193 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009194 else {
9195 if (ctxt->value->floatval < 0 && f == 0)
9196 ctxt->value->floatval = xmlXPathNZERO;
9197 else
9198 ctxt->value->floatval = f;
9199 }
9200
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009201 }
Owen Taylor3473f882001-02-23 17:55:21 +00009202#endif
9203}
9204
9205/**
9206 * xmlXPathRoundFunction:
9207 * @ctxt: the XPath Parser context
9208 * @nargs: the number of arguments
9209 *
9210 * Implement the round() XPath function
9211 * number round(number)
9212 * The round function returns the number that is closest to the
9213 * argument and that is an integer. If there are two such numbers,
9214 * then the one that is even is returned.
9215 */
9216void
9217xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9218 double f;
9219
9220 CHECK_ARITY(1);
9221 CAST_TO_NUMBER;
9222 CHECK_TYPE(XPATH_NUMBER);
9223
Daniel Veillardcda96922001-08-21 10:56:31 +00009224 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9225 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9226 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009227 (ctxt->value->floatval == 0.0))
9228 return;
9229
William M. Brack3d426662005-04-19 14:40:28 +00009230 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009231 if (ctxt->value->floatval < 0) {
9232 if (ctxt->value->floatval < f - 0.5)
9233 ctxt->value->floatval = f - 1;
9234 else
9235 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009236 if (ctxt->value->floatval == 0)
9237 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009238 } else {
9239 if (ctxt->value->floatval < f + 0.5)
9240 ctxt->value->floatval = f;
9241 else
9242 ctxt->value->floatval = f + 1;
9243 }
Owen Taylor3473f882001-02-23 17:55:21 +00009244}
9245
9246/************************************************************************
9247 * *
9248 * The Parser *
9249 * *
9250 ************************************************************************/
9251
9252/*
William M. Brack08171912003-12-29 02:52:11 +00009253 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009254 * implementation.
9255 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009256static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009257static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009258static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009259static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009260static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9261 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009262
9263/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009264 * xmlXPathCurrentChar:
9265 * @ctxt: the XPath parser context
9266 * @cur: pointer to the beginning of the char
9267 * @len: pointer to the length of the char read
9268 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009269 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009270 * bytes in the input buffer.
9271 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009272 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009273 */
9274
9275static int
9276xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9277 unsigned char c;
9278 unsigned int val;
9279 const xmlChar *cur;
9280
9281 if (ctxt == NULL)
9282 return(0);
9283 cur = ctxt->cur;
9284
9285 /*
9286 * We are supposed to handle UTF8, check it's valid
9287 * From rfc2044: encoding of the Unicode values on UTF-8:
9288 *
9289 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9290 * 0000 0000-0000 007F 0xxxxxxx
9291 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9292 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9293 *
9294 * Check for the 0x110000 limit too
9295 */
9296 c = *cur;
9297 if (c & 0x80) {
9298 if ((cur[1] & 0xc0) != 0x80)
9299 goto encoding_error;
9300 if ((c & 0xe0) == 0xe0) {
9301
9302 if ((cur[2] & 0xc0) != 0x80)
9303 goto encoding_error;
9304 if ((c & 0xf0) == 0xf0) {
9305 if (((c & 0xf8) != 0xf0) ||
9306 ((cur[3] & 0xc0) != 0x80))
9307 goto encoding_error;
9308 /* 4-byte code */
9309 *len = 4;
9310 val = (cur[0] & 0x7) << 18;
9311 val |= (cur[1] & 0x3f) << 12;
9312 val |= (cur[2] & 0x3f) << 6;
9313 val |= cur[3] & 0x3f;
9314 } else {
9315 /* 3-byte code */
9316 *len = 3;
9317 val = (cur[0] & 0xf) << 12;
9318 val |= (cur[1] & 0x3f) << 6;
9319 val |= cur[2] & 0x3f;
9320 }
9321 } else {
9322 /* 2-byte code */
9323 *len = 2;
9324 val = (cur[0] & 0x1f) << 6;
9325 val |= cur[1] & 0x3f;
9326 }
9327 if (!IS_CHAR(val)) {
9328 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9329 }
9330 return(val);
9331 } else {
9332 /* 1-byte code */
9333 *len = 1;
9334 return((int) *cur);
9335 }
9336encoding_error:
9337 /*
William M. Brack08171912003-12-29 02:52:11 +00009338 * If we detect an UTF8 error that probably means that the
9339 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009340 * declaration header. Report the error and switch the encoding
9341 * to ISO-Latin-1 (if you don't like this policy, just declare the
9342 * encoding !)
9343 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009344 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009345 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009346}
9347
9348/**
Owen Taylor3473f882001-02-23 17:55:21 +00009349 * xmlXPathParseNCName:
9350 * @ctxt: the XPath Parser context
9351 *
9352 * parse an XML namespace non qualified name.
9353 *
9354 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9355 *
9356 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9357 * CombiningChar | Extender
9358 *
9359 * Returns the namespace name or NULL
9360 */
9361
9362xmlChar *
9363xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009364 const xmlChar *in;
9365 xmlChar *ret;
9366 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009367
Daniel Veillarda82b1822004-11-08 16:24:57 +00009368 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009369 /*
9370 * Accelerator for simple ASCII names
9371 */
9372 in = ctxt->cur;
9373 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9374 ((*in >= 0x41) && (*in <= 0x5A)) ||
9375 (*in == '_')) {
9376 in++;
9377 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9378 ((*in >= 0x41) && (*in <= 0x5A)) ||
9379 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009380 (*in == '_') || (*in == '.') ||
9381 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009382 in++;
9383 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9384 (*in == '[') || (*in == ']') || (*in == ':') ||
9385 (*in == '@') || (*in == '*')) {
9386 count = in - ctxt->cur;
9387 if (count == 0)
9388 return(NULL);
9389 ret = xmlStrndup(ctxt->cur, count);
9390 ctxt->cur = in;
9391 return(ret);
9392 }
9393 }
9394 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009395}
9396
Daniel Veillard2156a562001-04-28 12:24:34 +00009397
Owen Taylor3473f882001-02-23 17:55:21 +00009398/**
9399 * xmlXPathParseQName:
9400 * @ctxt: the XPath Parser context
9401 * @prefix: a xmlChar **
9402 *
9403 * parse an XML qualified name
9404 *
9405 * [NS 5] QName ::= (Prefix ':')? LocalPart
9406 *
9407 * [NS 6] Prefix ::= NCName
9408 *
9409 * [NS 7] LocalPart ::= NCName
9410 *
9411 * Returns the function returns the local part, and prefix is updated
9412 * to get the Prefix if any.
9413 */
9414
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009415static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009416xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9417 xmlChar *ret = NULL;
9418
9419 *prefix = NULL;
9420 ret = xmlXPathParseNCName(ctxt);
9421 if (CUR == ':') {
9422 *prefix = ret;
9423 NEXT;
9424 ret = xmlXPathParseNCName(ctxt);
9425 }
9426 return(ret);
9427}
9428
9429/**
9430 * xmlXPathParseName:
9431 * @ctxt: the XPath Parser context
9432 *
9433 * parse an XML name
9434 *
9435 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9436 * CombiningChar | Extender
9437 *
9438 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9439 *
9440 * Returns the namespace name or NULL
9441 */
9442
9443xmlChar *
9444xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009445 const xmlChar *in;
9446 xmlChar *ret;
9447 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009448
Daniel Veillarda82b1822004-11-08 16:24:57 +00009449 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009450 /*
9451 * Accelerator for simple ASCII names
9452 */
9453 in = ctxt->cur;
9454 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9455 ((*in >= 0x41) && (*in <= 0x5A)) ||
9456 (*in == '_') || (*in == ':')) {
9457 in++;
9458 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9459 ((*in >= 0x41) && (*in <= 0x5A)) ||
9460 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009461 (*in == '_') || (*in == '-') ||
9462 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009463 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009464 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009465 count = in - ctxt->cur;
9466 ret = xmlStrndup(ctxt->cur, count);
9467 ctxt->cur = in;
9468 return(ret);
9469 }
9470 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009471 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009472}
9473
Daniel Veillard61d80a22001-04-27 17:13:01 +00009474static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009475xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009476 xmlChar buf[XML_MAX_NAMELEN + 5];
9477 int len = 0, l;
9478 int c;
9479
9480 /*
9481 * Handler for more complex cases
9482 */
9483 c = CUR_CHAR(l);
9484 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009485 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9486 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009487 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009488 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009489 return(NULL);
9490 }
9491
9492 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9493 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9494 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009495 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009496 (IS_COMBINING(c)) ||
9497 (IS_EXTENDER(c)))) {
9498 COPY_BUF(l,buf,len,c);
9499 NEXTL(l);
9500 c = CUR_CHAR(l);
9501 if (len >= XML_MAX_NAMELEN) {
9502 /*
9503 * Okay someone managed to make a huge name, so he's ready to pay
9504 * for the processing speed.
9505 */
9506 xmlChar *buffer;
9507 int max = len * 2;
9508
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009509 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009510 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009511 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009512 }
9513 memcpy(buffer, buf, len);
9514 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9515 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009516 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009517 (IS_COMBINING(c)) ||
9518 (IS_EXTENDER(c))) {
9519 if (len + 10 > max) {
9520 max *= 2;
9521 buffer = (xmlChar *) xmlRealloc(buffer,
9522 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009523 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009524 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009525 }
9526 }
9527 COPY_BUF(l,buffer,len,c);
9528 NEXTL(l);
9529 c = CUR_CHAR(l);
9530 }
9531 buffer[len] = 0;
9532 return(buffer);
9533 }
9534 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009535 if (len == 0)
9536 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009537 return(xmlStrndup(buf, len));
9538}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009539
9540#define MAX_FRAC 20
9541
William M. Brack372a4452004-02-17 13:09:23 +00009542/*
9543 * These are used as divisors for the fractional part of a number.
9544 * Since the table includes 1.0 (representing '0' fractional digits),
9545 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9546 */
9547static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009548 1.0, 10.0, 100.0, 1000.0, 10000.0,
9549 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9550 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9551 100000000000000.0,
9552 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009553 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009554};
9555
Owen Taylor3473f882001-02-23 17:55:21 +00009556/**
9557 * xmlXPathStringEvalNumber:
9558 * @str: A string to scan
9559 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009560 * [30a] Float ::= Number ('e' Digits?)?
9561 *
Owen Taylor3473f882001-02-23 17:55:21 +00009562 * [30] Number ::= Digits ('.' Digits?)?
9563 * | '.' Digits
9564 * [31] Digits ::= [0-9]+
9565 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009566 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009567 * In complement of the Number expression, this function also handles
9568 * negative values : '-' Number.
9569 *
9570 * Returns the double value.
9571 */
9572double
9573xmlXPathStringEvalNumber(const xmlChar *str) {
9574 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009575 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009576 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009577 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009578 int exponent = 0;
9579 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009580#ifdef __GNUC__
9581 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009582 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009583#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009584 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009585 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009586 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9587 return(xmlXPathNAN);
9588 }
9589 if (*cur == '-') {
9590 isneg = 1;
9591 cur++;
9592 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009593
9594#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009595 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009596 * tmp/temp is a workaround against a gcc compiler bug
9597 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009598 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009599 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009600 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009601 ret = ret * 10;
9602 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009603 ok = 1;
9604 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009605 temp = (double) tmp;
9606 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009607 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009608#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009609 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009610 while ((*cur >= '0') && (*cur <= '9')) {
9611 ret = ret * 10 + (*cur - '0');
9612 ok = 1;
9613 cur++;
9614 }
9615#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009616
Owen Taylor3473f882001-02-23 17:55:21 +00009617 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009618 int v, frac = 0;
9619 double fraction = 0;
9620
Owen Taylor3473f882001-02-23 17:55:21 +00009621 cur++;
9622 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9623 return(xmlXPathNAN);
9624 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009625 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9626 v = (*cur - '0');
9627 fraction = fraction * 10 + v;
9628 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009629 cur++;
9630 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009631 fraction /= my_pow10[frac];
9632 ret = ret + fraction;
9633 while ((*cur >= '0') && (*cur <= '9'))
9634 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009635 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009636 if ((*cur == 'e') || (*cur == 'E')) {
9637 cur++;
9638 if (*cur == '-') {
9639 is_exponent_negative = 1;
9640 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009641 } else if (*cur == '+') {
9642 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009643 }
9644 while ((*cur >= '0') && (*cur <= '9')) {
9645 exponent = exponent * 10 + (*cur - '0');
9646 cur++;
9647 }
9648 }
William M. Brack76e95df2003-10-18 16:20:14 +00009649 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009650 if (*cur != 0) return(xmlXPathNAN);
9651 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009652 if (is_exponent_negative) exponent = -exponent;
9653 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009654 return(ret);
9655}
9656
9657/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009658 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009659 * @ctxt: the XPath Parser context
9660 *
9661 * [30] Number ::= Digits ('.' Digits?)?
9662 * | '.' Digits
9663 * [31] Digits ::= [0-9]+
9664 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009665 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009666 *
9667 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009668static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009669xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9670{
Owen Taylor3473f882001-02-23 17:55:21 +00009671 double ret = 0.0;
9672 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009673 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009674 int exponent = 0;
9675 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009676#ifdef __GNUC__
9677 unsigned long tmp = 0;
9678 double temp;
9679#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009680
9681 CHECK_ERROR;
9682 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9683 XP_ERROR(XPATH_NUMBER_ERROR);
9684 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009685#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009686 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009687 * tmp/temp is a workaround against a gcc compiler bug
9688 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009689 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009690 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009691 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009692 ret = ret * 10;
9693 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009694 ok = 1;
9695 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00009696 temp = (double) tmp;
9697 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009698 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009699#else
9700 ret = 0;
9701 while ((CUR >= '0') && (CUR <= '9')) {
9702 ret = ret * 10 + (CUR - '0');
9703 ok = 1;
9704 NEXT;
9705 }
9706#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009707 if (CUR == '.') {
9708 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009709 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9710 XP_ERROR(XPATH_NUMBER_ERROR);
9711 }
9712 while ((CUR >= '0') && (CUR <= '9')) {
9713 mult /= 10;
9714 ret = ret + (CUR - '0') * mult;
9715 NEXT;
9716 }
Owen Taylor3473f882001-02-23 17:55:21 +00009717 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009718 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009719 NEXT;
9720 if (CUR == '-') {
9721 is_exponent_negative = 1;
9722 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00009723 } else if (CUR == '+') {
9724 NEXT;
9725 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009726 while ((CUR >= '0') && (CUR <= '9')) {
9727 exponent = exponent * 10 + (CUR - '0');
9728 NEXT;
9729 }
9730 if (is_exponent_negative)
9731 exponent = -exponent;
9732 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00009733 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009734 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009735 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009736}
9737
9738/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009739 * xmlXPathParseLiteral:
9740 * @ctxt: the XPath Parser context
9741 *
9742 * Parse a Literal
9743 *
9744 * [29] Literal ::= '"' [^"]* '"'
9745 * | "'" [^']* "'"
9746 *
9747 * Returns the value found or NULL in case of error
9748 */
9749static xmlChar *
9750xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9751 const xmlChar *q;
9752 xmlChar *ret = NULL;
9753
9754 if (CUR == '"') {
9755 NEXT;
9756 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009757 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009758 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009759 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009760 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009761 } else {
9762 ret = xmlStrndup(q, CUR_PTR - q);
9763 NEXT;
9764 }
9765 } else if (CUR == '\'') {
9766 NEXT;
9767 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009768 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009769 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009770 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009771 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009772 } else {
9773 ret = xmlStrndup(q, CUR_PTR - q);
9774 NEXT;
9775 }
9776 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00009777 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009778 }
9779 return(ret);
9780}
9781
9782/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009783 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00009784 * @ctxt: the XPath Parser context
9785 *
9786 * Parse a Literal and push it on the stack.
9787 *
9788 * [29] Literal ::= '"' [^"]* '"'
9789 * | "'" [^']* "'"
9790 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009791 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00009792 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009793static void
9794xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009795 const xmlChar *q;
9796 xmlChar *ret = NULL;
9797
9798 if (CUR == '"') {
9799 NEXT;
9800 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009801 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00009802 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009803 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009804 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9805 } else {
9806 ret = xmlStrndup(q, CUR_PTR - q);
9807 NEXT;
9808 }
9809 } else if (CUR == '\'') {
9810 NEXT;
9811 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009812 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00009813 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009814 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009815 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9816 } else {
9817 ret = xmlStrndup(q, CUR_PTR - q);
9818 NEXT;
9819 }
9820 } else {
9821 XP_ERROR(XPATH_START_LITERAL_ERROR);
9822 }
9823 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009824 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009825 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009826 xmlFree(ret);
9827}
9828
9829/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009830 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00009831 * @ctxt: the XPath Parser context
9832 *
9833 * Parse a VariableReference, evaluate it and push it on the stack.
9834 *
9835 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00009836 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00009837 * of any of the types that are possible for the value of an expression,
9838 * and may also be of additional types not specified here.
9839 *
9840 * Early evaluation is possible since:
9841 * The variable bindings [...] used to evaluate a subexpression are
9842 * always the same as those used to evaluate the containing expression.
9843 *
9844 * [36] VariableReference ::= '$' QName
9845 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009846static void
9847xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009848 xmlChar *name;
9849 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009850
9851 SKIP_BLANKS;
9852 if (CUR != '$') {
9853 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9854 }
9855 NEXT;
9856 name = xmlXPathParseQName(ctxt, &prefix);
9857 if (name == NULL) {
9858 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9859 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009860 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009861 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
9862 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00009863 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00009864 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9865 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
9866 }
Owen Taylor3473f882001-02-23 17:55:21 +00009867}
9868
9869/**
9870 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00009871 * @name: a name string
9872 *
9873 * Is the name given a NodeType one.
9874 *
9875 * [38] NodeType ::= 'comment'
9876 * | 'text'
9877 * | 'processing-instruction'
9878 * | 'node'
9879 *
9880 * Returns 1 if true 0 otherwise
9881 */
9882int
9883xmlXPathIsNodeType(const xmlChar *name) {
9884 if (name == NULL)
9885 return(0);
9886
Daniel Veillard1971ee22002-01-31 20:29:19 +00009887 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00009888 return(1);
9889 if (xmlStrEqual(name, BAD_CAST "text"))
9890 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009891 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00009892 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009893 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00009894 return(1);
9895 return(0);
9896}
9897
9898/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009899 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00009900 * @ctxt: the XPath Parser context
9901 *
9902 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9903 * [17] Argument ::= Expr
9904 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009905 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00009906 * pushed on the stack
9907 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009908static void
9909xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009910 xmlChar *name;
9911 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009912 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009913 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009914
9915 name = xmlXPathParseQName(ctxt, &prefix);
9916 if (name == NULL) {
9917 XP_ERROR(XPATH_EXPR_ERROR);
9918 }
9919 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009920#ifdef DEBUG_EXPR
9921 if (prefix == NULL)
9922 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
9923 name);
9924 else
9925 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
9926 prefix, name);
9927#endif
9928
Owen Taylor3473f882001-02-23 17:55:21 +00009929 if (CUR != '(') {
9930 XP_ERROR(XPATH_EXPR_ERROR);
9931 }
9932 NEXT;
9933 SKIP_BLANKS;
9934
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009935 /*
9936 * Optimization for count(): we don't need the node-set to be sorted.
9937 */
9938 if ((prefix == NULL) && (name[0] == 'c') &&
9939 xmlStrEqual(name, BAD_CAST "count"))
9940 {
9941 sort = 0;
9942 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009943 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00009944 if (CUR != ')') {
9945 while (CUR != 0) {
9946 int op1 = ctxt->comp->last;
9947 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009948 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +00009949 CHECK_ERROR;
9950 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9951 nbargs++;
9952 if (CUR == ')') break;
9953 if (CUR != ',') {
9954 XP_ERROR(XPATH_EXPR_ERROR);
9955 }
9956 NEXT;
9957 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009958 }
Owen Taylor3473f882001-02-23 17:55:21 +00009959 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009960 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
9961 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00009962 NEXT;
9963 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009964}
9965
9966/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009967 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00009968 * @ctxt: the XPath Parser context
9969 *
9970 * [15] PrimaryExpr ::= VariableReference
9971 * | '(' Expr ')'
9972 * | Literal
9973 * | Number
9974 * | FunctionCall
9975 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009976 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00009977 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009978static void
9979xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009980 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009981 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009982 else if (CUR == '(') {
9983 NEXT;
9984 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009985 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00009986 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00009987 if (CUR != ')') {
9988 XP_ERROR(XPATH_EXPR_ERROR);
9989 }
9990 NEXT;
9991 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00009992 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009993 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009994 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009995 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009996 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009997 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009998 }
9999 SKIP_BLANKS;
10000}
10001
10002/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010003 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010004 * @ctxt: the XPath Parser context
10005 *
10006 * [20] FilterExpr ::= PrimaryExpr
10007 * | FilterExpr Predicate
10008 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010009 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010010 * Square brackets are used to filter expressions in the same way that
10011 * they are used in location paths. It is an error if the expression to
10012 * be filtered does not evaluate to a node-set. The context node list
10013 * used for evaluating the expression in square brackets is the node-set
10014 * to be filtered listed in document order.
10015 */
10016
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010017static void
10018xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10019 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010020 CHECK_ERROR;
10021 SKIP_BLANKS;
10022
10023 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010024 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010025 SKIP_BLANKS;
10026 }
10027
10028
10029}
10030
10031/**
10032 * xmlXPathScanName:
10033 * @ctxt: the XPath Parser context
10034 *
10035 * Trickery: parse an XML name but without consuming the input flow
10036 * Needed to avoid insanity in the parser state.
10037 *
10038 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10039 * CombiningChar | Extender
10040 *
10041 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10042 *
10043 * [6] Names ::= Name (S Name)*
10044 *
10045 * Returns the Name parsed or NULL
10046 */
10047
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010048static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010049xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010050 int len = 0, l;
10051 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010052 const xmlChar *cur;
10053 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010054
Daniel Veillard03226812004-11-01 14:55:21 +000010055 cur = ctxt->cur;
10056
10057 c = CUR_CHAR(l);
10058 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10059 (!IS_LETTER(c) && (c != '_') &&
10060 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010061 return(NULL);
10062 }
10063
Daniel Veillard03226812004-11-01 14:55:21 +000010064 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10065 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10066 (c == '.') || (c == '-') ||
10067 (c == '_') || (c == ':') ||
10068 (IS_COMBINING(c)) ||
10069 (IS_EXTENDER(c)))) {
10070 len += l;
10071 NEXTL(l);
10072 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010073 }
Daniel Veillard03226812004-11-01 14:55:21 +000010074 ret = xmlStrndup(cur, ctxt->cur - cur);
10075 ctxt->cur = cur;
10076 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010077}
10078
10079/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010080 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010081 * @ctxt: the XPath Parser context
10082 *
10083 * [19] PathExpr ::= LocationPath
10084 * | FilterExpr
10085 * | FilterExpr '/' RelativeLocationPath
10086 * | FilterExpr '//' RelativeLocationPath
10087 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010088 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010089 * The / operator and // operators combine an arbitrary expression
10090 * and a relative location path. It is an error if the expression
10091 * does not evaluate to a node-set.
10092 * The / operator does composition in the same way as when / is
10093 * used in a location path. As in location paths, // is short for
10094 * /descendant-or-self::node()/.
10095 */
10096
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010097static void
10098xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010099 int lc = 1; /* Should we branch to LocationPath ? */
10100 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10101
10102 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010103 if ((CUR == '$') || (CUR == '(') ||
10104 (IS_ASCII_DIGIT(CUR)) ||
10105 (CUR == '\'') || (CUR == '"') ||
10106 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010107 lc = 0;
10108 } else if (CUR == '*') {
10109 /* relative or absolute location path */
10110 lc = 1;
10111 } else if (CUR == '/') {
10112 /* relative or absolute location path */
10113 lc = 1;
10114 } else if (CUR == '@') {
10115 /* relative abbreviated attribute location path */
10116 lc = 1;
10117 } else if (CUR == '.') {
10118 /* relative abbreviated attribute location path */
10119 lc = 1;
10120 } else {
10121 /*
10122 * Problem is finding if we have a name here whether it's:
10123 * - a nodetype
10124 * - a function call in which case it's followed by '('
10125 * - an axis in which case it's followed by ':'
10126 * - a element name
10127 * We do an a priori analysis here rather than having to
10128 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010129 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010130 * read/write/debug.
10131 */
10132 SKIP_BLANKS;
10133 name = xmlXPathScanName(ctxt);
10134 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10135#ifdef DEBUG_STEP
10136 xmlGenericError(xmlGenericErrorContext,
10137 "PathExpr: Axis\n");
10138#endif
10139 lc = 1;
10140 xmlFree(name);
10141 } else if (name != NULL) {
10142 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010143
10144
10145 while (NXT(len) != 0) {
10146 if (NXT(len) == '/') {
10147 /* element name */
10148#ifdef DEBUG_STEP
10149 xmlGenericError(xmlGenericErrorContext,
10150 "PathExpr: AbbrRelLocation\n");
10151#endif
10152 lc = 1;
10153 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010154 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010155 /* ignore blanks */
10156 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010157 } else if (NXT(len) == ':') {
10158#ifdef DEBUG_STEP
10159 xmlGenericError(xmlGenericErrorContext,
10160 "PathExpr: AbbrRelLocation\n");
10161#endif
10162 lc = 1;
10163 break;
10164 } else if ((NXT(len) == '(')) {
10165 /* Note Type or Function */
10166 if (xmlXPathIsNodeType(name)) {
10167#ifdef DEBUG_STEP
10168 xmlGenericError(xmlGenericErrorContext,
10169 "PathExpr: Type search\n");
10170#endif
10171 lc = 1;
10172 } else {
10173#ifdef DEBUG_STEP
10174 xmlGenericError(xmlGenericErrorContext,
10175 "PathExpr: function call\n");
10176#endif
10177 lc = 0;
10178 }
10179 break;
10180 } else if ((NXT(len) == '[')) {
10181 /* element name */
10182#ifdef DEBUG_STEP
10183 xmlGenericError(xmlGenericErrorContext,
10184 "PathExpr: AbbrRelLocation\n");
10185#endif
10186 lc = 1;
10187 break;
10188 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10189 (NXT(len) == '=')) {
10190 lc = 1;
10191 break;
10192 } else {
10193 lc = 1;
10194 break;
10195 }
10196 len++;
10197 }
10198 if (NXT(len) == 0) {
10199#ifdef DEBUG_STEP
10200 xmlGenericError(xmlGenericErrorContext,
10201 "PathExpr: AbbrRelLocation\n");
10202#endif
10203 /* element name */
10204 lc = 1;
10205 }
10206 xmlFree(name);
10207 } else {
William M. Brack08171912003-12-29 02:52:11 +000010208 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010209 XP_ERROR(XPATH_EXPR_ERROR);
10210 }
10211 }
10212
10213 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010214 if (CUR == '/') {
10215 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10216 } else {
10217 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010218 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010219 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010220 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010221 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010222 CHECK_ERROR;
10223 if ((CUR == '/') && (NXT(1) == '/')) {
10224 SKIP(2);
10225 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010226
10227 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10228 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10229 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10230
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010231 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010232 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010233 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010234 }
10235 }
10236 SKIP_BLANKS;
10237}
10238
10239/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010240 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010241 * @ctxt: the XPath Parser context
10242 *
10243 * [18] UnionExpr ::= PathExpr
10244 * | UnionExpr '|' PathExpr
10245 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010246 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010247 */
10248
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010249static void
10250xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10251 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010252 CHECK_ERROR;
10253 SKIP_BLANKS;
10254 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010255 int op1 = ctxt->comp->last;
10256 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010257
10258 NEXT;
10259 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010260 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010261
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010262 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10263
Owen Taylor3473f882001-02-23 17:55:21 +000010264 SKIP_BLANKS;
10265 }
Owen Taylor3473f882001-02-23 17:55:21 +000010266}
10267
10268/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010269 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010270 * @ctxt: the XPath Parser context
10271 *
10272 * [27] UnaryExpr ::= UnionExpr
10273 * | '-' UnaryExpr
10274 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010275 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010276 */
10277
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010278static void
10279xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010280 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010281 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010282
10283 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010284 while (CUR == '-') {
10285 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010286 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010287 NEXT;
10288 SKIP_BLANKS;
10289 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010290
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010291 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010292 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010293 if (found) {
10294 if (minus)
10295 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10296 else
10297 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010298 }
10299}
10300
10301/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010302 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010303 * @ctxt: the XPath Parser context
10304 *
10305 * [26] MultiplicativeExpr ::= UnaryExpr
10306 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10307 * | MultiplicativeExpr 'div' UnaryExpr
10308 * | MultiplicativeExpr 'mod' UnaryExpr
10309 * [34] MultiplyOperator ::= '*'
10310 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010311 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010312 */
10313
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010314static void
10315xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10316 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010317 CHECK_ERROR;
10318 SKIP_BLANKS;
10319 while ((CUR == '*') ||
10320 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10321 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10322 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010323 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010324
10325 if (CUR == '*') {
10326 op = 0;
10327 NEXT;
10328 } else if (CUR == 'd') {
10329 op = 1;
10330 SKIP(3);
10331 } else if (CUR == 'm') {
10332 op = 2;
10333 SKIP(3);
10334 }
10335 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010336 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010337 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010338 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010339 SKIP_BLANKS;
10340 }
10341}
10342
10343/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010344 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010345 * @ctxt: the XPath Parser context
10346 *
10347 * [25] AdditiveExpr ::= MultiplicativeExpr
10348 * | AdditiveExpr '+' MultiplicativeExpr
10349 * | AdditiveExpr '-' MultiplicativeExpr
10350 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010351 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010352 */
10353
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010354static void
10355xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010356
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010357 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010358 CHECK_ERROR;
10359 SKIP_BLANKS;
10360 while ((CUR == '+') || (CUR == '-')) {
10361 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010362 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010363
10364 if (CUR == '+') plus = 1;
10365 else plus = 0;
10366 NEXT;
10367 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010368 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010369 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010370 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010371 SKIP_BLANKS;
10372 }
10373}
10374
10375/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010376 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010377 * @ctxt: the XPath Parser context
10378 *
10379 * [24] RelationalExpr ::= AdditiveExpr
10380 * | RelationalExpr '<' AdditiveExpr
10381 * | RelationalExpr '>' AdditiveExpr
10382 * | RelationalExpr '<=' AdditiveExpr
10383 * | RelationalExpr '>=' AdditiveExpr
10384 *
10385 * A <= B > C is allowed ? Answer from James, yes with
10386 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10387 * which is basically what got implemented.
10388 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010389 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010390 * on the stack
10391 */
10392
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010393static void
10394xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10395 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010396 CHECK_ERROR;
10397 SKIP_BLANKS;
10398 while ((CUR == '<') ||
10399 (CUR == '>') ||
10400 ((CUR == '<') && (NXT(1) == '=')) ||
10401 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010402 int inf, strict;
10403 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010404
10405 if (CUR == '<') inf = 1;
10406 else inf = 0;
10407 if (NXT(1) == '=') strict = 0;
10408 else strict = 1;
10409 NEXT;
10410 if (!strict) NEXT;
10411 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010412 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010413 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010414 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010415 SKIP_BLANKS;
10416 }
10417}
10418
10419/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010420 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010421 * @ctxt: the XPath Parser context
10422 *
10423 * [23] EqualityExpr ::= RelationalExpr
10424 * | EqualityExpr '=' RelationalExpr
10425 * | EqualityExpr '!=' RelationalExpr
10426 *
10427 * A != B != C is allowed ? Answer from James, yes with
10428 * (RelationalExpr = RelationalExpr) = RelationalExpr
10429 * (RelationalExpr != RelationalExpr) != RelationalExpr
10430 * which is basically what got implemented.
10431 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010432 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010433 *
10434 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010435static void
10436xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10437 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010438 CHECK_ERROR;
10439 SKIP_BLANKS;
10440 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010441 int eq;
10442 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010443
10444 if (CUR == '=') eq = 1;
10445 else eq = 0;
10446 NEXT;
10447 if (!eq) NEXT;
10448 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010449 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010450 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010451 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010452 SKIP_BLANKS;
10453 }
10454}
10455
10456/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010457 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010458 * @ctxt: the XPath Parser context
10459 *
10460 * [22] AndExpr ::= EqualityExpr
10461 * | AndExpr 'and' EqualityExpr
10462 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010463 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010464 *
10465 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010466static void
10467xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10468 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010469 CHECK_ERROR;
10470 SKIP_BLANKS;
10471 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010472 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010473 SKIP(3);
10474 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010475 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010476 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010477 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010478 SKIP_BLANKS;
10479 }
10480}
10481
10482/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010483 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010484 * @ctxt: the XPath Parser context
10485 *
10486 * [14] Expr ::= OrExpr
10487 * [21] OrExpr ::= AndExpr
10488 * | OrExpr 'or' AndExpr
10489 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010490 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010491 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010492static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010493xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010494 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010495 CHECK_ERROR;
10496 SKIP_BLANKS;
10497 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010498 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010499 SKIP(2);
10500 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010501 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010502 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010503 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10504 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010505 SKIP_BLANKS;
10506 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010507 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010508 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010509 /*
10510 * This is the main place to eliminate sorting for
10511 * operations which don't require a sorted node-set.
10512 * E.g. count().
10513 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010514 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10515 }
Owen Taylor3473f882001-02-23 17:55:21 +000010516}
10517
10518/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010519 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010520 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010521 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010522 *
10523 * [8] Predicate ::= '[' PredicateExpr ']'
10524 * [9] PredicateExpr ::= Expr
10525 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010526 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010527 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010528static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010529xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010530 int op1 = ctxt->comp->last;
10531
10532 SKIP_BLANKS;
10533 if (CUR != '[') {
10534 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10535 }
10536 NEXT;
10537 SKIP_BLANKS;
10538
10539 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010540 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010541 CHECK_ERROR;
10542
10543 if (CUR != ']') {
10544 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10545 }
10546
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010547 if (filter)
10548 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10549 else
10550 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010551
10552 NEXT;
10553 SKIP_BLANKS;
10554}
10555
10556/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010557 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010558 * @ctxt: the XPath Parser context
10559 * @test: pointer to a xmlXPathTestVal
10560 * @type: pointer to a xmlXPathTypeVal
10561 * @prefix: placeholder for a possible name prefix
10562 *
10563 * [7] NodeTest ::= NameTest
10564 * | NodeType '(' ')'
10565 * | 'processing-instruction' '(' Literal ')'
10566 *
10567 * [37] NameTest ::= '*'
10568 * | NCName ':' '*'
10569 * | QName
10570 * [38] NodeType ::= 'comment'
10571 * | 'text'
10572 * | 'processing-instruction'
10573 * | 'node'
10574 *
William M. Brack08171912003-12-29 02:52:11 +000010575 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010576 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010577static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010578xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10579 xmlXPathTypeVal *type, const xmlChar **prefix,
10580 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010581 int blanks;
10582
10583 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10584 STRANGE;
10585 return(NULL);
10586 }
William M. Brack78637da2003-07-31 14:47:38 +000010587 *type = (xmlXPathTypeVal) 0;
10588 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010589 *prefix = NULL;
10590 SKIP_BLANKS;
10591
10592 if ((name == NULL) && (CUR == '*')) {
10593 /*
10594 * All elements
10595 */
10596 NEXT;
10597 *test = NODE_TEST_ALL;
10598 return(NULL);
10599 }
10600
10601 if (name == NULL)
10602 name = xmlXPathParseNCName(ctxt);
10603 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010604 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010605 }
10606
William M. Brack76e95df2003-10-18 16:20:14 +000010607 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010608 SKIP_BLANKS;
10609 if (CUR == '(') {
10610 NEXT;
10611 /*
10612 * NodeType or PI search
10613 */
10614 if (xmlStrEqual(name, BAD_CAST "comment"))
10615 *type = NODE_TYPE_COMMENT;
10616 else if (xmlStrEqual(name, BAD_CAST "node"))
10617 *type = NODE_TYPE_NODE;
10618 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10619 *type = NODE_TYPE_PI;
10620 else if (xmlStrEqual(name, BAD_CAST "text"))
10621 *type = NODE_TYPE_TEXT;
10622 else {
10623 if (name != NULL)
10624 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010625 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010626 }
10627
10628 *test = NODE_TEST_TYPE;
10629
10630 SKIP_BLANKS;
10631 if (*type == NODE_TYPE_PI) {
10632 /*
10633 * Specific case: search a PI by name.
10634 */
Owen Taylor3473f882001-02-23 17:55:21 +000010635 if (name != NULL)
10636 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010637 name = NULL;
10638 if (CUR != ')') {
10639 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010640 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010641 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010642 SKIP_BLANKS;
10643 }
Owen Taylor3473f882001-02-23 17:55:21 +000010644 }
10645 if (CUR != ')') {
10646 if (name != NULL)
10647 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010648 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010649 }
10650 NEXT;
10651 return(name);
10652 }
10653 *test = NODE_TEST_NAME;
10654 if ((!blanks) && (CUR == ':')) {
10655 NEXT;
10656
10657 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010658 * Since currently the parser context don't have a
10659 * namespace list associated:
10660 * The namespace name for this prefix can be computed
10661 * only at evaluation time. The compilation is done
10662 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010663 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010664#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010665 *prefix = xmlXPathNsLookup(ctxt->context, name);
10666 if (name != NULL)
10667 xmlFree(name);
10668 if (*prefix == NULL) {
10669 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10670 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010671#else
10672 *prefix = name;
10673#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010674
10675 if (CUR == '*') {
10676 /*
10677 * All elements
10678 */
10679 NEXT;
10680 *test = NODE_TEST_ALL;
10681 return(NULL);
10682 }
10683
10684 name = xmlXPathParseNCName(ctxt);
10685 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010686 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010687 }
10688 }
10689 return(name);
10690}
10691
10692/**
10693 * xmlXPathIsAxisName:
10694 * @name: a preparsed name token
10695 *
10696 * [6] AxisName ::= 'ancestor'
10697 * | 'ancestor-or-self'
10698 * | 'attribute'
10699 * | 'child'
10700 * | 'descendant'
10701 * | 'descendant-or-self'
10702 * | 'following'
10703 * | 'following-sibling'
10704 * | 'namespace'
10705 * | 'parent'
10706 * | 'preceding'
10707 * | 'preceding-sibling'
10708 * | 'self'
10709 *
10710 * Returns the axis or 0
10711 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010712static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000010713xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000010714 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010715 switch (name[0]) {
10716 case 'a':
10717 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10718 ret = AXIS_ANCESTOR;
10719 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10720 ret = AXIS_ANCESTOR_OR_SELF;
10721 if (xmlStrEqual(name, BAD_CAST "attribute"))
10722 ret = AXIS_ATTRIBUTE;
10723 break;
10724 case 'c':
10725 if (xmlStrEqual(name, BAD_CAST "child"))
10726 ret = AXIS_CHILD;
10727 break;
10728 case 'd':
10729 if (xmlStrEqual(name, BAD_CAST "descendant"))
10730 ret = AXIS_DESCENDANT;
10731 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10732 ret = AXIS_DESCENDANT_OR_SELF;
10733 break;
10734 case 'f':
10735 if (xmlStrEqual(name, BAD_CAST "following"))
10736 ret = AXIS_FOLLOWING;
10737 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10738 ret = AXIS_FOLLOWING_SIBLING;
10739 break;
10740 case 'n':
10741 if (xmlStrEqual(name, BAD_CAST "namespace"))
10742 ret = AXIS_NAMESPACE;
10743 break;
10744 case 'p':
10745 if (xmlStrEqual(name, BAD_CAST "parent"))
10746 ret = AXIS_PARENT;
10747 if (xmlStrEqual(name, BAD_CAST "preceding"))
10748 ret = AXIS_PRECEDING;
10749 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10750 ret = AXIS_PRECEDING_SIBLING;
10751 break;
10752 case 's':
10753 if (xmlStrEqual(name, BAD_CAST "self"))
10754 ret = AXIS_SELF;
10755 break;
10756 }
10757 return(ret);
10758}
10759
10760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010761 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000010762 * @ctxt: the XPath Parser context
10763 *
10764 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10765 * | AbbreviatedStep
10766 *
10767 * [12] AbbreviatedStep ::= '.' | '..'
10768 *
10769 * [5] AxisSpecifier ::= AxisName '::'
10770 * | AbbreviatedAxisSpecifier
10771 *
10772 * [13] AbbreviatedAxisSpecifier ::= '@'?
10773 *
10774 * Modified for XPtr range support as:
10775 *
10776 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10777 * | AbbreviatedStep
10778 * | 'range-to' '(' Expr ')' Predicate*
10779 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010780 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000010781 * A location step of . is short for self::node(). This is
10782 * particularly useful in conjunction with //. For example, the
10783 * location path .//para is short for
10784 * self::node()/descendant-or-self::node()/child::para
10785 * and so will select all para descendant elements of the context
10786 * node.
10787 * Similarly, a location step of .. is short for parent::node().
10788 * For example, ../title is short for parent::node()/child::title
10789 * and so will select the title children of the parent of the context
10790 * node.
10791 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010792static void
10793xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010794#ifdef LIBXML_XPTR_ENABLED
10795 int rangeto = 0;
10796 int op2 = -1;
10797#endif
10798
Owen Taylor3473f882001-02-23 17:55:21 +000010799 SKIP_BLANKS;
10800 if ((CUR == '.') && (NXT(1) == '.')) {
10801 SKIP(2);
10802 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10804 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010805 } else if (CUR == '.') {
10806 NEXT;
10807 SKIP_BLANKS;
10808 } else {
10809 xmlChar *name = NULL;
10810 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010811 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000010812 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010813 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010814 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000010815
10816 /*
10817 * The modification needed for XPointer change to the production
10818 */
10819#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010820 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000010821 name = xmlXPathParseNCName(ctxt);
10822 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010823 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010824 xmlFree(name);
10825 SKIP_BLANKS;
10826 if (CUR != '(') {
10827 XP_ERROR(XPATH_EXPR_ERROR);
10828 }
10829 NEXT;
10830 SKIP_BLANKS;
10831
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010832 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010833 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000010834 CHECK_ERROR;
10835
10836 SKIP_BLANKS;
10837 if (CUR != ')') {
10838 XP_ERROR(XPATH_EXPR_ERROR);
10839 }
10840 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010841 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010842 goto eval_predicates;
10843 }
10844 }
10845#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000010846 if (CUR == '*') {
10847 axis = AXIS_CHILD;
10848 } else {
10849 if (name == NULL)
10850 name = xmlXPathParseNCName(ctxt);
10851 if (name != NULL) {
10852 axis = xmlXPathIsAxisName(name);
10853 if (axis != 0) {
10854 SKIP_BLANKS;
10855 if ((CUR == ':') && (NXT(1) == ':')) {
10856 SKIP(2);
10857 xmlFree(name);
10858 name = NULL;
10859 } else {
10860 /* an element name can conflict with an axis one :-\ */
10861 axis = AXIS_CHILD;
10862 }
Owen Taylor3473f882001-02-23 17:55:21 +000010863 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000010864 axis = AXIS_CHILD;
10865 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010866 } else if (CUR == '@') {
10867 NEXT;
10868 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000010869 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000010870 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000010871 }
Owen Taylor3473f882001-02-23 17:55:21 +000010872 }
10873
10874 CHECK_ERROR;
10875
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010876 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000010877 if (test == 0)
10878 return;
10879
Daniel Veillarded6c5492005-07-23 15:00:22 +000010880 if ((prefix != NULL) && (ctxt->context != NULL) &&
10881 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10882 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10883 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10884 }
10885 }
Owen Taylor3473f882001-02-23 17:55:21 +000010886#ifdef DEBUG_STEP
10887 xmlGenericError(xmlGenericErrorContext,
10888 "Basis : computing new set\n");
10889#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010890
Owen Taylor3473f882001-02-23 17:55:21 +000010891#ifdef DEBUG_STEP
10892 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010893 if (ctxt->value == NULL)
10894 xmlGenericError(xmlGenericErrorContext, "no value\n");
10895 else if (ctxt->value->nodesetval == NULL)
10896 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10897 else
10898 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010899#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010900
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010901#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000010902eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010903#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010904 op1 = ctxt->comp->last;
10905 ctxt->comp->last = -1;
10906
Owen Taylor3473f882001-02-23 17:55:21 +000010907 SKIP_BLANKS;
10908 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010909 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010910 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010911
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010912#ifdef LIBXML_XPTR_ENABLED
10913 if (rangeto) {
10914 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10915 } else
10916#endif
10917 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10918 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010919
Owen Taylor3473f882001-02-23 17:55:21 +000010920 }
10921#ifdef DEBUG_STEP
10922 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010923 if (ctxt->value == NULL)
10924 xmlGenericError(xmlGenericErrorContext, "no value\n");
10925 else if (ctxt->value->nodesetval == NULL)
10926 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10927 else
10928 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
10929 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010930#endif
10931}
10932
10933/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010934 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000010935 * @ctxt: the XPath Parser context
10936 *
10937 * [3] RelativeLocationPath ::= Step
10938 * | RelativeLocationPath '/' Step
10939 * | AbbreviatedRelativeLocationPath
10940 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10941 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010942 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000010943 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010944static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010945xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000010946(xmlXPathParserContextPtr ctxt) {
10947 SKIP_BLANKS;
10948 if ((CUR == '/') && (NXT(1) == '/')) {
10949 SKIP(2);
10950 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010951 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10952 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010953 } else if (CUR == '/') {
10954 NEXT;
10955 SKIP_BLANKS;
10956 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010957 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010958 SKIP_BLANKS;
10959 while (CUR == '/') {
10960 if ((CUR == '/') && (NXT(1) == '/')) {
10961 SKIP(2);
10962 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010963 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000010964 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010965 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010966 } else if (CUR == '/') {
10967 NEXT;
10968 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010969 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010970 }
10971 SKIP_BLANKS;
10972 }
10973}
10974
10975/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010976 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000010977 * @ctxt: the XPath Parser context
10978 *
10979 * [1] LocationPath ::= RelativeLocationPath
10980 * | AbsoluteLocationPath
10981 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10982 * | AbbreviatedAbsoluteLocationPath
10983 * [10] AbbreviatedAbsoluteLocationPath ::=
10984 * '//' RelativeLocationPath
10985 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010986 * Compile a location path
10987 *
Owen Taylor3473f882001-02-23 17:55:21 +000010988 * // is short for /descendant-or-self::node()/. For example,
10989 * //para is short for /descendant-or-self::node()/child::para and
10990 * so will select any para element in the document (even a para element
10991 * that is a document element will be selected by //para since the
10992 * document element node is a child of the root node); div//para is
10993 * short for div/descendant-or-self::node()/child::para and so will
10994 * select all para descendants of div children.
10995 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010996static void
10997xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010998 SKIP_BLANKS;
10999 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011000 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011001 } else {
11002 while (CUR == '/') {
11003 if ((CUR == '/') && (NXT(1) == '/')) {
11004 SKIP(2);
11005 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011006 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11007 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011008 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011009 } else if (CUR == '/') {
11010 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011011 SKIP_BLANKS;
11012 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011013 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011014 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011015 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011016 }
11017 }
11018 }
11019}
11020
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011021/************************************************************************
11022 * *
11023 * XPath precompiled expression evaluation *
11024 * *
11025 ************************************************************************/
11026
Daniel Veillardf06307e2001-07-03 10:35:50 +000011027static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011028xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11029
11030/**
11031 * xmlXPathNodeCollectAndTest:
11032 * @ctxt: the XPath Parser context
11033 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +000011034 * @first: pointer to the first element in document order
11035 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011036 *
11037 * This is the function implementing a step: based on the current list
11038 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000011039 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011040 *
11041 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +000011042 *
William M. Brack08171912003-12-29 02:52:11 +000011043 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011044 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011045static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011046xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011047 /* xmlXPathStepOpPtr prevop, */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011048 xmlXPathStepOpPtr op,
11049 xmlNodePtr * first, xmlNodePtr * last)
11050{
William M. Brack78637da2003-07-31 14:47:38 +000011051 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11052 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11053 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011054 const xmlChar *prefix = op->value4;
11055 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +000011056 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011057
11058#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011059 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011060#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011061 int i, t = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011062 xmlNodeSetPtr ret, list = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011063 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011064 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +000011065 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011066 xmlNodePtr cur = NULL;
11067 xmlXPathObjectPtr obj;
11068 xmlNodeSetPtr nodelist;
11069 xmlNodePtr tmp;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011070 int specialNodeInSet = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011071
Daniel Veillardf06307e2001-07-03 10:35:50 +000011072 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011073 obj = valuePop(ctxt);
11074 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +000011075 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +000011076 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011077 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011078 if (URI == NULL) {
11079 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011080 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011081 }
Daniel Veillarde043ee12001-04-16 14:08:07 +000011082 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011083#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011084 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011085#endif
11086 switch (axis) {
11087 case AXIS_ANCESTOR:
11088#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011089 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011090#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011091 first = NULL;
11092 next = xmlXPathNextAncestor;
11093 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011094 case AXIS_ANCESTOR_OR_SELF:
11095#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011096 xmlGenericError(xmlGenericErrorContext,
11097 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011098#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011099 first = NULL;
11100 next = xmlXPathNextAncestorOrSelf;
11101 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011102 case AXIS_ATTRIBUTE:
11103#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011104 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011105#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011106 first = NULL;
11107 last = NULL;
11108 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +000011109 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011110 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011111 case AXIS_CHILD:
11112#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011113 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011114#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011115 last = NULL;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011116 if (test == NODE_TEST_NAME) {
11117 /*
11118 * Optimization if an element node type is 'element'.
11119 */
11120 next = xmlXPathNextChildElement;
11121 } else
11122 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +000011123 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011124 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011125 case AXIS_DESCENDANT:
11126#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011127 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011128#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011129 last = NULL;
11130 next = xmlXPathNextDescendant;
11131 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011132 case AXIS_DESCENDANT_OR_SELF:
11133#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011134 xmlGenericError(xmlGenericErrorContext,
11135 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011136#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011137 last = NULL;
11138 next = xmlXPathNextDescendantOrSelf;
11139 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011140 case AXIS_FOLLOWING:
11141#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011142 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011143#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011144 last = NULL;
11145 next = xmlXPathNextFollowing;
11146 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011147 case AXIS_FOLLOWING_SIBLING:
11148#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011149 xmlGenericError(xmlGenericErrorContext,
11150 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011151#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011152 last = NULL;
11153 next = xmlXPathNextFollowingSibling;
11154 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011155 case AXIS_NAMESPACE:
11156#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011157 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011158#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011159 first = NULL;
11160 last = NULL;
11161 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +000011162 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011163 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011164 case AXIS_PARENT:
11165#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011166 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011167#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011168 first = NULL;
11169 next = xmlXPathNextParent;
11170 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011171 case AXIS_PRECEDING:
11172#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011173 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011174#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011175 first = NULL;
11176 next = xmlXPathNextPrecedingInternal;
11177 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011178 case AXIS_PRECEDING_SIBLING:
11179#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011180 xmlGenericError(xmlGenericErrorContext,
11181 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011182#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011183 first = NULL;
11184 next = xmlXPathNextPrecedingSibling;
11185 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011186 case AXIS_SELF:
11187#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011188 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011189#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011190 first = NULL;
11191 last = NULL;
11192 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +000011193 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011194 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011195 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011196 if (next == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011197 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011198 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011199 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011200
11201 nodelist = obj->nodesetval;
11202 if (nodelist == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011203 xmlXPathReleaseObject(ctxt->context, obj);
11204 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011205 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011206 }
11207 addNode = xmlXPathNodeSetAddUnique;
11208 ret = NULL;
11209#ifdef DEBUG_STEP
11210 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011211 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011212 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011213 case NODE_TEST_NONE:
11214 xmlGenericError(xmlGenericErrorContext,
11215 " searching for none !!!\n");
11216 break;
11217 case NODE_TEST_TYPE:
11218 xmlGenericError(xmlGenericErrorContext,
11219 " searching for type %d\n", type);
11220 break;
11221 case NODE_TEST_PI:
11222 xmlGenericError(xmlGenericErrorContext,
11223 " searching for PI !!!\n");
11224 break;
11225 case NODE_TEST_ALL:
11226 xmlGenericError(xmlGenericErrorContext,
11227 " searching for *\n");
11228 break;
11229 case NODE_TEST_NS:
11230 xmlGenericError(xmlGenericErrorContext,
11231 " searching for namespace %s\n",
11232 prefix);
11233 break;
11234 case NODE_TEST_NAME:
11235 xmlGenericError(xmlGenericErrorContext,
11236 " searching for name %s\n", name);
11237 if (prefix != NULL)
11238 xmlGenericError(xmlGenericErrorContext,
11239 " with namespace %s\n", prefix);
11240 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011241 }
11242 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11243#endif
11244 /*
11245 * 2.3 Node Tests
11246 * - For the attribute axis, the principal node type is attribute.
11247 * - For the namespace axis, the principal node type is namespace.
11248 * - For other axes, the principal node type is element.
11249 *
11250 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011251 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011252 * select all element children of the context node
11253 */
11254 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011255 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011256 ctxt->context->node = nodelist->nodeTab[i];
11257
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011258 specialNodeInSet = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011259 cur = NULL;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011260 if (list == NULL) {
11261 list = xmlXPathNodeSetCreate(NULL);
11262 if (list == NULL) {
11263 t = 0;
11264 goto error;
11265 }
11266 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011267 do {
11268 cur = next(ctxt, cur);
11269 if (cur == NULL)
11270 break;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011271 if (first != NULL) {
11272 if (*first == cur)
11273 break;
11274 if ((*first != NULL) &&
11275 ((t % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011276#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011277 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011278#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011279 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011280#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011281 {
11282 break;
11283 }
11284 }
11285 if (last != NULL) {
11286 if (*last == cur)
11287 break;
11288 if ((*last != NULL) &&
11289 ((t % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011290#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011291 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011292#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011293 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011294#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011295 {
11296 break;
11297 }
11298 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011299 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011300#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011301 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
11302#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011303 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011304 case NODE_TEST_NONE:
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011305 ctxt->context->node = tmp;
11306 STRANGE
11307 goto error;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011308 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011309 if ((cur->type == type) ||
11310 ((type == NODE_TYPE_NODE) &&
11311 ((cur->type == XML_DOCUMENT_NODE) ||
11312 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11313 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000011314 (cur->type == XML_NAMESPACE_DECL) ||
11315 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +000011316 (cur->type == XML_PI_NODE) ||
11317 (cur->type == XML_COMMENT_NODE) ||
11318 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +000011319 (cur->type == XML_TEXT_NODE))) ||
11320 ((type == NODE_TYPE_TEXT) &&
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011321 (cur->type == XML_CDATA_SECTION_NODE)))
11322 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011323#ifdef DEBUG_STEP
11324 n++;
11325#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011326 if (cur->type == XML_NAMESPACE_DECL)
11327 specialNodeInSet = 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011328 addNode(list, cur);
11329 }
11330 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011331 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011332 if (cur->type == XML_PI_NODE) {
11333 if ((name != NULL) &&
11334 (!xmlStrEqual(name, cur->name)))
11335 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011336#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011337 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011338#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011339 addNode(list, cur);
11340 }
11341 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011342 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011343 if (axis == AXIS_ATTRIBUTE) {
11344 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011345#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011346 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011347#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011348 addNode(list, cur);
11349 }
11350 } else if (axis == AXIS_NAMESPACE) {
11351 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011352#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011353 n++;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011354#endif
11355 specialNodeInSet = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011356 xmlXPathNodeSetAddNs(list, ctxt->context->node,
11357 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011358 }
11359 } else {
11360 if (cur->type == XML_ELEMENT_NODE) {
11361 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011362#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011363 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011364#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011365 addNode(list, cur);
11366 } else if ((cur->ns != NULL) &&
11367 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011368#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011369 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011370#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011371 addNode(list, cur);
11372 }
11373 }
11374 }
11375 break;
11376 case NODE_TEST_NS:{
11377 TODO;
11378 break;
11379 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011380 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011381 switch (cur->type) {
11382 case XML_ELEMENT_NODE:
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011383 if (xmlStrEqual(name, cur->name)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011384 if (prefix == NULL) {
11385 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011386#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011387 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011388#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011389 addNode(list, cur);
11390 }
11391 } else {
11392 if ((cur->ns != NULL) &&
11393 (xmlStrEqual(URI,
11394 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011395#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011396 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011397#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 addNode(list, cur);
11399 }
11400 }
11401 }
11402 break;
11403 case XML_ATTRIBUTE_NODE:{
11404 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011405
Daniel Veillardf06307e2001-07-03 10:35:50 +000011406 if (xmlStrEqual(name, attr->name)) {
11407 if (prefix == NULL) {
11408 if ((attr->ns == NULL) ||
11409 (attr->ns->prefix == NULL)) {
11410#ifdef DEBUG_STEP
11411 n++;
11412#endif
11413 addNode(list,
11414 (xmlNodePtr) attr);
11415 }
11416 } else {
11417 if ((attr->ns != NULL) &&
11418 (xmlStrEqual(URI,
11419 attr->ns->
11420 href))) {
11421#ifdef DEBUG_STEP
11422 n++;
11423#endif
11424 addNode(list,
11425 (xmlNodePtr) attr);
11426 }
11427 }
11428 }
11429 break;
11430 }
11431 case XML_NAMESPACE_DECL:
11432 if (cur->type == XML_NAMESPACE_DECL) {
11433 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011434
Daniel Veillardf06307e2001-07-03 10:35:50 +000011435 if ((ns->prefix != NULL) && (name != NULL)
11436 && (xmlStrEqual(ns->prefix, name))) {
11437#ifdef DEBUG_STEP
11438 n++;
11439#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011440 specialNodeInSet = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011441 xmlXPathNodeSetAddNs(list,
11442 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011443 }
11444 }
11445 break;
11446 default:
11447 break;
11448 }
11449 break;
11450 break;
11451 }
11452 } while (cur != NULL);
11453
11454 /*
11455 * If there is some predicate filtering do it now
11456 */
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011457 if ((op->ch2 != -1) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011458 xmlXPathObjectPtr obj2;
11459
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011460 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, list));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011461 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
11462 CHECK_TYPE0(XPATH_NODESET);
11463 obj2 = valuePop(ctxt);
11464 list = obj2->nodesetval;
11465 obj2->nodesetval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011466 xmlXPathReleaseObject(ctxt->context, obj2);
11467
William M. Brack2c19a7b2005-04-10 01:03:23 +000011468 if (ctxt->error != XPATH_EXPRESSION_OK) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011469 t = 0;
11470 goto error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000011471 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011472 }
11473 if (ret == NULL) {
11474 ret = list;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011475 list = NULL;
11476 } else if (list->nodeNr > 0) {
Daniel Veillard75be0132002-03-13 10:03:35 +000011477 ret = mergeNodeSet(ret, list);
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011478 /*
11479 * This is the list containing the current matching nodes.
11480 * Avoid massive creation/freeing and preserve it for the
11481 * next iterations.
11482 */
11483 /* If a namespace node was put it, then we need a more
11484 * time consuming cleanup.
11485 */
11486 if (specialNodeInSet)
11487 xmlXPathNodeSetClear(list);
11488 else
11489 list->nodeNr = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011490 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011491 }
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011492 /*
11493 * Cleanup the temporary list of current node-test matches.
11494 */
11495 if ((list != NULL) && (list != ret)) {
11496 xmlXPathFreeNodeSet(list);
11497 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011498 ctxt->context->node = tmp;
11499#ifdef DEBUG_STEP
11500 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011501 "\nExamined %d nodes, found %d nodes at that step\n",
11502 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011503#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011504 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
11505
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011506 if ((obj->boolval) && (obj->user != NULL)) {
11507 ctxt->value->boolval = 1;
11508 ctxt->value->user = obj->user;
11509 obj->user = NULL;
11510 obj->boolval = 0;
11511 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011512 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011513 return(t);
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011514
11515error:
11516 xmlXPathReleaseObject(ctxt->context, obj);
11517 if ((list != NULL) && (list != ret)) {
11518 xmlXPathFreeNodeSet(list);
11519 }
11520 if (ret != NULL)
11521 xmlXPathFreeNodeSet(ret);
11522 return(t);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011523}
11524
11525/**
11526 * xmlXPathNodeCollectAndTestNth:
11527 * @ctxt: the XPath Parser context
11528 * @op: the XPath precompiled step operation
11529 * @indx: the index to collect
11530 * @first: pointer to the first element in document order
11531 * @last: pointer to the last element in document order
11532 *
11533 * This is the function implementing a step: based on the current list
11534 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000011535 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +000011536 *
11537 * Pushes the new NodeSet resulting from the search.
11538 * Returns the number of node traversed
11539 */
11540static int
11541xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
11542 xmlXPathStepOpPtr op, int indx,
11543 xmlNodePtr * first, xmlNodePtr * last)
11544{
William M. Brack78637da2003-07-31 14:47:38 +000011545 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11546 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11547 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011548 const xmlChar *prefix = op->value4;
11549 const xmlChar *name = op->value5;
11550 const xmlChar *URI = NULL;
11551 int n = 0, t = 0;
11552
11553 int i;
11554 xmlNodeSetPtr list;
11555 xmlXPathTraversalFunction next = NULL;
11556 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11557 xmlNodePtr cur = NULL;
11558 xmlXPathObjectPtr obj;
11559 xmlNodeSetPtr nodelist;
11560 xmlNodePtr tmp;
11561
11562 CHECK_TYPE0(XPATH_NODESET);
11563 obj = valuePop(ctxt);
11564 addNode = xmlXPathNodeSetAdd;
11565 if (prefix != NULL) {
11566 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011567 if (URI == NULL) {
11568 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011569 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011570 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571 }
11572#ifdef DEBUG_STEP_NTH
11573 xmlGenericError(xmlGenericErrorContext, "new step : ");
11574 if (first != NULL) {
11575 if (*first != NULL)
11576 xmlGenericError(xmlGenericErrorContext, "first = %s ",
11577 (*first)->name);
11578 else
11579 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
11580 }
11581 if (last != NULL) {
11582 if (*last != NULL)
11583 xmlGenericError(xmlGenericErrorContext, "last = %s ",
11584 (*last)->name);
11585 else
11586 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
11587 }
11588#endif
11589 switch (axis) {
11590 case AXIS_ANCESTOR:
11591#ifdef DEBUG_STEP_NTH
11592 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11593#endif
11594 first = NULL;
11595 next = xmlXPathNextAncestor;
11596 break;
11597 case AXIS_ANCESTOR_OR_SELF:
11598#ifdef DEBUG_STEP_NTH
11599 xmlGenericError(xmlGenericErrorContext,
11600 "axis 'ancestors-or-self' ");
11601#endif
11602 first = NULL;
11603 next = xmlXPathNextAncestorOrSelf;
11604 break;
11605 case AXIS_ATTRIBUTE:
11606#ifdef DEBUG_STEP_NTH
11607 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11608#endif
11609 first = NULL;
11610 last = NULL;
11611 next = xmlXPathNextAttribute;
11612 break;
11613 case AXIS_CHILD:
11614#ifdef DEBUG_STEP_NTH
11615 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11616#endif
11617 last = NULL;
11618 next = xmlXPathNextChild;
11619 break;
11620 case AXIS_DESCENDANT:
11621#ifdef DEBUG_STEP_NTH
11622 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11623#endif
11624 last = NULL;
11625 next = xmlXPathNextDescendant;
11626 break;
11627 case AXIS_DESCENDANT_OR_SELF:
11628#ifdef DEBUG_STEP_NTH
11629 xmlGenericError(xmlGenericErrorContext,
11630 "axis 'descendant-or-self' ");
11631#endif
11632 last = NULL;
11633 next = xmlXPathNextDescendantOrSelf;
11634 break;
11635 case AXIS_FOLLOWING:
11636#ifdef DEBUG_STEP_NTH
11637 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11638#endif
11639 last = NULL;
11640 next = xmlXPathNextFollowing;
11641 break;
11642 case AXIS_FOLLOWING_SIBLING:
11643#ifdef DEBUG_STEP_NTH
11644 xmlGenericError(xmlGenericErrorContext,
11645 "axis 'following-siblings' ");
11646#endif
11647 last = NULL;
11648 next = xmlXPathNextFollowingSibling;
11649 break;
11650 case AXIS_NAMESPACE:
11651#ifdef DEBUG_STEP_NTH
11652 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11653#endif
11654 last = NULL;
11655 first = NULL;
11656 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11657 break;
11658 case AXIS_PARENT:
11659#ifdef DEBUG_STEP_NTH
11660 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11661#endif
11662 first = NULL;
11663 next = xmlXPathNextParent;
11664 break;
11665 case AXIS_PRECEDING:
11666#ifdef DEBUG_STEP_NTH
11667 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11668#endif
11669 first = NULL;
11670 next = xmlXPathNextPrecedingInternal;
11671 break;
11672 case AXIS_PRECEDING_SIBLING:
11673#ifdef DEBUG_STEP_NTH
11674 xmlGenericError(xmlGenericErrorContext,
11675 "axis 'preceding-sibling' ");
11676#endif
11677 first = NULL;
11678 next = xmlXPathNextPrecedingSibling;
11679 break;
11680 case AXIS_SELF:
11681#ifdef DEBUG_STEP_NTH
11682 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11683#endif
11684 first = NULL;
11685 last = NULL;
11686 next = xmlXPathNextSelf;
11687 break;
11688 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011689 if (next == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011690 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011691 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011692 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011693
11694 nodelist = obj->nodesetval;
11695 if (nodelist == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011696 xmlXPathReleaseObject(ctxt->context, obj);
11697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011698 return(0);
11699 }
11700 addNode = xmlXPathNodeSetAddUnique;
11701#ifdef DEBUG_STEP_NTH
11702 xmlGenericError(xmlGenericErrorContext,
11703 " context contains %d nodes\n", nodelist->nodeNr);
11704 switch (test) {
11705 case NODE_TEST_NONE:
11706 xmlGenericError(xmlGenericErrorContext,
11707 " searching for none !!!\n");
11708 break;
11709 case NODE_TEST_TYPE:
11710 xmlGenericError(xmlGenericErrorContext,
11711 " searching for type %d\n", type);
11712 break;
11713 case NODE_TEST_PI:
11714 xmlGenericError(xmlGenericErrorContext,
11715 " searching for PI !!!\n");
11716 break;
11717 case NODE_TEST_ALL:
11718 xmlGenericError(xmlGenericErrorContext,
11719 " searching for *\n");
11720 break;
11721 case NODE_TEST_NS:
11722 xmlGenericError(xmlGenericErrorContext,
11723 " searching for namespace %s\n",
11724 prefix);
11725 break;
11726 case NODE_TEST_NAME:
11727 xmlGenericError(xmlGenericErrorContext,
11728 " searching for name %s\n", name);
11729 if (prefix != NULL)
11730 xmlGenericError(xmlGenericErrorContext,
11731 " with namespace %s\n", prefix);
11732 break;
11733 }
11734 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11735#endif
11736 /*
11737 * 2.3 Node Tests
11738 * - For the attribute axis, the principal node type is attribute.
11739 * - For the namespace axis, the principal node type is namespace.
11740 * - For other axes, the principal node type is element.
11741 *
11742 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011743 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +000011744 * select all element children of the context node
11745 */
11746 tmp = ctxt->context->node;
11747 list = xmlXPathNodeSetCreate(NULL);
11748 for (i = 0; i < nodelist->nodeNr; i++) {
11749 ctxt->context->node = nodelist->nodeTab[i];
11750
11751 cur = NULL;
11752 n = 0;
11753 do {
11754 cur = next(ctxt, cur);
11755 if (cur == NULL)
11756 break;
11757 if ((first != NULL) && (*first == cur))
11758 break;
11759 if (((t % 256) == 0) &&
11760 (first != NULL) && (*first != NULL) &&
11761 (xmlXPathCmpNodes(*first, cur) >= 0))
11762 break;
11763 if ((last != NULL) && (*last == cur))
11764 break;
11765 if (((t % 256) == 0) &&
11766 (last != NULL) && (*last != NULL) &&
11767 (xmlXPathCmpNodes(cur, *last) >= 0))
11768 break;
11769 t++;
11770 switch (test) {
11771 case NODE_TEST_NONE:
11772 ctxt->context->node = tmp;
11773 STRANGE return(0);
11774 case NODE_TEST_TYPE:
11775 if ((cur->type == type) ||
11776 ((type == NODE_TYPE_NODE) &&
11777 ((cur->type == XML_DOCUMENT_NODE) ||
11778 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11779 (cur->type == XML_ELEMENT_NODE) ||
11780 (cur->type == XML_PI_NODE) ||
11781 (cur->type == XML_COMMENT_NODE) ||
11782 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +000011783 (cur->type == XML_TEXT_NODE))) ||
11784 ((type == NODE_TYPE_TEXT) &&
11785 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011786 n++;
11787 if (n == indx)
11788 addNode(list, cur);
11789 }
11790 break;
11791 case NODE_TEST_PI:
11792 if (cur->type == XML_PI_NODE) {
11793 if ((name != NULL) &&
11794 (!xmlStrEqual(name, cur->name)))
11795 break;
11796 n++;
11797 if (n == indx)
11798 addNode(list, cur);
11799 }
11800 break;
11801 case NODE_TEST_ALL:
11802 if (axis == AXIS_ATTRIBUTE) {
11803 if (cur->type == XML_ATTRIBUTE_NODE) {
11804 n++;
11805 if (n == indx)
11806 addNode(list, cur);
11807 }
11808 } else if (axis == AXIS_NAMESPACE) {
11809 if (cur->type == XML_NAMESPACE_DECL) {
11810 n++;
11811 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011812 xmlXPathNodeSetAddNs(list, ctxt->context->node,
11813 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011814 }
11815 } else {
11816 if (cur->type == XML_ELEMENT_NODE) {
11817 if (prefix == NULL) {
11818 n++;
11819 if (n == indx)
11820 addNode(list, cur);
11821 } else if ((cur->ns != NULL) &&
11822 (xmlStrEqual(URI, cur->ns->href))) {
11823 n++;
11824 if (n == indx)
11825 addNode(list, cur);
11826 }
11827 }
11828 }
11829 break;
11830 case NODE_TEST_NS:{
11831 TODO;
11832 break;
11833 }
11834 case NODE_TEST_NAME:
11835 switch (cur->type) {
11836 case XML_ELEMENT_NODE:
11837 if (xmlStrEqual(name, cur->name)) {
11838 if (prefix == NULL) {
11839 if (cur->ns == NULL) {
11840 n++;
11841 if (n == indx)
11842 addNode(list, cur);
11843 }
11844 } else {
11845 if ((cur->ns != NULL) &&
11846 (xmlStrEqual(URI,
11847 cur->ns->href))) {
11848 n++;
11849 if (n == indx)
11850 addNode(list, cur);
11851 }
11852 }
11853 }
11854 break;
11855 case XML_ATTRIBUTE_NODE:{
11856 xmlAttrPtr attr = (xmlAttrPtr) cur;
11857
11858 if (xmlStrEqual(name, attr->name)) {
11859 if (prefix == NULL) {
11860 if ((attr->ns == NULL) ||
11861 (attr->ns->prefix == NULL)) {
11862 n++;
11863 if (n == indx)
11864 addNode(list, cur);
11865 }
11866 } else {
11867 if ((attr->ns != NULL) &&
11868 (xmlStrEqual(URI,
11869 attr->ns->
11870 href))) {
11871 n++;
11872 if (n == indx)
11873 addNode(list, cur);
11874 }
11875 }
11876 }
11877 break;
11878 }
11879 case XML_NAMESPACE_DECL:
11880 if (cur->type == XML_NAMESPACE_DECL) {
11881 xmlNsPtr ns = (xmlNsPtr) cur;
11882
11883 if ((ns->prefix != NULL) && (name != NULL)
11884 && (xmlStrEqual(ns->prefix, name))) {
11885 n++;
11886 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011887 xmlXPathNodeSetAddNs(list,
11888 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011889 }
11890 }
11891 break;
11892 default:
11893 break;
11894 }
11895 break;
11896 break;
11897 }
11898 } while (n < indx);
11899 }
11900 ctxt->context->node = tmp;
11901#ifdef DEBUG_STEP_NTH
11902 xmlGenericError(xmlGenericErrorContext,
11903 "\nExamined %d nodes, found %d nodes at that step\n",
11904 t, list->nodeNr);
11905#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011906 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011907 if ((obj->boolval) && (obj->user != NULL)) {
11908 ctxt->value->boolval = 1;
11909 ctxt->value->user = obj->user;
11910 obj->user = NULL;
11911 obj->boolval = 0;
11912 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011913 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011914 return(t);
11915}
11916
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011917static int
11918xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11919 xmlXPathStepOpPtr op, xmlNodePtr * first);
11920
Daniel Veillardf06307e2001-07-03 10:35:50 +000011921/**
11922 * xmlXPathCompOpEvalFirst:
11923 * @ctxt: the XPath parser context with the compiled expression
11924 * @op: an XPath compiled operation
11925 * @first: the first elem found so far
11926 *
11927 * Evaluate the Precompiled XPath operation searching only the first
11928 * element in document order
11929 *
11930 * Returns the number of examined objects.
11931 */
11932static int
11933xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11934 xmlXPathStepOpPtr op, xmlNodePtr * first)
11935{
11936 int total = 0, cur;
11937 xmlXPathCompExprPtr comp;
11938 xmlXPathObjectPtr arg1, arg2;
11939
Daniel Veillard556c6682001-10-06 09:59:51 +000011940 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011941 comp = ctxt->comp;
11942 switch (op->op) {
11943 case XPATH_OP_END:
11944 return (0);
11945 case XPATH_OP_UNION:
11946 total =
11947 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11948 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000011949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011950 if ((ctxt->value != NULL)
11951 && (ctxt->value->type == XPATH_NODESET)
11952 && (ctxt->value->nodesetval != NULL)
11953 && (ctxt->value->nodesetval->nodeNr >= 1)) {
11954 /*
11955 * limit tree traversing to first node in the result
11956 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011957 /*
11958 * OPTIMIZE TODO: This implicitely sorts
11959 * the result, even if not needed. E.g. if the argument
11960 * of the count() function, no sorting is needed.
11961 * OPTIMIZE TODO: How do we know if the node-list wasn't
11962 * aready sorted?
11963 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011964 if (ctxt->value->nodesetval->nodeNr > 1)
11965 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011966 *first = ctxt->value->nodesetval->nodeTab[0];
11967 }
11968 cur =
11969 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11970 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000011971 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011972 CHECK_TYPE0(XPATH_NODESET);
11973 arg2 = valuePop(ctxt);
11974
11975 CHECK_TYPE0(XPATH_NODESET);
11976 arg1 = valuePop(ctxt);
11977
11978 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11979 arg2->nodesetval);
11980 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011981 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011982 /* optimizer */
11983 if (total > cur)
11984 xmlXPathCompSwap(op);
11985 return (total + cur);
11986 case XPATH_OP_ROOT:
11987 xmlXPathRoot(ctxt);
11988 return (0);
11989 case XPATH_OP_NODE:
11990 if (op->ch1 != -1)
11991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011992 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011993 if (op->ch2 != -1)
11994 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011995 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011996 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11997 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011998 return (total);
11999 case XPATH_OP_RESET:
12000 if (op->ch1 != -1)
12001 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012002 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012003 if (op->ch2 != -1)
12004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012005 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012006 ctxt->context->node = NULL;
12007 return (total);
12008 case XPATH_OP_COLLECT:{
12009 if (op->ch1 == -1)
12010 return (total);
12011
12012 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012013 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012014
12015 /*
12016 * Optimization for [n] selection where n is a number
12017 */
12018 if ((op->ch2 != -1) &&
12019 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12020 (comp->steps[op->ch2].ch1 == -1) &&
12021 (comp->steps[op->ch2].ch2 != -1) &&
12022 (comp->steps[comp->steps[op->ch2].ch2].op ==
12023 XPATH_OP_VALUE)) {
12024 xmlXPathObjectPtr val;
12025
12026 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12027 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12028 int indx = (int) val->floatval;
12029
12030 if (val->floatval == (float) indx) {
12031 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
12032 first, NULL);
12033 return (total);
12034 }
12035 }
12036 }
12037 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
12038 return (total);
12039 }
12040 case XPATH_OP_VALUE:
12041 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012042 xmlXPathCacheObjectCopy(ctxt->context,
12043 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012044 return (0);
12045 case XPATH_OP_SORT:
12046 if (op->ch1 != -1)
12047 total +=
12048 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12049 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012050 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012051 if ((ctxt->value != NULL)
12052 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012053 && (ctxt->value->nodesetval != NULL)
12054 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012055 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12056 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012057#ifdef XP_OPTIMIZED_FILTER_FIRST
12058 case XPATH_OP_FILTER:
12059 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12060 return (total);
12061#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012062 default:
12063 return (xmlXPathCompOpEval(ctxt, op));
12064 }
12065}
12066
12067/**
12068 * xmlXPathCompOpEvalLast:
12069 * @ctxt: the XPath parser context with the compiled expression
12070 * @op: an XPath compiled operation
12071 * @last: the last elem found so far
12072 *
12073 * Evaluate the Precompiled XPath operation searching only the last
12074 * element in document order
12075 *
William M. Brack08171912003-12-29 02:52:11 +000012076 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012077 */
12078static int
12079xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12080 xmlNodePtr * last)
12081{
12082 int total = 0, cur;
12083 xmlXPathCompExprPtr comp;
12084 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012085 xmlNodePtr bak;
12086 xmlDocPtr bakd;
12087 int pp;
12088 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012089
Daniel Veillard556c6682001-10-06 09:59:51 +000012090 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012091 comp = ctxt->comp;
12092 switch (op->op) {
12093 case XPATH_OP_END:
12094 return (0);
12095 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012096 bakd = ctxt->context->doc;
12097 bak = ctxt->context->node;
12098 pp = ctxt->context->proximityPosition;
12099 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012100 total =
12101 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012102 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012103 if ((ctxt->value != NULL)
12104 && (ctxt->value->type == XPATH_NODESET)
12105 && (ctxt->value->nodesetval != NULL)
12106 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12107 /*
12108 * limit tree traversing to first node in the result
12109 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012110 if (ctxt->value->nodesetval->nodeNr > 1)
12111 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012112 *last =
12113 ctxt->value->nodesetval->nodeTab[ctxt->value->
12114 nodesetval->nodeNr -
12115 1];
12116 }
William M. Brackce4fc562004-01-22 02:47:18 +000012117 ctxt->context->doc = bakd;
12118 ctxt->context->node = bak;
12119 ctxt->context->proximityPosition = pp;
12120 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012121 cur =
12122 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012123 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012124 if ((ctxt->value != NULL)
12125 && (ctxt->value->type == XPATH_NODESET)
12126 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012127 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012128 }
12129 CHECK_TYPE0(XPATH_NODESET);
12130 arg2 = valuePop(ctxt);
12131
12132 CHECK_TYPE0(XPATH_NODESET);
12133 arg1 = valuePop(ctxt);
12134
12135 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12136 arg2->nodesetval);
12137 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012138 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012139 /* optimizer */
12140 if (total > cur)
12141 xmlXPathCompSwap(op);
12142 return (total + cur);
12143 case XPATH_OP_ROOT:
12144 xmlXPathRoot(ctxt);
12145 return (0);
12146 case XPATH_OP_NODE:
12147 if (op->ch1 != -1)
12148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012149 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012150 if (op->ch2 != -1)
12151 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012152 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012153 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12154 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012155 return (total);
12156 case XPATH_OP_RESET:
12157 if (op->ch1 != -1)
12158 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012159 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012160 if (op->ch2 != -1)
12161 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012162 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012163 ctxt->context->node = NULL;
12164 return (total);
12165 case XPATH_OP_COLLECT:{
12166 if (op->ch1 == -1)
12167 return (0);
12168
12169 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012170 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012171
12172 /*
12173 * Optimization for [n] selection where n is a number
12174 */
12175 if ((op->ch2 != -1) &&
12176 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12177 (comp->steps[op->ch2].ch1 == -1) &&
12178 (comp->steps[op->ch2].ch2 != -1) &&
12179 (comp->steps[comp->steps[op->ch2].ch2].op ==
12180 XPATH_OP_VALUE)) {
12181 xmlXPathObjectPtr val;
12182
12183 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12184 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12185 int indx = (int) val->floatval;
12186
12187 if (val->floatval == (float) indx) {
12188 total +=
12189 xmlXPathNodeCollectAndTestNth(ctxt, op,
12190 indx, NULL,
12191 last);
12192 return (total);
12193 }
12194 }
12195 }
12196 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
12197 return (total);
12198 }
12199 case XPATH_OP_VALUE:
12200 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012201 xmlXPathCacheObjectCopy(ctxt->context,
12202 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012203 return (0);
12204 case XPATH_OP_SORT:
12205 if (op->ch1 != -1)
12206 total +=
12207 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12208 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012209 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012210 if ((ctxt->value != NULL)
12211 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012212 && (ctxt->value->nodesetval != NULL)
12213 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012214 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12215 return (total);
12216 default:
12217 return (xmlXPathCompOpEval(ctxt, op));
12218 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012219}
12220
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012221#ifdef XP_OPTIMIZED_FILTER_FIRST
12222static int
12223xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12224 xmlXPathStepOpPtr op, xmlNodePtr * first)
12225{
12226 int total = 0;
12227 xmlXPathCompExprPtr comp;
12228 xmlXPathObjectPtr res;
12229 xmlXPathObjectPtr obj;
12230 xmlNodeSetPtr oldset;
12231 xmlNodePtr oldnode;
12232 xmlDocPtr oldDoc;
12233 int i;
12234
12235 CHECK_ERROR0;
12236 comp = ctxt->comp;
12237 /*
12238 * Optimization for ()[last()] selection i.e. the last elem
12239 */
12240 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12241 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12242 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12243 int f = comp->steps[op->ch2].ch1;
12244
12245 if ((f != -1) &&
12246 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12247 (comp->steps[f].value5 == NULL) &&
12248 (comp->steps[f].value == 0) &&
12249 (comp->steps[f].value4 != NULL) &&
12250 (xmlStrEqual
12251 (comp->steps[f].value4, BAD_CAST "last"))) {
12252 xmlNodePtr last = NULL;
12253
12254 total +=
12255 xmlXPathCompOpEvalLast(ctxt,
12256 &comp->steps[op->ch1],
12257 &last);
12258 CHECK_ERROR0;
12259 /*
12260 * The nodeset should be in document order,
12261 * Keep only the last value
12262 */
12263 if ((ctxt->value != NULL) &&
12264 (ctxt->value->type == XPATH_NODESET) &&
12265 (ctxt->value->nodesetval != NULL) &&
12266 (ctxt->value->nodesetval->nodeTab != NULL) &&
12267 (ctxt->value->nodesetval->nodeNr > 1)) {
12268 ctxt->value->nodesetval->nodeTab[0] =
12269 ctxt->value->nodesetval->nodeTab[ctxt->
12270 value->
12271 nodesetval->
12272 nodeNr -
12273 1];
12274 ctxt->value->nodesetval->nodeNr = 1;
12275 *first = *(ctxt->value->nodesetval->nodeTab);
12276 }
12277 return (total);
12278 }
12279 }
12280
12281 if (op->ch1 != -1)
12282 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12283 CHECK_ERROR0;
12284 if (op->ch2 == -1)
12285 return (total);
12286 if (ctxt->value == NULL)
12287 return (total);
12288
12289#ifdef LIBXML_XPTR_ENABLED
12290 oldnode = ctxt->context->node;
12291 /*
12292 * Hum are we filtering the result of an XPointer expression
12293 */
12294 if (ctxt->value->type == XPATH_LOCATIONSET) {
12295 xmlXPathObjectPtr tmp = NULL;
12296 xmlLocationSetPtr newlocset = NULL;
12297 xmlLocationSetPtr oldlocset;
12298
12299 /*
12300 * Extract the old locset, and then evaluate the result of the
12301 * expression for all the element in the locset. use it to grow
12302 * up a new locset.
12303 */
12304 CHECK_TYPE0(XPATH_LOCATIONSET);
12305 obj = valuePop(ctxt);
12306 oldlocset = obj->user;
12307 ctxt->context->node = NULL;
12308
12309 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12310 ctxt->context->contextSize = 0;
12311 ctxt->context->proximityPosition = 0;
12312 if (op->ch2 != -1)
12313 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12314 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012315 if (res != NULL) {
12316 xmlXPathReleaseObject(ctxt->context, res);
12317 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012318 valuePush(ctxt, obj);
12319 CHECK_ERROR0;
12320 return (total);
12321 }
12322 newlocset = xmlXPtrLocationSetCreate(NULL);
12323
12324 for (i = 0; i < oldlocset->locNr; i++) {
12325 /*
12326 * Run the evaluation with a node list made of a
12327 * single item in the nodelocset.
12328 */
12329 ctxt->context->node = oldlocset->locTab[i]->user;
12330 ctxt->context->contextSize = oldlocset->locNr;
12331 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012332 if (tmp == NULL) {
12333 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12334 ctxt->context->node);
12335 } else {
12336 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12337 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012338 }
12339 valuePush(ctxt, tmp);
12340 if (op->ch2 != -1)
12341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12342 if (ctxt->error != XPATH_EXPRESSION_OK) {
12343 xmlXPathFreeObject(obj);
12344 return(0);
12345 }
12346 /*
12347 * The result of the evaluation need to be tested to
12348 * decided whether the filter succeeded or not
12349 */
12350 res = valuePop(ctxt);
12351 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12352 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012353 xmlXPathCacheObjectCopy(ctxt->context,
12354 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012355 }
12356 /*
12357 * Cleanup
12358 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012359 if (res != NULL) {
12360 xmlXPathReleaseObject(ctxt->context, res);
12361 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012362 if (ctxt->value == tmp) {
12363 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012364 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012365 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012366 * REVISIT TODO: Don't create a temporary nodeset
12367 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012368 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012369 /* OLD: xmlXPathFreeObject(res); */
12370 } else
12371 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012372 ctxt->context->node = NULL;
12373 /*
12374 * Only put the first node in the result, then leave.
12375 */
12376 if (newlocset->locNr > 0) {
12377 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12378 break;
12379 }
12380 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012381 if (tmp != NULL) {
12382 xmlXPathReleaseObject(ctxt->context, tmp);
12383 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012384 /*
12385 * The result is used as the new evaluation locset.
12386 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012387 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012388 ctxt->context->node = NULL;
12389 ctxt->context->contextSize = -1;
12390 ctxt->context->proximityPosition = -1;
12391 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12392 ctxt->context->node = oldnode;
12393 return (total);
12394 }
12395#endif /* LIBXML_XPTR_ENABLED */
12396
12397 /*
12398 * Extract the old set, and then evaluate the result of the
12399 * expression for all the element in the set. use it to grow
12400 * up a new set.
12401 */
12402 CHECK_TYPE0(XPATH_NODESET);
12403 obj = valuePop(ctxt);
12404 oldset = obj->nodesetval;
12405
12406 oldnode = ctxt->context->node;
12407 oldDoc = ctxt->context->doc;
12408 ctxt->context->node = NULL;
12409
12410 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12411 ctxt->context->contextSize = 0;
12412 ctxt->context->proximityPosition = 0;
12413 /* QUESTION TODO: Why was this code commented out?
12414 if (op->ch2 != -1)
12415 total +=
12416 xmlXPathCompOpEval(ctxt,
12417 &comp->steps[op->ch2]);
12418 CHECK_ERROR0;
12419 res = valuePop(ctxt);
12420 if (res != NULL)
12421 xmlXPathFreeObject(res);
12422 */
12423 valuePush(ctxt, obj);
12424 ctxt->context->node = oldnode;
12425 CHECK_ERROR0;
12426 } else {
12427 xmlNodeSetPtr newset;
12428 xmlXPathObjectPtr tmp = NULL;
12429 /*
12430 * Initialize the new set.
12431 * Also set the xpath document in case things like
12432 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012433 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012434 newset = xmlXPathNodeSetCreate(NULL);
12435
12436 for (i = 0; i < oldset->nodeNr; i++) {
12437 /*
12438 * Run the evaluation with a node list made of
12439 * a single item in the nodeset.
12440 */
12441 ctxt->context->node = oldset->nodeTab[i];
12442 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12443 (oldset->nodeTab[i]->doc != NULL))
12444 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012445 if (tmp == NULL) {
12446 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12447 ctxt->context->node);
12448 } else {
12449 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12450 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012451 }
12452 valuePush(ctxt, tmp);
12453 ctxt->context->contextSize = oldset->nodeNr;
12454 ctxt->context->proximityPosition = i + 1;
12455 if (op->ch2 != -1)
12456 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12457 if (ctxt->error != XPATH_EXPRESSION_OK) {
12458 xmlXPathFreeNodeSet(newset);
12459 xmlXPathFreeObject(obj);
12460 return(0);
12461 }
12462 /*
12463 * The result of the evaluation needs to be tested to
12464 * decide whether the filter succeeded or not
12465 */
12466 res = valuePop(ctxt);
12467 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12468 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12469 }
12470 /*
12471 * Cleanup
12472 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012473 if (res != NULL) {
12474 xmlXPathReleaseObject(ctxt->context, res);
12475 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012476 if (ctxt->value == tmp) {
12477 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012478 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012479 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012480 * in order to avoid massive recreation inside this
12481 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012482 */
12483 xmlXPathNodeSetClear(tmp->nodesetval);
12484 } else
12485 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012486 ctxt->context->node = NULL;
12487 /*
12488 * Only put the first node in the result, then leave.
12489 */
12490 if (newset->nodeNr > 0) {
12491 *first = *(newset->nodeTab);
12492 break;
12493 }
12494 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012495 if (tmp != NULL) {
12496 xmlXPathReleaseObject(ctxt->context, tmp);
12497 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012498 /*
12499 * The result is used as the new evaluation set.
12500 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012501 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012502 ctxt->context->node = NULL;
12503 ctxt->context->contextSize = -1;
12504 ctxt->context->proximityPosition = -1;
12505 /* may want to move this past the '}' later */
12506 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012507 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012508 }
12509 ctxt->context->node = oldnode;
12510 return(total);
12511}
12512#endif /* XP_OPTIMIZED_FILTER_FIRST */
12513
Owen Taylor3473f882001-02-23 17:55:21 +000012514/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012515 * xmlXPathCompOpEval:
12516 * @ctxt: the XPath parser context with the compiled expression
12517 * @op: an XPath compiled operation
12518 *
12519 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000012520 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012521 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012522static int
12523xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12524{
12525 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012526 int equal, ret;
12527 xmlXPathCompExprPtr comp;
12528 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012529 xmlNodePtr bak;
12530 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000012531 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000012532 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012533
Daniel Veillard556c6682001-10-06 09:59:51 +000012534 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012535 comp = ctxt->comp;
12536 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012537 case XPATH_OP_END:
12538 return (0);
12539 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012540 bakd = ctxt->context->doc;
12541 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012542 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012543 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012544 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012545 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012546 xmlXPathBooleanFunction(ctxt, 1);
12547 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12548 return (total);
12549 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012550 ctxt->context->doc = bakd;
12551 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012552 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012553 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012554 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012555 if (ctxt->error) {
12556 xmlXPathFreeObject(arg2);
12557 return(0);
12558 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012559 xmlXPathBooleanFunction(ctxt, 1);
12560 arg1 = valuePop(ctxt);
12561 arg1->boolval &= arg2->boolval;
12562 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012563 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012564 return (total);
12565 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012566 bakd = ctxt->context->doc;
12567 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012568 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012569 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012570 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012571 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012572 xmlXPathBooleanFunction(ctxt, 1);
12573 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12574 return (total);
12575 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012576 ctxt->context->doc = bakd;
12577 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012578 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012579 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012580 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012581 if (ctxt->error) {
12582 xmlXPathFreeObject(arg2);
12583 return(0);
12584 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012585 xmlXPathBooleanFunction(ctxt, 1);
12586 arg1 = valuePop(ctxt);
12587 arg1->boolval |= arg2->boolval;
12588 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012589 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012590 return (total);
12591 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012592 bakd = ctxt->context->doc;
12593 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012594 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012595 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012596 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012597 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012598 ctxt->context->doc = bakd;
12599 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012600 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012601 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012602 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012603 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000012604 if (op->value)
12605 equal = xmlXPathEqualValues(ctxt);
12606 else
12607 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012608 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012609 return (total);
12610 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012611 bakd = ctxt->context->doc;
12612 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012613 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012614 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012615 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012616 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012617 ctxt->context->doc = bakd;
12618 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012619 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012620 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012621 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012622 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012623 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012624 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012625 return (total);
12626 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012627 bakd = ctxt->context->doc;
12628 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012629 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012630 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012631 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012632 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012633 if (op->ch2 != -1) {
12634 ctxt->context->doc = bakd;
12635 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012636 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012637 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012638 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012639 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012640 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012641 if (op->value == 0)
12642 xmlXPathSubValues(ctxt);
12643 else if (op->value == 1)
12644 xmlXPathAddValues(ctxt);
12645 else if (op->value == 2)
12646 xmlXPathValueFlipSign(ctxt);
12647 else if (op->value == 3) {
12648 CAST_TO_NUMBER;
12649 CHECK_TYPE0(XPATH_NUMBER);
12650 }
12651 return (total);
12652 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012653 bakd = ctxt->context->doc;
12654 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012655 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012656 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012657 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012658 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012659 ctxt->context->doc = bakd;
12660 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012661 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012662 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012663 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012664 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012665 if (op->value == 0)
12666 xmlXPathMultValues(ctxt);
12667 else if (op->value == 1)
12668 xmlXPathDivValues(ctxt);
12669 else if (op->value == 2)
12670 xmlXPathModValues(ctxt);
12671 return (total);
12672 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012673 bakd = ctxt->context->doc;
12674 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012675 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012676 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012677 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012678 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012679 ctxt->context->doc = bakd;
12680 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012681 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012682 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012684 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012685 CHECK_TYPE0(XPATH_NODESET);
12686 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012687
Daniel Veillardf06307e2001-07-03 10:35:50 +000012688 CHECK_TYPE0(XPATH_NODESET);
12689 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012690
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012691 if ((arg1->nodesetval == NULL) ||
12692 ((arg2->nodesetval != NULL) &&
12693 (arg2->nodesetval->nodeNr != 0)))
12694 {
12695 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12696 arg2->nodesetval);
12697 }
12698
Daniel Veillardf06307e2001-07-03 10:35:50 +000012699 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012700 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012701 return (total);
12702 case XPATH_OP_ROOT:
12703 xmlXPathRoot(ctxt);
12704 return (total);
12705 case XPATH_OP_NODE:
12706 if (op->ch1 != -1)
12707 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012708 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012709 if (op->ch2 != -1)
12710 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012711 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012712 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12713 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012714 return (total);
12715 case XPATH_OP_RESET:
12716 if (op->ch1 != -1)
12717 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012718 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012719 if (op->ch2 != -1)
12720 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012721 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012722 ctxt->context->node = NULL;
12723 return (total);
12724 case XPATH_OP_COLLECT:{
12725 if (op->ch1 == -1)
12726 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012727
Daniel Veillardf06307e2001-07-03 10:35:50 +000012728 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012729 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012730
Daniel Veillardf06307e2001-07-03 10:35:50 +000012731 /*
12732 * Optimization for [n] selection where n is a number
12733 */
12734 if ((op->ch2 != -1) &&
12735 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12736 (comp->steps[op->ch2].ch1 == -1) &&
12737 (comp->steps[op->ch2].ch2 != -1) &&
12738 (comp->steps[comp->steps[op->ch2].ch2].op ==
12739 XPATH_OP_VALUE)) {
12740 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000012741
Daniel Veillardf06307e2001-07-03 10:35:50 +000012742 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12743 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12744 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012745
Daniel Veillardf06307e2001-07-03 10:35:50 +000012746 if (val->floatval == (float) indx) {
12747 total +=
12748 xmlXPathNodeCollectAndTestNth(ctxt, op,
12749 indx, NULL,
12750 NULL);
12751 return (total);
12752 }
12753 }
12754 }
12755 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
12756 return (total);
12757 }
12758 case XPATH_OP_VALUE:
12759 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012760 xmlXPathCacheObjectCopy(ctxt->context,
12761 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012762 return (total);
12763 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000012764 xmlXPathObjectPtr val;
12765
Daniel Veillardf06307e2001-07-03 10:35:50 +000012766 if (op->ch1 != -1)
12767 total +=
12768 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012769 if (op->value5 == NULL) {
12770 val = xmlXPathVariableLookup(ctxt->context, op->value4);
12771 if (val == NULL) {
12772 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12773 return(0);
12774 }
12775 valuePush(ctxt, val);
12776 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012777 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012778
Daniel Veillardf06307e2001-07-03 10:35:50 +000012779 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12780 if (URI == NULL) {
12781 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012782 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012783 op->value4, op->value5);
12784 return (total);
12785 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012786 val = xmlXPathVariableLookupNS(ctxt->context,
12787 op->value4, URI);
12788 if (val == NULL) {
12789 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12790 return(0);
12791 }
12792 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012793 }
12794 return (total);
12795 }
12796 case XPATH_OP_FUNCTION:{
12797 xmlXPathFunction func;
12798 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000012799 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012800
12801 if (op->ch1 != -1)
12802 total +=
12803 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012804 if (ctxt->valueNr < op->value) {
12805 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012806 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000012807 ctxt->error = XPATH_INVALID_OPERAND;
12808 return (total);
12809 }
12810 for (i = 0; i < op->value; i++)
12811 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
12812 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012813 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000012814 ctxt->error = XPATH_INVALID_OPERAND;
12815 return (total);
12816 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012817 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000012818 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012819 else {
12820 const xmlChar *URI = NULL;
12821
12822 if (op->value5 == NULL)
12823 func =
12824 xmlXPathFunctionLookup(ctxt->context,
12825 op->value4);
12826 else {
12827 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12828 if (URI == NULL) {
12829 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012830 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012831 op->value4, op->value5);
12832 return (total);
12833 }
12834 func = xmlXPathFunctionLookupNS(ctxt->context,
12835 op->value4, URI);
12836 }
12837 if (func == NULL) {
12838 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012839 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012840 op->value4);
12841 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012842 }
William M. Brackad0e67c2004-12-01 14:35:10 +000012843 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012844 op->cacheURI = (void *) URI;
12845 }
12846 oldFunc = ctxt->context->function;
12847 oldFuncURI = ctxt->context->functionURI;
12848 ctxt->context->function = op->value4;
12849 ctxt->context->functionURI = op->cacheURI;
12850 func(ctxt, op->value);
12851 ctxt->context->function = oldFunc;
12852 ctxt->context->functionURI = oldFuncURI;
12853 return (total);
12854 }
12855 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000012856 bakd = ctxt->context->doc;
12857 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000012858 pp = ctxt->context->proximityPosition;
12859 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012860 if (op->ch1 != -1)
12861 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000012862 ctxt->context->contextSize = cs;
12863 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000012864 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000012865 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000012866 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000012867 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012868 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000012869 ctxt->context->doc = bakd;
12870 ctxt->context->node = bak;
12871 CHECK_ERROR0;
12872 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012873 return (total);
12874 case XPATH_OP_PREDICATE:
12875 case XPATH_OP_FILTER:{
12876 xmlXPathObjectPtr res;
12877 xmlXPathObjectPtr obj, tmp;
12878 xmlNodeSetPtr newset = NULL;
12879 xmlNodeSetPtr oldset;
12880 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000012881 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012882 int i;
12883
12884 /*
12885 * Optimization for ()[1] selection i.e. the first elem
12886 */
12887 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012888#ifdef XP_OPTIMIZED_FILTER_FIRST
12889 /*
12890 * FILTER TODO: Can we assume that the inner processing
12891 * will result in an ordered list if we have an
12892 * XPATH_OP_FILTER?
12893 * What about an additional field or flag on
12894 * xmlXPathObject like @sorted ? This way we wouln'd need
12895 * to assume anything, so it would be more robust and
12896 * easier to optimize.
12897 */
12898 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12899 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12900#else
12901 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12902#endif
12903 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012904 xmlXPathObjectPtr val;
12905
12906 val = comp->steps[op->ch2].value4;
12907 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12908 (val->floatval == 1.0)) {
12909 xmlNodePtr first = NULL;
12910
12911 total +=
12912 xmlXPathCompOpEvalFirst(ctxt,
12913 &comp->steps[op->ch1],
12914 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012915 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012916 /*
12917 * The nodeset should be in document order,
12918 * Keep only the first value
12919 */
12920 if ((ctxt->value != NULL) &&
12921 (ctxt->value->type == XPATH_NODESET) &&
12922 (ctxt->value->nodesetval != NULL) &&
12923 (ctxt->value->nodesetval->nodeNr > 1))
12924 ctxt->value->nodesetval->nodeNr = 1;
12925 return (total);
12926 }
12927 }
12928 /*
12929 * Optimization for ()[last()] selection i.e. the last elem
12930 */
12931 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12932 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12933 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12934 int f = comp->steps[op->ch2].ch1;
12935
12936 if ((f != -1) &&
12937 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12938 (comp->steps[f].value5 == NULL) &&
12939 (comp->steps[f].value == 0) &&
12940 (comp->steps[f].value4 != NULL) &&
12941 (xmlStrEqual
12942 (comp->steps[f].value4, BAD_CAST "last"))) {
12943 xmlNodePtr last = NULL;
12944
12945 total +=
12946 xmlXPathCompOpEvalLast(ctxt,
12947 &comp->steps[op->ch1],
12948 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012950 /*
12951 * The nodeset should be in document order,
12952 * Keep only the last value
12953 */
12954 if ((ctxt->value != NULL) &&
12955 (ctxt->value->type == XPATH_NODESET) &&
12956 (ctxt->value->nodesetval != NULL) &&
12957 (ctxt->value->nodesetval->nodeTab != NULL) &&
12958 (ctxt->value->nodesetval->nodeNr > 1)) {
12959 ctxt->value->nodesetval->nodeTab[0] =
12960 ctxt->value->nodesetval->nodeTab[ctxt->
12961 value->
12962 nodesetval->
12963 nodeNr -
12964 1];
12965 ctxt->value->nodesetval->nodeNr = 1;
12966 }
12967 return (total);
12968 }
12969 }
12970
12971 if (op->ch1 != -1)
12972 total +=
12973 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012974 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012975 if (op->ch2 == -1)
12976 return (total);
12977 if (ctxt->value == NULL)
12978 return (total);
12979
12980 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012981
12982#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000012983 /*
12984 * Hum are we filtering the result of an XPointer expression
12985 */
12986 if (ctxt->value->type == XPATH_LOCATIONSET) {
12987 xmlLocationSetPtr newlocset = NULL;
12988 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012989
Daniel Veillardf06307e2001-07-03 10:35:50 +000012990 /*
12991 * Extract the old locset, and then evaluate the result of the
12992 * expression for all the element in the locset. use it to grow
12993 * up a new locset.
12994 */
12995 CHECK_TYPE0(XPATH_LOCATIONSET);
12996 obj = valuePop(ctxt);
12997 oldlocset = obj->user;
12998 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012999
Daniel Veillardf06307e2001-07-03 10:35:50 +000013000 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13001 ctxt->context->contextSize = 0;
13002 ctxt->context->proximityPosition = 0;
13003 if (op->ch2 != -1)
13004 total +=
13005 xmlXPathCompOpEval(ctxt,
13006 &comp->steps[op->ch2]);
13007 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013008 if (res != NULL) {
13009 xmlXPathReleaseObject(ctxt->context, res);
13010 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013011 valuePush(ctxt, obj);
13012 CHECK_ERROR0;
13013 return (total);
13014 }
13015 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013016
Daniel Veillardf06307e2001-07-03 10:35:50 +000013017 for (i = 0; i < oldlocset->locNr; i++) {
13018 /*
13019 * Run the evaluation with a node list made of a
13020 * single item in the nodelocset.
13021 */
13022 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013023 ctxt->context->contextSize = oldlocset->locNr;
13024 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013025 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13026 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013027 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013028
Daniel Veillardf06307e2001-07-03 10:35:50 +000013029 if (op->ch2 != -1)
13030 total +=
13031 xmlXPathCompOpEval(ctxt,
13032 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013033 if (ctxt->error != XPATH_EXPRESSION_OK) {
13034 xmlXPathFreeObject(obj);
13035 return(0);
13036 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013037
Daniel Veillardf06307e2001-07-03 10:35:50 +000013038 /*
13039 * The result of the evaluation need to be tested to
13040 * decided whether the filter succeeded or not
13041 */
13042 res = valuePop(ctxt);
13043 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13044 xmlXPtrLocationSetAdd(newlocset,
13045 xmlXPathObjectCopy
13046 (oldlocset->locTab[i]));
13047 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013048
Daniel Veillardf06307e2001-07-03 10:35:50 +000013049 /*
13050 * Cleanup
13051 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013052 if (res != NULL) {
13053 xmlXPathReleaseObject(ctxt->context, res);
13054 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013055 if (ctxt->value == tmp) {
13056 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013057 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013058 }
13059
13060 ctxt->context->node = NULL;
13061 }
13062
13063 /*
13064 * The result is used as the new evaluation locset.
13065 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013066 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013067 ctxt->context->node = NULL;
13068 ctxt->context->contextSize = -1;
13069 ctxt->context->proximityPosition = -1;
13070 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13071 ctxt->context->node = oldnode;
13072 return (total);
13073 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013074#endif /* LIBXML_XPTR_ENABLED */
13075
Daniel Veillardf06307e2001-07-03 10:35:50 +000013076 /*
13077 * Extract the old set, and then evaluate the result of the
13078 * expression for all the element in the set. use it to grow
13079 * up a new set.
13080 */
13081 CHECK_TYPE0(XPATH_NODESET);
13082 obj = valuePop(ctxt);
13083 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013084
Daniel Veillardf06307e2001-07-03 10:35:50 +000013085 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013086 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013087 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013088
Daniel Veillardf06307e2001-07-03 10:35:50 +000013089 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13090 ctxt->context->contextSize = 0;
13091 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013092/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013093 if (op->ch2 != -1)
13094 total +=
13095 xmlXPathCompOpEval(ctxt,
13096 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013097 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013098 res = valuePop(ctxt);
13099 if (res != NULL)
13100 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013101*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013102 valuePush(ctxt, obj);
13103 ctxt->context->node = oldnode;
13104 CHECK_ERROR0;
13105 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013106 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013107 /*
13108 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013109 * Also set the xpath document in case things like
13110 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013111 */
13112 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013113
Daniel Veillardf06307e2001-07-03 10:35:50 +000013114 for (i = 0; i < oldset->nodeNr; i++) {
13115 /*
13116 * Run the evaluation with a node list made of
13117 * a single item in the nodeset.
13118 */
13119 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013120 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13121 (oldset->nodeTab[i]->doc != NULL))
13122 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013123 if (tmp == NULL) {
13124 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13125 ctxt->context->node);
13126 } else {
13127 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13128 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013129 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013130 valuePush(ctxt, tmp);
13131 ctxt->context->contextSize = oldset->nodeNr;
13132 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013133
Daniel Veillardf06307e2001-07-03 10:35:50 +000013134 if (op->ch2 != -1)
13135 total +=
13136 xmlXPathCompOpEval(ctxt,
13137 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013138 if (ctxt->error != XPATH_EXPRESSION_OK) {
13139 xmlXPathFreeNodeSet(newset);
13140 xmlXPathFreeObject(obj);
13141 return(0);
13142 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013143
Daniel Veillardf06307e2001-07-03 10:35:50 +000013144 /*
William M. Brack08171912003-12-29 02:52:11 +000013145 * The result of the evaluation needs to be tested to
13146 * decide whether the filter succeeded or not
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000013147 */ /* URGENT TODO: xmlXPathNodeSetAdd*Unique* ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013148 res = valuePop(ctxt);
13149 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13150 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13151 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013152
Daniel Veillardf06307e2001-07-03 10:35:50 +000013153 /*
13154 * Cleanup
13155 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013156 if (res != NULL) {
13157 xmlXPathReleaseObject(ctxt->context, res);
13158 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013159 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013160 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013161 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013162 /*
13163 * REVISIT TODO: Don't free the temporary nodeset
13164 * in order to avoid massive recreation inside this
13165 * loop.
13166 */
13167 /* xmlXPathFreeObject(res); */
13168 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013169 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013170 ctxt->context->node = NULL;
13171 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013172 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013173 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013174 /*
13175 * The result is used as the new evaluation set.
13176 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013177 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013178 ctxt->context->node = NULL;
13179 ctxt->context->contextSize = -1;
13180 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013181 /* may want to move this past the '}' later */
13182 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013183 valuePush(ctxt,
13184 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013185 }
13186 ctxt->context->node = oldnode;
13187 return (total);
13188 }
13189 case XPATH_OP_SORT:
13190 if (op->ch1 != -1)
13191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013192 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013193 if ((ctxt->value != NULL) &&
13194 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013195 (ctxt->value->nodesetval != NULL) &&
13196 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013197 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013198 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013199 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013200 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013201#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013202 case XPATH_OP_RANGETO:{
13203 xmlXPathObjectPtr range;
13204 xmlXPathObjectPtr res, obj;
13205 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013206 xmlLocationSetPtr newlocset = NULL;
13207 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013208 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013209 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013210
Daniel Veillardf06307e2001-07-03 10:35:50 +000013211 if (op->ch1 != -1)
13212 total +=
13213 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13214 if (op->ch2 == -1)
13215 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013216
William M. Brack08171912003-12-29 02:52:11 +000013217 if (ctxt->value->type == XPATH_LOCATIONSET) {
13218 /*
13219 * Extract the old locset, and then evaluate the result of the
13220 * expression for all the element in the locset. use it to grow
13221 * up a new locset.
13222 */
13223 CHECK_TYPE0(XPATH_LOCATIONSET);
13224 obj = valuePop(ctxt);
13225 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013226
William M. Brack08171912003-12-29 02:52:11 +000013227 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013228 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013229 ctxt->context->contextSize = 0;
13230 ctxt->context->proximityPosition = 0;
13231 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13232 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013233 if (res != NULL) {
13234 xmlXPathReleaseObject(ctxt->context, res);
13235 }
William M. Brack08171912003-12-29 02:52:11 +000013236 valuePush(ctxt, obj);
13237 CHECK_ERROR0;
13238 return (total);
13239 }
13240 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013241
William M. Brack08171912003-12-29 02:52:11 +000013242 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013243 /*
William M. Brack08171912003-12-29 02:52:11 +000013244 * Run the evaluation with a node list made of a
13245 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013246 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013247 ctxt->context->node = oldlocset->locTab[i]->user;
13248 ctxt->context->contextSize = oldlocset->locNr;
13249 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013250 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13251 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013252 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013253
Daniel Veillardf06307e2001-07-03 10:35:50 +000013254 if (op->ch2 != -1)
13255 total +=
13256 xmlXPathCompOpEval(ctxt,
13257 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013258 if (ctxt->error != XPATH_EXPRESSION_OK) {
13259 xmlXPathFreeObject(obj);
13260 return(0);
13261 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013262
Daniel Veillardf06307e2001-07-03 10:35:50 +000013263 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013264 if (res->type == XPATH_LOCATIONSET) {
13265 xmlLocationSetPtr rloc =
13266 (xmlLocationSetPtr)res->user;
13267 for (j=0; j<rloc->locNr; j++) {
13268 range = xmlXPtrNewRange(
13269 oldlocset->locTab[i]->user,
13270 oldlocset->locTab[i]->index,
13271 rloc->locTab[j]->user2,
13272 rloc->locTab[j]->index2);
13273 if (range != NULL) {
13274 xmlXPtrLocationSetAdd(newlocset, range);
13275 }
13276 }
13277 } else {
13278 range = xmlXPtrNewRangeNodeObject(
13279 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13280 if (range != NULL) {
13281 xmlXPtrLocationSetAdd(newlocset,range);
13282 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013283 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013284
Daniel Veillardf06307e2001-07-03 10:35:50 +000013285 /*
13286 * Cleanup
13287 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013288 if (res != NULL) {
13289 xmlXPathReleaseObject(ctxt->context, res);
13290 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013291 if (ctxt->value == tmp) {
13292 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013293 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013294 }
13295
13296 ctxt->context->node = NULL;
13297 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013298 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013299 CHECK_TYPE0(XPATH_NODESET);
13300 obj = valuePop(ctxt);
13301 oldset = obj->nodesetval;
13302 ctxt->context->node = NULL;
13303
13304 newlocset = xmlXPtrLocationSetCreate(NULL);
13305
13306 if (oldset != NULL) {
13307 for (i = 0; i < oldset->nodeNr; i++) {
13308 /*
13309 * Run the evaluation with a node list made of a single item
13310 * in the nodeset.
13311 */
13312 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013313 /*
13314 * OPTIMIZE TODO: Avoid recreation for every iteration.
13315 */
13316 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13317 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013318 valuePush(ctxt, tmp);
13319
13320 if (op->ch2 != -1)
13321 total +=
13322 xmlXPathCompOpEval(ctxt,
13323 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013324 if (ctxt->error != XPATH_EXPRESSION_OK) {
13325 xmlXPathFreeObject(obj);
13326 return(0);
13327 }
William M. Brack08171912003-12-29 02:52:11 +000013328
William M. Brack08171912003-12-29 02:52:11 +000013329 res = valuePop(ctxt);
13330 range =
13331 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13332 res);
13333 if (range != NULL) {
13334 xmlXPtrLocationSetAdd(newlocset, range);
13335 }
13336
13337 /*
13338 * Cleanup
13339 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013340 if (res != NULL) {
13341 xmlXPathReleaseObject(ctxt->context, res);
13342 }
William M. Brack08171912003-12-29 02:52:11 +000013343 if (ctxt->value == tmp) {
13344 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013345 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013346 }
13347
13348 ctxt->context->node = NULL;
13349 }
13350 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013351 }
13352
13353 /*
13354 * The result is used as the new evaluation set.
13355 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013356 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013357 ctxt->context->node = NULL;
13358 ctxt->context->contextSize = -1;
13359 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013360 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013361 return (total);
13362 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013363#endif /* LIBXML_XPTR_ENABLED */
13364 }
13365 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013366 "XPath: unknown precompiled operation %d\n", op->op);
13367 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013368}
13369
Daniel Veillard56de87e2005-02-16 00:22:29 +000013370#ifdef XPATH_STREAMING
13371/**
13372 * xmlXPathRunStreamEval:
13373 * @ctxt: the XPath parser context with the compiled expression
13374 *
13375 * Evaluate the Precompiled Streamable XPath expression in the given context.
13376 */
13377static xmlXPathObjectPtr
13378xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013379 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013380 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013381 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013382#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13383 int eval_all_nodes;
13384#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000013385 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013386 xmlXPathObjectPtr retval;
13387 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013388
13389 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013390
13391 if ((ctxt == NULL) || (comp == NULL))
13392 return(NULL);
13393 max_depth = xmlPatternMaxDepth(comp);
13394 if (max_depth == -1)
13395 return(NULL);
13396 if (max_depth == -2)
13397 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013398 min_depth = xmlPatternMinDepth(comp);
13399 if (min_depth == -1)
13400 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013401 from_root = xmlPatternFromRoot(comp);
13402 if (from_root < 0)
13403 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013404#if 0
13405 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13406#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013407
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013408 retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013409 if (retval == NULL)
13410 return(NULL);
13411
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013412 /*
13413 * handle the special cases of / amd . being matched
13414 */
13415 if (min_depth == 0) {
13416 if (from_root) {
13417 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
13418 } else {
13419 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
13420 }
13421 }
13422 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013423 return(retval);
13424 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013425
Daniel Veillard56de87e2005-02-16 00:22:29 +000013426 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013427 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013428 } else if (ctxt->node != NULL) {
13429 switch (ctxt->node->type) {
13430 case XML_ELEMENT_NODE:
13431 case XML_DOCUMENT_NODE:
13432 case XML_DOCUMENT_FRAG_NODE:
13433 case XML_HTML_DOCUMENT_NODE:
13434#ifdef LIBXML_DOCB_ENABLED
13435 case XML_DOCB_DOCUMENT_NODE:
13436#endif
13437 cur = ctxt->node;
13438 break;
13439 case XML_ATTRIBUTE_NODE:
13440 case XML_TEXT_NODE:
13441 case XML_CDATA_SECTION_NODE:
13442 case XML_ENTITY_REF_NODE:
13443 case XML_ENTITY_NODE:
13444 case XML_PI_NODE:
13445 case XML_COMMENT_NODE:
13446 case XML_NOTATION_NODE:
13447 case XML_DTD_NODE:
13448 case XML_DOCUMENT_TYPE_NODE:
13449 case XML_ELEMENT_DECL:
13450 case XML_ATTRIBUTE_DECL:
13451 case XML_ENTITY_DECL:
13452 case XML_NAMESPACE_DECL:
13453 case XML_XINCLUDE_START:
13454 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013455 break;
13456 }
13457 limit = cur;
13458 }
13459 if (cur == NULL)
13460 return(retval);
13461
13462 patstream = xmlPatternGetStreamCtxt(comp);
13463 if (patstream == NULL) {
13464 return(retval);
13465 }
13466
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013467#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13468 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13469#endif
13470
Daniel Veillard56de87e2005-02-16 00:22:29 +000013471 if (from_root) {
13472 ret = xmlStreamPush(patstream, NULL, NULL);
13473 if (ret < 0) {
13474 } else if (ret == 1) {
13475 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13476 }
13477 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013478 depth = 0;
13479 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013480next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013481 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013482 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013483
13484 switch (cur->type) {
13485 case XML_ELEMENT_NODE:
13486#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13487 case XML_TEXT_NODE:
13488 case XML_CDATA_SECTION_NODE:
13489 case XML_COMMENT_NODE:
13490 case XML_PI_NODE:
13491#endif
13492 if (cur->type == XML_ELEMENT_NODE) {
13493 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013494 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000013495 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013496#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13497 else if (eval_all_nodes)
13498 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13499 else
13500 break;
13501#endif
13502
13503 if (ret < 0) {
13504 /* NOP. */
13505 } else if (ret == 1) {
13506 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13507 }
13508 if ((cur->children == NULL) || (depth >= max_depth)) {
13509 ret = xmlStreamPop(patstream);
13510 while (cur->next != NULL) {
13511 cur = cur->next;
13512 if ((cur->type != XML_ENTITY_DECL) &&
13513 (cur->type != XML_DTD_NODE))
13514 goto next_node;
13515 }
13516 }
13517 default:
13518 break;
13519 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013520
13521scan_children:
13522 if ((cur->children != NULL) && (depth < max_depth)) {
13523 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013524 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000013525 */
13526 if (cur->children->type != XML_ENTITY_DECL) {
13527 cur = cur->children;
13528 depth++;
13529 /*
13530 * Skip DTDs
13531 */
13532 if (cur->type != XML_DTD_NODE)
13533 continue;
13534 }
13535 }
13536
13537 if (cur == limit)
13538 break;
13539
13540 while (cur->next != NULL) {
13541 cur = cur->next;
13542 if ((cur->type != XML_ENTITY_DECL) &&
13543 (cur->type != XML_DTD_NODE))
13544 goto next_node;
13545 }
13546
13547 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013548 cur = cur->parent;
13549 depth--;
13550 if ((cur == NULL) || (cur == limit))
13551 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013552 if (cur->type == XML_ELEMENT_NODE) {
13553 ret = xmlStreamPop(patstream);
13554 }
13555#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13556 else if ((eval_all_nodes) &&
13557 ((cur->type == XML_TEXT_NODE) ||
13558 (cur->type == XML_CDATA_SECTION_NODE) ||
13559 (cur->type == XML_COMMENT_NODE) ||
13560 (cur->type == XML_PI_NODE)))
13561 {
13562 ret = xmlStreamPop(patstream);
13563 }
13564#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013565 if (cur->next != NULL) {
13566 cur = cur->next;
13567 break;
13568 }
13569 } while (cur != NULL);
13570
13571 } while ((cur != NULL) && (depth >= 0));
13572done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013573#if 0
13574 printf("stream eval: checked %d nodes selected %d\n",
13575 nb_nodes, retval->nodesetval->nodeNr);
13576#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013577 xmlFreeStreamCtxt(patstream);
13578 return(retval);
13579}
13580#endif /* XPATH_STREAMING */
13581
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013582/**
13583 * xmlXPathRunEval:
13584 * @ctxt: the XPath parser context with the compiled expression
13585 *
13586 * Evaluate the Precompiled XPath expression in the given context.
13587 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013588static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013589xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
13590 xmlXPathCompExprPtr comp;
13591
13592 if ((ctxt == NULL) || (ctxt->comp == NULL))
13593 return;
13594
13595 if (ctxt->valueTab == NULL) {
13596 /* Allocate the value stack */
13597 ctxt->valueTab = (xmlXPathObjectPtr *)
13598 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13599 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000013600 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013601 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013602 }
13603 ctxt->valueNr = 0;
13604 ctxt->valueMax = 10;
13605 ctxt->value = NULL;
13606 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013607#ifdef XPATH_STREAMING
13608 if (ctxt->comp->stream) {
13609 xmlXPathObjectPtr ret;
13610 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
13611 if (ret != NULL) {
13612 valuePush(ctxt, ret);
13613 return;
13614 }
13615 }
13616#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013617 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013618 if(comp->last < 0) {
13619 xmlGenericError(xmlGenericErrorContext,
13620 "xmlXPathRunEval: last is less than zero\n");
13621 return;
13622 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013623 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13624}
13625
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013626/************************************************************************
13627 * *
13628 * Public interfaces *
13629 * *
13630 ************************************************************************/
13631
13632/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013633 * xmlXPathEvalPredicate:
13634 * @ctxt: the XPath context
13635 * @res: the Predicate Expression evaluation result
13636 *
13637 * Evaluate a predicate result for the current node.
13638 * A PredicateExpr is evaluated by evaluating the Expr and converting
13639 * the result to a boolean. If the result is a number, the result will
13640 * be converted to true if the number is equal to the position of the
13641 * context node in the context node list (as returned by the position
13642 * function) and will be converted to false otherwise; if the result
13643 * is not a number, then the result will be converted as if by a call
13644 * to the boolean function.
13645 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013646 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013647 */
13648int
13649xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013650 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013651 switch (res->type) {
13652 case XPATH_BOOLEAN:
13653 return(res->boolval);
13654 case XPATH_NUMBER:
13655 return(res->floatval == ctxt->proximityPosition);
13656 case XPATH_NODESET:
13657 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013658 if (res->nodesetval == NULL)
13659 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013660 return(res->nodesetval->nodeNr != 0);
13661 case XPATH_STRING:
13662 return((res->stringval != NULL) &&
13663 (xmlStrlen(res->stringval) != 0));
13664 default:
13665 STRANGE
13666 }
13667 return(0);
13668}
13669
13670/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013671 * xmlXPathEvaluatePredicateResult:
13672 * @ctxt: the XPath Parser context
13673 * @res: the Predicate Expression evaluation result
13674 *
13675 * Evaluate a predicate result for the current node.
13676 * A PredicateExpr is evaluated by evaluating the Expr and converting
13677 * the result to a boolean. If the result is a number, the result will
13678 * be converted to true if the number is equal to the position of the
13679 * context node in the context node list (as returned by the position
13680 * function) and will be converted to false otherwise; if the result
13681 * is not a number, then the result will be converted as if by a call
13682 * to the boolean function.
13683 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013684 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013685 */
13686int
13687xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13688 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013689 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013690 switch (res->type) {
13691 case XPATH_BOOLEAN:
13692 return(res->boolval);
13693 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000013694#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000013695 return((res->floatval == ctxt->context->proximityPosition) &&
13696 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000013697#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013698 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000013699#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013700 case XPATH_NODESET:
13701 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000013702 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000013703 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013704 return(res->nodesetval->nodeNr != 0);
13705 case XPATH_STRING:
13706 return((res->stringval != NULL) &&
13707 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000013708#ifdef LIBXML_XPTR_ENABLED
13709 case XPATH_LOCATIONSET:{
13710 xmlLocationSetPtr ptr = res->user;
13711 if (ptr == NULL)
13712 return(0);
13713 return (ptr->locNr != 0);
13714 }
13715#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013716 default:
13717 STRANGE
13718 }
13719 return(0);
13720}
13721
Daniel Veillard56de87e2005-02-16 00:22:29 +000013722#ifdef XPATH_STREAMING
13723/**
13724 * xmlXPathTryStreamCompile:
13725 * @ctxt: an XPath context
13726 * @str: the XPath expression
13727 *
13728 * Try to compile the XPath expression as a streamable subset.
13729 *
13730 * Returns the compiled expression or NULL if failed to compile.
13731 */
13732static xmlXPathCompExprPtr
13733xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13734 /*
13735 * Optimization: use streaming patterns when the XPath expression can
13736 * be compiled to a stream lookup
13737 */
13738 xmlPatternPtr stream;
13739 xmlXPathCompExprPtr comp;
13740 xmlDictPtr dict = NULL;
13741 const xmlChar **namespaces = NULL;
13742 xmlNsPtr ns;
13743 int i, j;
13744
13745 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13746 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013747 const xmlChar *tmp;
13748
13749 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013750 * We don't try to handle expressions using the verbose axis
13751 * specifiers ("::"), just the simplied form at this point.
13752 * Additionally, if there is no list of namespaces available and
13753 * there's a ":" in the expression, indicating a prefixed QName,
13754 * then we won't try to compile either. xmlPatterncompile() needs
13755 * to have a list of namespaces at compilation time in order to
13756 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013757 */
13758 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013759 if ((tmp != NULL) &&
13760 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13761 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013762
Daniel Veillard56de87e2005-02-16 00:22:29 +000013763 if (ctxt != NULL) {
13764 dict = ctxt->dict;
13765 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000013766 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000013767 if (namespaces == NULL) {
13768 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
13769 return(NULL);
13770 }
13771 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
13772 ns = ctxt->namespaces[j];
13773 namespaces[i++] = ns->href;
13774 namespaces[i++] = ns->prefix;
13775 }
13776 namespaces[i++] = NULL;
13777 namespaces[i++] = NULL;
13778 }
13779 }
13780
William M. Brackea152c02005-06-09 18:12:28 +000013781 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
13782 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013783 if (namespaces != NULL) {
13784 xmlFree((xmlChar **)namespaces);
13785 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013786 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
13787 comp = xmlXPathNewCompExpr();
13788 if (comp == NULL) {
13789 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
13790 return(NULL);
13791 }
13792 comp->stream = stream;
13793 comp->dict = dict;
13794 if (comp->dict)
13795 xmlDictReference(comp->dict);
13796 return(comp);
13797 }
13798 xmlFreePattern(stream);
13799 }
13800 return(NULL);
13801}
13802#endif /* XPATH_STREAMING */
13803
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013804/**
Daniel Veillard4773df22004-01-23 13:15:13 +000013805 * xmlXPathCtxtCompile:
13806 * @ctxt: an XPath context
13807 * @str: the XPath expression
13808 *
13809 * Compile an XPath expression
13810 *
13811 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13812 * the caller has to free the object.
13813 */
13814xmlXPathCompExprPtr
13815xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13816 xmlXPathParserContextPtr pctxt;
13817 xmlXPathCompExprPtr comp;
13818
Daniel Veillard56de87e2005-02-16 00:22:29 +000013819#ifdef XPATH_STREAMING
13820 comp = xmlXPathTryStreamCompile(ctxt, str);
13821 if (comp != NULL)
13822 return(comp);
13823#endif
13824
Daniel Veillard4773df22004-01-23 13:15:13 +000013825 xmlXPathInit();
13826
13827 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013828 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000013829
13830 if( pctxt->error != XPATH_EXPRESSION_OK )
13831 {
13832 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000013833 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000013834 }
13835
13836 if (*pctxt->cur != 0) {
13837 /*
13838 * aleksey: in some cases this line prints *second* error message
13839 * (see bug #78858) and probably this should be fixed.
13840 * However, we are not sure that all error messages are printed
13841 * out in other places. It's not critical so we leave it as-is for now
13842 */
13843 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13844 comp = NULL;
13845 } else {
13846 comp = pctxt->comp;
13847 pctxt->comp = NULL;
13848 }
13849 xmlXPathFreeParserContext(pctxt);
13850 if (comp != NULL) {
13851 comp->expr = xmlStrdup(str);
13852#ifdef DEBUG_EVAL_COUNTS
13853 comp->string = xmlStrdup(str);
13854 comp->nb = 0;
13855#endif
13856 }
13857 return(comp);
13858}
13859
13860/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013861 * xmlXPathCompile:
13862 * @str: the XPath expression
13863 *
13864 * Compile an XPath expression
13865 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000013866 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013867 * the caller has to free the object.
13868 */
13869xmlXPathCompExprPtr
13870xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000013871 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013872}
13873
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013874/**
13875 * xmlXPathCompiledEval:
13876 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000013877 * @ctx: the XPath context
13878 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013879 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000013880 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013881 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000013882 * the caller has to free the object.
13883 */
13884xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013885xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000013886 xmlXPathParserContextPtr ctxt;
13887 xmlXPathObjectPtr res, tmp, init = NULL;
13888 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000013889#ifndef LIBXML_THREAD_ENABLED
13890 static int reentance = 0;
13891#endif
Owen Taylor3473f882001-02-23 17:55:21 +000013892
William M. Brackf13f77f2004-11-12 16:03:48 +000013893 CHECK_CTXT(ctx)
13894
13895 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013896 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000013897 xmlXPathInit();
13898
Daniel Veillard81463942001-10-16 12:34:39 +000013899#ifndef LIBXML_THREAD_ENABLED
13900 reentance++;
13901 if (reentance > 1)
13902 xmlXPathDisableOptimizer = 1;
13903#endif
13904
Daniel Veillardf06307e2001-07-03 10:35:50 +000013905#ifdef DEBUG_EVAL_COUNTS
13906 comp->nb++;
13907 if ((comp->string != NULL) && (comp->nb > 100)) {
13908 fprintf(stderr, "100 x %s\n", comp->string);
13909 comp->nb = 0;
13910 }
13911#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013912 ctxt = xmlXPathCompParserContext(comp, ctx);
13913 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000013914
13915 if (ctxt->value == NULL) {
13916 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013917 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000013918 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000013919 } else {
13920 res = valuePop(ctxt);
13921 }
13922
Daniel Veillardf06307e2001-07-03 10:35:50 +000013923
Owen Taylor3473f882001-02-23 17:55:21 +000013924 do {
13925 tmp = valuePop(ctxt);
13926 if (tmp != NULL) {
13927 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013928 stack++;
13929 xmlXPathReleaseObject(ctx, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000013930 }
13931 } while (tmp != NULL);
13932 if ((stack != 0) && (res != NULL)) {
13933 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013934 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000013935 stack);
13936 }
13937 if (ctxt->error != XPATH_EXPRESSION_OK) {
13938 xmlXPathFreeObject(res);
13939 res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013940 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013941 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013942 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000013943#ifndef LIBXML_THREAD_ENABLED
13944 reentance--;
13945#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013946 return(res);
13947}
13948
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013949/**
13950 * xmlXPathEvalExpr:
13951 * @ctxt: the XPath Parser context
13952 *
13953 * Parse and evaluate an XPath expression in the given context,
13954 * then push the result on the context stack
13955 */
13956void
13957xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013958#ifdef XPATH_STREAMING
13959 xmlXPathCompExprPtr comp;
13960#endif
13961
Daniel Veillarda82b1822004-11-08 16:24:57 +000013962 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013963
13964#ifdef XPATH_STREAMING
13965 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13966 if (comp != NULL) {
13967 if (ctxt->comp != NULL)
13968 xmlXPathFreeCompExpr(ctxt->comp);
13969 ctxt->comp = comp;
13970 if (ctxt->cur != NULL)
13971 while (*ctxt->cur != 0) ctxt->cur++;
13972 } else
13973#endif
13974 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013975 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013976 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000013977 CHECK_ERROR;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000013978 xmlXPathRunEval(ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013979}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013980
13981/**
13982 * xmlXPathEval:
13983 * @str: the XPath expression
13984 * @ctx: the XPath context
13985 *
13986 * Evaluate the XPath Location Path in the given context.
13987 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013988 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013989 * the caller has to free the object.
13990 */
13991xmlXPathObjectPtr
13992xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13993 xmlXPathParserContextPtr ctxt;
13994 xmlXPathObjectPtr res, tmp, init = NULL;
13995 int stack = 0;
13996
William M. Brackf13f77f2004-11-12 16:03:48 +000013997 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013998
William M. Brackf13f77f2004-11-12 16:03:48 +000013999 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014000
14001 ctxt = xmlXPathNewParserContext(str, ctx);
14002 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014003
14004 if (ctxt->value == NULL) {
14005 xmlGenericError(xmlGenericErrorContext,
14006 "xmlXPathEval: evaluation failed\n");
14007 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014008 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14009#ifdef XPATH_STREAMING
14010 && (ctxt->comp->stream == NULL)
14011#endif
14012 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014013 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14014 res = NULL;
14015 } else {
14016 res = valuePop(ctxt);
14017 }
14018
14019 do {
14020 tmp = valuePop(ctxt);
14021 if (tmp != NULL) {
14022 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014023 stack++;
14024 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014025 }
14026 } while (tmp != NULL);
14027 if ((stack != 0) && (res != NULL)) {
14028 xmlGenericError(xmlGenericErrorContext,
14029 "xmlXPathEval: %d object left on the stack\n",
14030 stack);
14031 }
14032 if (ctxt->error != XPATH_EXPRESSION_OK) {
14033 xmlXPathFreeObject(res);
14034 res = NULL;
14035 }
14036
Owen Taylor3473f882001-02-23 17:55:21 +000014037 xmlXPathFreeParserContext(ctxt);
14038 return(res);
14039}
14040
14041/**
14042 * xmlXPathEvalExpression:
14043 * @str: the XPath expression
14044 * @ctxt: the XPath context
14045 *
14046 * Evaluate the XPath expression in the given context.
14047 *
14048 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14049 * the caller has to free the object.
14050 */
14051xmlXPathObjectPtr
14052xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14053 xmlXPathParserContextPtr pctxt;
14054 xmlXPathObjectPtr res, tmp;
14055 int stack = 0;
14056
William M. Brackf13f77f2004-11-12 16:03:48 +000014057 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014058
William M. Brackf13f77f2004-11-12 16:03:48 +000014059 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014060
14061 pctxt = xmlXPathNewParserContext(str, ctxt);
14062 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014063
14064 if (*pctxt->cur != 0) {
14065 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14066 res = NULL;
14067 } else {
14068 res = valuePop(pctxt);
14069 }
14070 do {
14071 tmp = valuePop(pctxt);
14072 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014073 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014074 stack++;
14075 }
14076 } while (tmp != NULL);
14077 if ((stack != 0) && (res != NULL)) {
14078 xmlGenericError(xmlGenericErrorContext,
14079 "xmlXPathEvalExpression: %d object left on the stack\n",
14080 stack);
14081 }
14082 xmlXPathFreeParserContext(pctxt);
14083 return(res);
14084}
14085
Daniel Veillard42766c02002-08-22 20:52:17 +000014086/************************************************************************
14087 * *
14088 * Extra functions not pertaining to the XPath spec *
14089 * *
14090 ************************************************************************/
14091/**
14092 * xmlXPathEscapeUriFunction:
14093 * @ctxt: the XPath Parser context
14094 * @nargs: the number of arguments
14095 *
14096 * Implement the escape-uri() XPath function
14097 * string escape-uri(string $str, bool $escape-reserved)
14098 *
14099 * This function applies the URI escaping rules defined in section 2 of [RFC
14100 * 2396] to the string supplied as $uri-part, which typically represents all
14101 * or part of a URI. The effect of the function is to replace any special
14102 * character in the string by an escape sequence of the form %xx%yy...,
14103 * where xxyy... is the hexadecimal representation of the octets used to
14104 * represent the character in UTF-8.
14105 *
14106 * The set of characters that are escaped depends on the setting of the
14107 * boolean argument $escape-reserved.
14108 *
14109 * If $escape-reserved is true, all characters are escaped other than lower
14110 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14111 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14112 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14113 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14114 * A-F).
14115 *
14116 * If $escape-reserved is false, the behavior differs in that characters
14117 * referred to in [RFC 2396] as reserved characters are not escaped. These
14118 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14119 *
14120 * [RFC 2396] does not define whether escaped URIs should use lower case or
14121 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14122 * compared using string comparison functions, this function must always use
14123 * the upper-case letters A-F.
14124 *
14125 * Generally, $escape-reserved should be set to true when escaping a string
14126 * that is to form a single part of a URI, and to false when escaping an
14127 * entire URI or URI reference.
14128 *
14129 * In the case of non-ascii characters, the string is encoded according to
14130 * utf-8 and then converted according to RFC 2396.
14131 *
14132 * Examples
14133 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14134 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14135 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14136 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14137 *
14138 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014139static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014140xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14141 xmlXPathObjectPtr str;
14142 int escape_reserved;
14143 xmlBufferPtr target;
14144 xmlChar *cptr;
14145 xmlChar escape[4];
14146
14147 CHECK_ARITY(2);
14148
14149 escape_reserved = xmlXPathPopBoolean(ctxt);
14150
14151 CAST_TO_STRING;
14152 str = valuePop(ctxt);
14153
14154 target = xmlBufferCreate();
14155
14156 escape[0] = '%';
14157 escape[3] = 0;
14158
14159 if (target) {
14160 for (cptr = str->stringval; *cptr; cptr++) {
14161 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14162 (*cptr >= 'a' && *cptr <= 'z') ||
14163 (*cptr >= '0' && *cptr <= '9') ||
14164 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14165 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14166 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14167 (*cptr == '%' &&
14168 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14169 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14170 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14171 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14172 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14173 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14174 (!escape_reserved &&
14175 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14176 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14177 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14178 *cptr == ','))) {
14179 xmlBufferAdd(target, cptr, 1);
14180 } else {
14181 if ((*cptr >> 4) < 10)
14182 escape[1] = '0' + (*cptr >> 4);
14183 else
14184 escape[1] = 'A' - 10 + (*cptr >> 4);
14185 if ((*cptr & 0xF) < 10)
14186 escape[2] = '0' + (*cptr & 0xF);
14187 else
14188 escape[2] = 'A' - 10 + (*cptr & 0xF);
14189
14190 xmlBufferAdd(target, &escape[0], 3);
14191 }
14192 }
14193 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014194 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14195 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014196 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014197 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014198}
14199
Owen Taylor3473f882001-02-23 17:55:21 +000014200/**
14201 * xmlXPathRegisterAllFunctions:
14202 * @ctxt: the XPath context
14203 *
14204 * Registers all default XPath functions in this context
14205 */
14206void
14207xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14208{
14209 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14210 xmlXPathBooleanFunction);
14211 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14212 xmlXPathCeilingFunction);
14213 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14214 xmlXPathCountFunction);
14215 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14216 xmlXPathConcatFunction);
14217 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14218 xmlXPathContainsFunction);
14219 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14220 xmlXPathIdFunction);
14221 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14222 xmlXPathFalseFunction);
14223 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14224 xmlXPathFloorFunction);
14225 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14226 xmlXPathLastFunction);
14227 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14228 xmlXPathLangFunction);
14229 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14230 xmlXPathLocalNameFunction);
14231 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14232 xmlXPathNotFunction);
14233 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14234 xmlXPathNameFunction);
14235 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14236 xmlXPathNamespaceURIFunction);
14237 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14238 xmlXPathNormalizeFunction);
14239 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14240 xmlXPathNumberFunction);
14241 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14242 xmlXPathPositionFunction);
14243 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14244 xmlXPathRoundFunction);
14245 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14246 xmlXPathStringFunction);
14247 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14248 xmlXPathStringLengthFunction);
14249 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14250 xmlXPathStartsWithFunction);
14251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14252 xmlXPathSubstringFunction);
14253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14254 xmlXPathSubstringBeforeFunction);
14255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14256 xmlXPathSubstringAfterFunction);
14257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14258 xmlXPathSumFunction);
14259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14260 xmlXPathTrueFunction);
14261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14262 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014263
14264 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14265 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14266 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014267}
14268
14269#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014270#define bottom_xpath
14271#include "elfgcchack.h"