blob: c6c227448ac33cd06e64ea2dbd71adce1ffd4d9e [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 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +0000371
372 /* cleanup current last error */
373 xmlResetError(&ctxt->context->lastError);
374
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000375 ctxt->context->lastError.domain = XML_FROM_XPATH;
376 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
377 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000378 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000379 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
380 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
381 ctxt->context->lastError.node = ctxt->context->debugNode;
382 if (ctxt->context->error != NULL) {
383 ctxt->context->error(ctxt->context->userData,
384 &ctxt->context->lastError);
385 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000386 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000387 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
388 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
389 XML_ERR_ERROR, NULL, 0,
390 (const char *) ctxt->base, NULL, NULL,
391 ctxt->cur - ctxt->base, 0,
392 xmlXPathErrorMessages[error]);
393 }
394
395}
396
397/**
398 * xmlXPatherror:
399 * @ctxt: the XPath Parser context
400 * @file: the file name
401 * @line: the line number
402 * @no: the error number
403 *
404 * Formats an error message.
405 */
406void
407xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
408 int line ATTRIBUTE_UNUSED, int no) {
409 xmlXPathErr(ctxt, no);
410}
411
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000412/************************************************************************
413 * *
414 * Utilities *
415 * *
416 ************************************************************************/
417
418/**
419 * xsltPointerList:
420 *
421 * Pointer-list for various purposes.
422 */
423typedef struct _xmlPointerList xmlPointerList;
424typedef xmlPointerList *xmlPointerListPtr;
425struct _xmlPointerList {
426 void **items;
427 int number;
428 int size;
429};
430/*
431* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
432* and here, we should make the functions public.
433*/
434static int
435xmlPointerListAddSize(xmlPointerListPtr list,
436 void *item,
437 int initialSize)
438{
439 if (list->items == NULL) {
440 if (initialSize <= 0)
441 initialSize = 1;
442 list->items = (void **) xmlMalloc(
443 initialSize * sizeof(void *));
444 if (list->items == NULL) {
445 xmlXPathErrMemory(NULL,
446 "xmlPointerListCreate: allocating item\n");
447 return(-1);
448 }
449 list->number = 0;
450 list->size = initialSize;
451 } else if (list->size <= list->number) {
452 list->size *= 2;
453 list->items = (void **) xmlRealloc(list->items,
454 list->size * sizeof(void *));
455 if (list->items == NULL) {
456 xmlXPathErrMemory(NULL,
457 "xmlPointerListCreate: re-allocating item\n");
458 list->size = 0;
459 return(-1);
460 }
461 }
462 list->items[list->number++] = item;
463 return(0);
464}
465
466/**
467 * xsltPointerListCreate:
468 *
469 * Creates an xsltPointerList structure.
470 *
471 * Returns a xsltPointerList structure or NULL in case of an error.
472 */
473static xmlPointerListPtr
474xmlPointerListCreate(int initialSize)
475{
476 xmlPointerListPtr ret;
477
478 ret = xmlMalloc(sizeof(xmlPointerList));
479 if (ret == NULL) {
480 xmlXPathErrMemory(NULL,
481 "xmlPointerListCreate: allocating item\n");
482 return (NULL);
483 }
484 memset(ret, 0, sizeof(xmlPointerList));
485 if (initialSize > 0) {
486 xmlPointerListAddSize(ret, NULL, initialSize);
487 ret->number = 0;
488 }
489 return (ret);
490}
491
492/**
493 * xsltPointerListFree:
494 *
495 * Frees the xsltPointerList structure. This does not free
496 * the content of the list.
497 */
498static void
499xmlPointerListFree(xmlPointerListPtr list)
500{
501 if (list == NULL)
502 return;
503 if (list->items != NULL)
504 xmlFree(list->items);
505 xmlFree(list);
506}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000507
508/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 * *
510 * Parser Types *
511 * *
512 ************************************************************************/
513
514/*
515 * Types are private:
516 */
517
518typedef enum {
519 XPATH_OP_END=0,
520 XPATH_OP_AND,
521 XPATH_OP_OR,
522 XPATH_OP_EQUAL,
523 XPATH_OP_CMP,
524 XPATH_OP_PLUS,
525 XPATH_OP_MULT,
526 XPATH_OP_UNION,
527 XPATH_OP_ROOT,
528 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000529 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000530 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000531 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000532 XPATH_OP_VARIABLE,
533 XPATH_OP_FUNCTION,
534 XPATH_OP_ARG,
535 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000536 XPATH_OP_FILTER, /* 17 */
537 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538#ifdef LIBXML_XPTR_ENABLED
539 ,XPATH_OP_RANGETO
540#endif
541} xmlXPathOp;
542
543typedef enum {
544 AXIS_ANCESTOR = 1,
545 AXIS_ANCESTOR_OR_SELF,
546 AXIS_ATTRIBUTE,
547 AXIS_CHILD,
548 AXIS_DESCENDANT,
549 AXIS_DESCENDANT_OR_SELF,
550 AXIS_FOLLOWING,
551 AXIS_FOLLOWING_SIBLING,
552 AXIS_NAMESPACE,
553 AXIS_PARENT,
554 AXIS_PRECEDING,
555 AXIS_PRECEDING_SIBLING,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000556 AXIS_SELF
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000557} xmlXPathAxisVal;
558
559typedef enum {
560 NODE_TEST_NONE = 0,
561 NODE_TEST_TYPE = 1,
562 NODE_TEST_PI = 2,
563 NODE_TEST_ALL = 3,
564 NODE_TEST_NS = 4,
565 NODE_TEST_NAME = 5
566} xmlXPathTestVal;
567
568typedef enum {
569 NODE_TYPE_NODE = 0,
570 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
571 NODE_TYPE_TEXT = XML_TEXT_NODE,
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000572 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573} xmlXPathTypeVal;
574
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000575#define XP_REWRITE_DOS_CHILD_ELEM 1
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000576
577typedef struct _xmlXPathStepOp xmlXPathStepOp;
578typedef xmlXPathStepOp *xmlXPathStepOpPtr;
579struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000580 xmlXPathOp op; /* The identifier of the operation */
581 int ch1; /* First child */
582 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000583 int value;
584 int value2;
585 int value3;
586 void *value4;
587 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000588 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000589 void *cacheURI;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +0000590 int rewriteType;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000591};
592
593struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000594 int nbStep; /* Number of steps in this expression */
595 int maxStep; /* Maximum number of steps allocated */
596 xmlXPathStepOp *steps; /* ops for computation of this expression */
597 int last; /* index of last step in expression */
598 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000599 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000600#ifdef DEBUG_EVAL_COUNTS
601 int nb;
602 xmlChar *string;
603#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000604#ifdef XPATH_STREAMING
605 xmlPatternPtr stream;
606#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000607};
608
609/************************************************************************
610 * *
611 * Parser Type functions *
612 * *
613 ************************************************************************/
614
615/**
616 * xmlXPathNewCompExpr:
617 *
618 * Create a new Xpath component
619 *
620 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
621 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000622static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000623xmlXPathNewCompExpr(void) {
624 xmlXPathCompExprPtr cur;
625
626 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
627 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000628 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000629 return(NULL);
630 }
631 memset(cur, 0, sizeof(xmlXPathCompExpr));
632 cur->maxStep = 10;
633 cur->nbStep = 0;
634 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
635 sizeof(xmlXPathStepOp));
636 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000637 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000638 xmlFree(cur);
639 return(NULL);
640 }
641 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
642 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000643#ifdef DEBUG_EVAL_COUNTS
644 cur->nb = 0;
645#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000646 return(cur);
647}
648
649/**
650 * xmlXPathFreeCompExpr:
651 * @comp: an XPATH comp
652 *
653 * Free up the memory allocated by @comp
654 */
655void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000656xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
657{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000658 xmlXPathStepOpPtr op;
659 int i;
660
661 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000662 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000663 if (comp->dict == NULL) {
664 for (i = 0; i < comp->nbStep; i++) {
665 op = &comp->steps[i];
666 if (op->value4 != NULL) {
667 if (op->op == XPATH_OP_VALUE)
668 xmlXPathFreeObject(op->value4);
669 else
670 xmlFree(op->value4);
671 }
672 if (op->value5 != NULL)
673 xmlFree(op->value5);
674 }
675 } else {
676 for (i = 0; i < comp->nbStep; i++) {
677 op = &comp->steps[i];
678 if (op->value4 != NULL) {
679 if (op->op == XPATH_OP_VALUE)
680 xmlXPathFreeObject(op->value4);
681 }
682 }
683 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684 }
685 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000686 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000687 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000688#ifdef DEBUG_EVAL_COUNTS
689 if (comp->string != NULL) {
690 xmlFree(comp->string);
691 }
692#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000693#ifdef XPATH_STREAMING
694 if (comp->stream != NULL) {
695 xmlFreePatternList(comp->stream);
696 }
697#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000698 if (comp->expr != NULL) {
699 xmlFree(comp->expr);
700 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000701
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000702 xmlFree(comp);
703}
704
705/**
706 * xmlXPathCompExprAdd:
707 * @comp: the compiled expression
708 * @ch1: first child index
709 * @ch2: second child index
710 * @op: an op
711 * @value: the first int value
712 * @value2: the second int value
713 * @value3: the third int value
714 * @value4: the first string value
715 * @value5: the second string value
716 *
William M. Brack08171912003-12-29 02:52:11 +0000717 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000718 *
719 * Returns -1 in case of failure, the index otherwise
720 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000721static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000722xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
723 xmlXPathOp op, int value,
724 int value2, int value3, void *value4, void *value5) {
725 if (comp->nbStep >= comp->maxStep) {
726 xmlXPathStepOp *real;
727
728 comp->maxStep *= 2;
729 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
730 comp->maxStep * sizeof(xmlXPathStepOp));
731 if (real == NULL) {
732 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000733 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000734 return(-1);
735 }
736 comp->steps = real;
737 }
738 comp->last = comp->nbStep;
739 comp->steps[comp->nbStep].ch1 = ch1;
740 comp->steps[comp->nbStep].ch2 = ch2;
741 comp->steps[comp->nbStep].op = op;
742 comp->steps[comp->nbStep].value = value;
743 comp->steps[comp->nbStep].value2 = value2;
744 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000745 if ((comp->dict != NULL) &&
746 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
747 (op == XPATH_OP_COLLECT))) {
748 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000749 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000750 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000751 xmlFree(value4);
752 } else
753 comp->steps[comp->nbStep].value4 = NULL;
754 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000755 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000756 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000757 xmlFree(value5);
758 } else
759 comp->steps[comp->nbStep].value5 = NULL;
760 } else {
761 comp->steps[comp->nbStep].value4 = value4;
762 comp->steps[comp->nbStep].value5 = value5;
763 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000764 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000765 return(comp->nbStep++);
766}
767
Daniel Veillardf06307e2001-07-03 10:35:50 +0000768/**
769 * xmlXPathCompSwap:
770 * @comp: the compiled expression
771 * @op: operation index
772 *
773 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000774 */
775static void
776xmlXPathCompSwap(xmlXPathStepOpPtr op) {
777 int tmp;
778
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000779#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000780 /*
781 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000782 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000783 * application
784 */
785 if (xmlXPathDisableOptimizer)
786 return;
787#endif
788
Daniel Veillardf06307e2001-07-03 10:35:50 +0000789 tmp = op->ch1;
790 op->ch1 = op->ch2;
791 op->ch2 = tmp;
792}
793
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000794#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
795 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
796 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000797#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
798 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
799 (op), (val), (val2), (val3), (val4), (val5))
800
801#define PUSH_LEAVE_EXPR(op, val, val2) \
802xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
803
804#define PUSH_UNARY_EXPR(op, ch, val, val2) \
805xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
806
807#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000808xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
809 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000810
811/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000812 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000813 * XPath object cache structures *
814 * *
815 ************************************************************************/
816
817/* #define XP_DEFAULT_CACHE_ON */
818
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000819#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000820
Kasimier T. Buchcik58694692006-05-31 12:37:28 +0000821typedef struct _xmlXPathContextCache xmlXPathContextCache;
822typedef xmlXPathContextCache *xmlXPathContextCachePtr;
823struct _xmlXPathContextCache {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +0000824 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
827 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
828 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +0000829 int maxNodeset;
830 int maxString;
831 int maxBoolean;
832 int maxNumber;
833 int maxMisc;
834#ifdef XP_DEBUG_OBJ_USAGE
835 int dbgCachedAll;
836 int dbgCachedNodeset;
837 int dbgCachedString;
838 int dbgCachedBool;
839 int dbgCachedNumber;
840 int dbgCachedPoint;
841 int dbgCachedRange;
842 int dbgCachedLocset;
843 int dbgCachedUsers;
844 int dbgCachedXSLTTree;
845 int dbgCachedUndefined;
846
847
848 int dbgReusedAll;
849 int dbgReusedNodeset;
850 int dbgReusedString;
851 int dbgReusedBool;
852 int dbgReusedNumber;
853 int dbgReusedPoint;
854 int dbgReusedRange;
855 int dbgReusedLocset;
856 int dbgReusedUsers;
857 int dbgReusedXSLTTree;
858 int dbgReusedUndefined;
859
860#endif
861};
862
863/************************************************************************
864 * *
Owen Taylor3473f882001-02-23 17:55:21 +0000865 * Debugging related functions *
866 * *
867 ************************************************************************/
868
Owen Taylor3473f882001-02-23 17:55:21 +0000869#define STRANGE \
870 xmlGenericError(xmlGenericErrorContext, \
871 "Internal error at %s:%d\n", \
872 __FILE__, __LINE__);
873
874#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000875static void
876xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000877 int i;
878 char shift[100];
879
880 for (i = 0;((i < depth) && (i < 25));i++)
881 shift[2 * i] = shift[2 * i + 1] = ' ';
882 shift[2 * i] = shift[2 * i + 1] = 0;
883 if (cur == NULL) {
884 fprintf(output, shift);
885 fprintf(output, "Node is NULL !\n");
886 return;
887
888 }
889
890 if ((cur->type == XML_DOCUMENT_NODE) ||
891 (cur->type == XML_HTML_DOCUMENT_NODE)) {
892 fprintf(output, shift);
893 fprintf(output, " /\n");
894 } else if (cur->type == XML_ATTRIBUTE_NODE)
895 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
896 else
897 xmlDebugDumpOneNode(output, cur, depth);
898}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000899static void
900xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000901 xmlNodePtr tmp;
902 int i;
903 char shift[100];
904
905 for (i = 0;((i < depth) && (i < 25));i++)
906 shift[2 * i] = shift[2 * i + 1] = ' ';
907 shift[2 * i] = shift[2 * i + 1] = 0;
908 if (cur == NULL) {
909 fprintf(output, shift);
910 fprintf(output, "Node is NULL !\n");
911 return;
912
913 }
914
915 while (cur != NULL) {
916 tmp = cur;
917 cur = cur->next;
918 xmlDebugDumpOneNode(output, tmp, depth);
919 }
920}
Owen Taylor3473f882001-02-23 17:55:21 +0000921
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000922static void
923xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000924 int i;
925 char shift[100];
926
927 for (i = 0;((i < depth) && (i < 25));i++)
928 shift[2 * i] = shift[2 * i + 1] = ' ';
929 shift[2 * i] = shift[2 * i + 1] = 0;
930
931 if (cur == NULL) {
932 fprintf(output, shift);
933 fprintf(output, "NodeSet is NULL !\n");
934 return;
935
936 }
937
Daniel Veillard911f49a2001-04-07 15:39:35 +0000938 if (cur != NULL) {
939 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
940 for (i = 0;i < cur->nodeNr;i++) {
941 fprintf(output, shift);
942 fprintf(output, "%d", i + 1);
943 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
944 }
Owen Taylor3473f882001-02-23 17:55:21 +0000945 }
946}
947
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000948static void
949xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000950 int i;
951 char shift[100];
952
953 for (i = 0;((i < depth) && (i < 25));i++)
954 shift[2 * i] = shift[2 * i + 1] = ' ';
955 shift[2 * i] = shift[2 * i + 1] = 0;
956
957 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
958 fprintf(output, shift);
959 fprintf(output, "Value Tree is NULL !\n");
960 return;
961
962 }
963
964 fprintf(output, shift);
965 fprintf(output, "%d", i + 1);
966 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
967}
Owen Taylor3473f882001-02-23 17:55:21 +0000968#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000969static void
970xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000971 int i;
972 char shift[100];
973
974 for (i = 0;((i < depth) && (i < 25));i++)
975 shift[2 * i] = shift[2 * i + 1] = ' ';
976 shift[2 * i] = shift[2 * i + 1] = 0;
977
978 if (cur == NULL) {
979 fprintf(output, shift);
980 fprintf(output, "LocationSet is NULL !\n");
981 return;
982
983 }
984
985 for (i = 0;i < cur->locNr;i++) {
986 fprintf(output, shift);
987 fprintf(output, "%d : ", i + 1);
988 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
989 }
990}
Daniel Veillard017b1082001-06-21 11:20:21 +0000991#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000992
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000993/**
994 * xmlXPathDebugDumpObject:
995 * @output: the FILE * to dump the output
996 * @cur: the object to inspect
997 * @depth: indentation level
998 *
999 * Dump the content of the object for debugging purposes
1000 */
1001void
1002xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +00001003 int i;
1004 char shift[100];
1005
Daniel Veillarda82b1822004-11-08 16:24:57 +00001006 if (output == NULL) return;
1007
Owen Taylor3473f882001-02-23 17:55:21 +00001008 for (i = 0;((i < depth) && (i < 25));i++)
1009 shift[2 * i] = shift[2 * i + 1] = ' ';
1010 shift[2 * i] = shift[2 * i + 1] = 0;
1011
Kasimier T. Buchcik97258712006-01-05 12:30:43 +00001012
1013 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +00001014
1015 if (cur == NULL) {
1016 fprintf(output, "Object is empty (NULL)\n");
1017 return;
1018 }
1019 switch(cur->type) {
1020 case XPATH_UNDEFINED:
1021 fprintf(output, "Object is uninitialized\n");
1022 break;
1023 case XPATH_NODESET:
1024 fprintf(output, "Object is a Node Set :\n");
1025 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1026 break;
1027 case XPATH_XSLT_TREE:
1028 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +00001029 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +00001030 break;
1031 case XPATH_BOOLEAN:
1032 fprintf(output, "Object is a Boolean : ");
1033 if (cur->boolval) fprintf(output, "true\n");
1034 else fprintf(output, "false\n");
1035 break;
1036 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +00001037 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001038 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001039 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001040 break;
1041 case -1:
1042 fprintf(output, "Object is a number : -Infinity\n");
1043 break;
1044 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001045 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +00001046 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001047 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1048 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +00001049 } else {
1050 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1051 }
1052 }
Owen Taylor3473f882001-02-23 17:55:21 +00001053 break;
1054 case XPATH_STRING:
1055 fprintf(output, "Object is a string : ");
1056 xmlDebugDumpString(output, cur->stringval);
1057 fprintf(output, "\n");
1058 break;
1059 case XPATH_POINT:
1060 fprintf(output, "Object is a point : index %d in node", cur->index);
1061 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1062 fprintf(output, "\n");
1063 break;
1064 case XPATH_RANGE:
1065 if ((cur->user2 == NULL) ||
1066 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1067 fprintf(output, "Object is a collapsed range :\n");
1068 fprintf(output, shift);
1069 if (cur->index >= 0)
1070 fprintf(output, "index %d in ", cur->index);
1071 fprintf(output, "node\n");
1072 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1073 depth + 1);
1074 } else {
1075 fprintf(output, "Object is a range :\n");
1076 fprintf(output, shift);
1077 fprintf(output, "From ");
1078 if (cur->index >= 0)
1079 fprintf(output, "index %d in ", cur->index);
1080 fprintf(output, "node\n");
1081 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1082 depth + 1);
1083 fprintf(output, shift);
1084 fprintf(output, "To ");
1085 if (cur->index2 >= 0)
1086 fprintf(output, "index %d in ", cur->index2);
1087 fprintf(output, "node\n");
1088 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1089 depth + 1);
1090 fprintf(output, "\n");
1091 }
1092 break;
1093 case XPATH_LOCATIONSET:
1094#if defined(LIBXML_XPTR_ENABLED)
1095 fprintf(output, "Object is a Location Set:\n");
1096 xmlXPathDebugDumpLocationSet(output,
1097 (xmlLocationSetPtr) cur->user, depth);
1098#endif
1099 break;
1100 case XPATH_USERS:
1101 fprintf(output, "Object is user defined\n");
1102 break;
1103 }
1104}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001105
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001106static void
1107xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001108 xmlXPathStepOpPtr op, int depth) {
1109 int i;
1110 char shift[100];
1111
1112 for (i = 0;((i < depth) && (i < 25));i++)
1113 shift[2 * i] = shift[2 * i + 1] = ' ';
1114 shift[2 * i] = shift[2 * i + 1] = 0;
1115
1116 fprintf(output, shift);
1117 if (op == NULL) {
1118 fprintf(output, "Step is NULL\n");
1119 return;
1120 }
1121 switch (op->op) {
1122 case XPATH_OP_END:
1123 fprintf(output, "END"); break;
1124 case XPATH_OP_AND:
1125 fprintf(output, "AND"); break;
1126 case XPATH_OP_OR:
1127 fprintf(output, "OR"); break;
1128 case XPATH_OP_EQUAL:
1129 if (op->value)
1130 fprintf(output, "EQUAL =");
1131 else
1132 fprintf(output, "EQUAL !=");
1133 break;
1134 case XPATH_OP_CMP:
1135 if (op->value)
1136 fprintf(output, "CMP <");
1137 else
1138 fprintf(output, "CMP >");
1139 if (!op->value2)
1140 fprintf(output, "=");
1141 break;
1142 case XPATH_OP_PLUS:
1143 if (op->value == 0)
1144 fprintf(output, "PLUS -");
1145 else if (op->value == 1)
1146 fprintf(output, "PLUS +");
1147 else if (op->value == 2)
1148 fprintf(output, "PLUS unary -");
1149 else if (op->value == 3)
1150 fprintf(output, "PLUS unary - -");
1151 break;
1152 case XPATH_OP_MULT:
1153 if (op->value == 0)
1154 fprintf(output, "MULT *");
1155 else if (op->value == 1)
1156 fprintf(output, "MULT div");
1157 else
1158 fprintf(output, "MULT mod");
1159 break;
1160 case XPATH_OP_UNION:
1161 fprintf(output, "UNION"); break;
1162 case XPATH_OP_ROOT:
1163 fprintf(output, "ROOT"); break;
1164 case XPATH_OP_NODE:
1165 fprintf(output, "NODE"); break;
1166 case XPATH_OP_RESET:
1167 fprintf(output, "RESET"); break;
1168 case XPATH_OP_SORT:
1169 fprintf(output, "SORT"); break;
1170 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001171 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1172 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1173 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001174 const xmlChar *prefix = op->value4;
1175 const xmlChar *name = op->value5;
1176
1177 fprintf(output, "COLLECT ");
1178 switch (axis) {
1179 case AXIS_ANCESTOR:
1180 fprintf(output, " 'ancestors' "); break;
1181 case AXIS_ANCESTOR_OR_SELF:
1182 fprintf(output, " 'ancestors-or-self' "); break;
1183 case AXIS_ATTRIBUTE:
1184 fprintf(output, " 'attributes' "); break;
1185 case AXIS_CHILD:
1186 fprintf(output, " 'child' "); break;
1187 case AXIS_DESCENDANT:
1188 fprintf(output, " 'descendant' "); break;
1189 case AXIS_DESCENDANT_OR_SELF:
1190 fprintf(output, " 'descendant-or-self' "); break;
1191 case AXIS_FOLLOWING:
1192 fprintf(output, " 'following' "); break;
1193 case AXIS_FOLLOWING_SIBLING:
1194 fprintf(output, " 'following-siblings' "); break;
1195 case AXIS_NAMESPACE:
1196 fprintf(output, " 'namespace' "); break;
1197 case AXIS_PARENT:
1198 fprintf(output, " 'parent' "); break;
1199 case AXIS_PRECEDING:
1200 fprintf(output, " 'preceding' "); break;
1201 case AXIS_PRECEDING_SIBLING:
1202 fprintf(output, " 'preceding-sibling' "); break;
1203 case AXIS_SELF:
1204 fprintf(output, " 'self' "); break;
1205 }
1206 switch (test) {
1207 case NODE_TEST_NONE:
1208 fprintf(output, "'none' "); break;
1209 case NODE_TEST_TYPE:
1210 fprintf(output, "'type' "); break;
1211 case NODE_TEST_PI:
1212 fprintf(output, "'PI' "); break;
1213 case NODE_TEST_ALL:
1214 fprintf(output, "'all' "); break;
1215 case NODE_TEST_NS:
1216 fprintf(output, "'namespace' "); break;
1217 case NODE_TEST_NAME:
1218 fprintf(output, "'name' "); break;
1219 }
1220 switch (type) {
1221 case NODE_TYPE_NODE:
1222 fprintf(output, "'node' "); break;
1223 case NODE_TYPE_COMMENT:
1224 fprintf(output, "'comment' "); break;
1225 case NODE_TYPE_TEXT:
1226 fprintf(output, "'text' "); break;
1227 case NODE_TYPE_PI:
1228 fprintf(output, "'PI' "); break;
1229 }
1230 if (prefix != NULL)
1231 fprintf(output, "%s:", prefix);
1232 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001233 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001234 break;
1235
1236 }
1237 case XPATH_OP_VALUE: {
1238 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1239
1240 fprintf(output, "ELEM ");
1241 xmlXPathDebugDumpObject(output, object, 0);
1242 goto finish;
1243 }
1244 case XPATH_OP_VARIABLE: {
1245 const xmlChar *prefix = op->value5;
1246 const xmlChar *name = op->value4;
1247
1248 if (prefix != NULL)
1249 fprintf(output, "VARIABLE %s:%s", prefix, name);
1250 else
1251 fprintf(output, "VARIABLE %s", name);
1252 break;
1253 }
1254 case XPATH_OP_FUNCTION: {
1255 int nbargs = op->value;
1256 const xmlChar *prefix = op->value5;
1257 const xmlChar *name = op->value4;
1258
1259 if (prefix != NULL)
1260 fprintf(output, "FUNCTION %s:%s(%d args)",
1261 prefix, name, nbargs);
1262 else
1263 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1264 break;
1265 }
1266 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1267 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001268 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001269#ifdef LIBXML_XPTR_ENABLED
1270 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1271#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001272 default:
1273 fprintf(output, "UNKNOWN %d\n", op->op); return;
1274 }
1275 fprintf(output, "\n");
1276finish:
1277 if (op->ch1 >= 0)
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1279 if (op->ch2 >= 0)
1280 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1281}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001282
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001283/**
1284 * xmlXPathDebugDumpCompExpr:
1285 * @output: the FILE * for the output
1286 * @comp: the precompiled XPath expression
1287 * @depth: the indentation level.
1288 *
1289 * Dumps the tree of the compiled XPath expression.
1290 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001291void
1292xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1293 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001294 int i;
1295 char shift[100];
1296
Daniel Veillarda82b1822004-11-08 16:24:57 +00001297 if ((output == NULL) || (comp == NULL)) return;
1298
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001299 for (i = 0;((i < depth) && (i < 25));i++)
1300 shift[2 * i] = shift[2 * i + 1] = ' ';
1301 shift[2 * i] = shift[2 * i + 1] = 0;
1302
1303 fprintf(output, shift);
1304
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001305 fprintf(output, "Compiled Expression : %d elements\n",
1306 comp->nbStep);
1307 i = comp->last;
1308 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1309}
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001310
1311#ifdef XP_DEBUG_OBJ_USAGE
1312
1313/*
1314* XPath object usage related debugging variables.
1315*/
1316static int xmlXPathDebugObjCounterUndefined = 0;
1317static int xmlXPathDebugObjCounterNodeset = 0;
1318static int xmlXPathDebugObjCounterBool = 0;
1319static int xmlXPathDebugObjCounterNumber = 0;
1320static int xmlXPathDebugObjCounterString = 0;
1321static int xmlXPathDebugObjCounterPoint = 0;
1322static int xmlXPathDebugObjCounterRange = 0;
1323static int xmlXPathDebugObjCounterLocset = 0;
1324static int xmlXPathDebugObjCounterUsers = 0;
1325static int xmlXPathDebugObjCounterXSLTTree = 0;
1326static int xmlXPathDebugObjCounterAll = 0;
1327
1328static int xmlXPathDebugObjTotalUndefined = 0;
1329static int xmlXPathDebugObjTotalNodeset = 0;
1330static int xmlXPathDebugObjTotalBool = 0;
1331static int xmlXPathDebugObjTotalNumber = 0;
1332static int xmlXPathDebugObjTotalString = 0;
1333static int xmlXPathDebugObjTotalPoint = 0;
1334static int xmlXPathDebugObjTotalRange = 0;
1335static int xmlXPathDebugObjTotalLocset = 0;
1336static int xmlXPathDebugObjTotalUsers = 0;
1337static int xmlXPathDebugObjTotalXSLTTree = 0;
1338static int xmlXPathDebugObjTotalAll = 0;
1339
1340static int xmlXPathDebugObjMaxUndefined = 0;
1341static int xmlXPathDebugObjMaxNodeset = 0;
1342static int xmlXPathDebugObjMaxBool = 0;
1343static int xmlXPathDebugObjMaxNumber = 0;
1344static int xmlXPathDebugObjMaxString = 0;
1345static int xmlXPathDebugObjMaxPoint = 0;
1346static int xmlXPathDebugObjMaxRange = 0;
1347static int xmlXPathDebugObjMaxLocset = 0;
1348static int xmlXPathDebugObjMaxUsers = 0;
1349static int xmlXPathDebugObjMaxXSLTTree = 0;
1350static int xmlXPathDebugObjMaxAll = 0;
1351
1352/* REVISIT TODO: Make this static when committing */
1353static void
1354xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1355{
1356 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001357 if (ctxt->cache != NULL) {
1358 xmlXPathContextCachePtr cache =
1359 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001360
1361 cache->dbgCachedAll = 0;
1362 cache->dbgCachedNodeset = 0;
1363 cache->dbgCachedString = 0;
1364 cache->dbgCachedBool = 0;
1365 cache->dbgCachedNumber = 0;
1366 cache->dbgCachedPoint = 0;
1367 cache->dbgCachedRange = 0;
1368 cache->dbgCachedLocset = 0;
1369 cache->dbgCachedUsers = 0;
1370 cache->dbgCachedXSLTTree = 0;
1371 cache->dbgCachedUndefined = 0;
1372
1373 cache->dbgReusedAll = 0;
1374 cache->dbgReusedNodeset = 0;
1375 cache->dbgReusedString = 0;
1376 cache->dbgReusedBool = 0;
1377 cache->dbgReusedNumber = 0;
1378 cache->dbgReusedPoint = 0;
1379 cache->dbgReusedRange = 0;
1380 cache->dbgReusedLocset = 0;
1381 cache->dbgReusedUsers = 0;
1382 cache->dbgReusedXSLTTree = 0;
1383 cache->dbgReusedUndefined = 0;
1384 }
1385 }
1386
1387 xmlXPathDebugObjCounterUndefined = 0;
1388 xmlXPathDebugObjCounterNodeset = 0;
1389 xmlXPathDebugObjCounterBool = 0;
1390 xmlXPathDebugObjCounterNumber = 0;
1391 xmlXPathDebugObjCounterString = 0;
1392 xmlXPathDebugObjCounterPoint = 0;
1393 xmlXPathDebugObjCounterRange = 0;
1394 xmlXPathDebugObjCounterLocset = 0;
1395 xmlXPathDebugObjCounterUsers = 0;
1396 xmlXPathDebugObjCounterXSLTTree = 0;
1397 xmlXPathDebugObjCounterAll = 0;
1398
1399 xmlXPathDebugObjTotalUndefined = 0;
1400 xmlXPathDebugObjTotalNodeset = 0;
1401 xmlXPathDebugObjTotalBool = 0;
1402 xmlXPathDebugObjTotalNumber = 0;
1403 xmlXPathDebugObjTotalString = 0;
1404 xmlXPathDebugObjTotalPoint = 0;
1405 xmlXPathDebugObjTotalRange = 0;
1406 xmlXPathDebugObjTotalLocset = 0;
1407 xmlXPathDebugObjTotalUsers = 0;
1408 xmlXPathDebugObjTotalXSLTTree = 0;
1409 xmlXPathDebugObjTotalAll = 0;
1410
1411 xmlXPathDebugObjMaxUndefined = 0;
1412 xmlXPathDebugObjMaxNodeset = 0;
1413 xmlXPathDebugObjMaxBool = 0;
1414 xmlXPathDebugObjMaxNumber = 0;
1415 xmlXPathDebugObjMaxString = 0;
1416 xmlXPathDebugObjMaxPoint = 0;
1417 xmlXPathDebugObjMaxRange = 0;
1418 xmlXPathDebugObjMaxLocset = 0;
1419 xmlXPathDebugObjMaxUsers = 0;
1420 xmlXPathDebugObjMaxXSLTTree = 0;
1421 xmlXPathDebugObjMaxAll = 0;
1422
1423}
1424
1425static void
1426xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1427 xmlXPathObjectType objType)
1428{
1429 int isCached = 0;
1430
1431 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001432 if (ctxt->cache != NULL) {
1433 xmlXPathContextCachePtr cache =
1434 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001435
1436 isCached = 1;
1437
1438 cache->dbgReusedAll++;
1439 switch (objType) {
1440 case XPATH_UNDEFINED:
1441 cache->dbgReusedUndefined++;
1442 break;
1443 case XPATH_NODESET:
1444 cache->dbgReusedNodeset++;
1445 break;
1446 case XPATH_BOOLEAN:
1447 cache->dbgReusedBool++;
1448 break;
1449 case XPATH_NUMBER:
1450 cache->dbgReusedNumber++;
1451 break;
1452 case XPATH_STRING:
1453 cache->dbgReusedString++;
1454 break;
1455 case XPATH_POINT:
1456 cache->dbgReusedPoint++;
1457 break;
1458 case XPATH_RANGE:
1459 cache->dbgReusedRange++;
1460 break;
1461 case XPATH_LOCATIONSET:
1462 cache->dbgReusedLocset++;
1463 break;
1464 case XPATH_USERS:
1465 cache->dbgReusedUsers++;
1466 break;
1467 case XPATH_XSLT_TREE:
1468 cache->dbgReusedXSLTTree++;
1469 break;
1470 default:
1471 break;
1472 }
1473 }
1474 }
1475
1476 switch (objType) {
1477 case XPATH_UNDEFINED:
1478 if (! isCached)
1479 xmlXPathDebugObjTotalUndefined++;
1480 xmlXPathDebugObjCounterUndefined++;
1481 if (xmlXPathDebugObjCounterUndefined >
1482 xmlXPathDebugObjMaxUndefined)
1483 xmlXPathDebugObjMaxUndefined =
1484 xmlXPathDebugObjCounterUndefined;
1485 break;
1486 case XPATH_NODESET:
1487 if (! isCached)
1488 xmlXPathDebugObjTotalNodeset++;
1489 xmlXPathDebugObjCounterNodeset++;
1490 if (xmlXPathDebugObjCounterNodeset >
1491 xmlXPathDebugObjMaxNodeset)
1492 xmlXPathDebugObjMaxNodeset =
1493 xmlXPathDebugObjCounterNodeset;
1494 break;
1495 case XPATH_BOOLEAN:
1496 if (! isCached)
1497 xmlXPathDebugObjTotalBool++;
1498 xmlXPathDebugObjCounterBool++;
1499 if (xmlXPathDebugObjCounterBool >
1500 xmlXPathDebugObjMaxBool)
1501 xmlXPathDebugObjMaxBool =
1502 xmlXPathDebugObjCounterBool;
1503 break;
1504 case XPATH_NUMBER:
1505 if (! isCached)
1506 xmlXPathDebugObjTotalNumber++;
1507 xmlXPathDebugObjCounterNumber++;
1508 if (xmlXPathDebugObjCounterNumber >
1509 xmlXPathDebugObjMaxNumber)
1510 xmlXPathDebugObjMaxNumber =
1511 xmlXPathDebugObjCounterNumber;
1512 break;
1513 case XPATH_STRING:
1514 if (! isCached)
1515 xmlXPathDebugObjTotalString++;
1516 xmlXPathDebugObjCounterString++;
1517 if (xmlXPathDebugObjCounterString >
1518 xmlXPathDebugObjMaxString)
1519 xmlXPathDebugObjMaxString =
1520 xmlXPathDebugObjCounterString;
1521 break;
1522 case XPATH_POINT:
1523 if (! isCached)
1524 xmlXPathDebugObjTotalPoint++;
1525 xmlXPathDebugObjCounterPoint++;
1526 if (xmlXPathDebugObjCounterPoint >
1527 xmlXPathDebugObjMaxPoint)
1528 xmlXPathDebugObjMaxPoint =
1529 xmlXPathDebugObjCounterPoint;
1530 break;
1531 case XPATH_RANGE:
1532 if (! isCached)
1533 xmlXPathDebugObjTotalRange++;
1534 xmlXPathDebugObjCounterRange++;
1535 if (xmlXPathDebugObjCounterRange >
1536 xmlXPathDebugObjMaxRange)
1537 xmlXPathDebugObjMaxRange =
1538 xmlXPathDebugObjCounterRange;
1539 break;
1540 case XPATH_LOCATIONSET:
1541 if (! isCached)
1542 xmlXPathDebugObjTotalLocset++;
1543 xmlXPathDebugObjCounterLocset++;
1544 if (xmlXPathDebugObjCounterLocset >
1545 xmlXPathDebugObjMaxLocset)
1546 xmlXPathDebugObjMaxLocset =
1547 xmlXPathDebugObjCounterLocset;
1548 break;
1549 case XPATH_USERS:
1550 if (! isCached)
1551 xmlXPathDebugObjTotalUsers++;
1552 xmlXPathDebugObjCounterUsers++;
1553 if (xmlXPathDebugObjCounterUsers >
1554 xmlXPathDebugObjMaxUsers)
1555 xmlXPathDebugObjMaxUsers =
1556 xmlXPathDebugObjCounterUsers;
1557 break;
1558 case XPATH_XSLT_TREE:
1559 if (! isCached)
1560 xmlXPathDebugObjTotalXSLTTree++;
1561 xmlXPathDebugObjCounterXSLTTree++;
1562 if (xmlXPathDebugObjCounterXSLTTree >
1563 xmlXPathDebugObjMaxXSLTTree)
1564 xmlXPathDebugObjMaxXSLTTree =
1565 xmlXPathDebugObjCounterXSLTTree;
1566 break;
1567 default:
1568 break;
1569 }
1570 if (! isCached)
1571 xmlXPathDebugObjTotalAll++;
1572 xmlXPathDebugObjCounterAll++;
1573 if (xmlXPathDebugObjCounterAll >
1574 xmlXPathDebugObjMaxAll)
1575 xmlXPathDebugObjMaxAll =
1576 xmlXPathDebugObjCounterAll;
1577}
1578
1579static void
1580xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1581 xmlXPathObjectType objType)
1582{
1583 int isCached = 0;
1584
1585 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001586 if (ctxt->cache != NULL) {
1587 xmlXPathContextCachePtr cache =
1588 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001589
1590 isCached = 1;
1591
1592 cache->dbgCachedAll++;
1593 switch (objType) {
1594 case XPATH_UNDEFINED:
1595 cache->dbgCachedUndefined++;
1596 break;
1597 case XPATH_NODESET:
1598 cache->dbgCachedNodeset++;
1599 break;
1600 case XPATH_BOOLEAN:
1601 cache->dbgCachedBool++;
1602 break;
1603 case XPATH_NUMBER:
1604 cache->dbgCachedNumber++;
1605 break;
1606 case XPATH_STRING:
1607 cache->dbgCachedString++;
1608 break;
1609 case XPATH_POINT:
1610 cache->dbgCachedPoint++;
1611 break;
1612 case XPATH_RANGE:
1613 cache->dbgCachedRange++;
1614 break;
1615 case XPATH_LOCATIONSET:
1616 cache->dbgCachedLocset++;
1617 break;
1618 case XPATH_USERS:
1619 cache->dbgCachedUsers++;
1620 break;
1621 case XPATH_XSLT_TREE:
1622 cache->dbgCachedXSLTTree++;
1623 break;
1624 default:
1625 break;
1626 }
1627
1628 }
1629 }
1630 switch (objType) {
1631 case XPATH_UNDEFINED:
1632 xmlXPathDebugObjCounterUndefined--;
1633 break;
1634 case XPATH_NODESET:
1635 xmlXPathDebugObjCounterNodeset--;
1636 break;
1637 case XPATH_BOOLEAN:
1638 xmlXPathDebugObjCounterBool--;
1639 break;
1640 case XPATH_NUMBER:
1641 xmlXPathDebugObjCounterNumber--;
1642 break;
1643 case XPATH_STRING:
1644 xmlXPathDebugObjCounterString--;
1645 break;
1646 case XPATH_POINT:
1647 xmlXPathDebugObjCounterPoint--;
1648 break;
1649 case XPATH_RANGE:
1650 xmlXPathDebugObjCounterRange--;
1651 break;
1652 case XPATH_LOCATIONSET:
1653 xmlXPathDebugObjCounterLocset--;
1654 break;
1655 case XPATH_USERS:
1656 xmlXPathDebugObjCounterUsers--;
1657 break;
1658 case XPATH_XSLT_TREE:
1659 xmlXPathDebugObjCounterXSLTTree--;
1660 break;
1661 default:
1662 break;
1663 }
1664 xmlXPathDebugObjCounterAll--;
1665}
1666
1667/* REVISIT TODO: Make this static when committing */
1668static void
1669xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1670{
1671 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1672 reqXSLTTree, reqUndefined;
1673 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1674 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1675 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1676 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1677 int leftObjs = xmlXPathDebugObjCounterAll;
1678
1679 reqAll = xmlXPathDebugObjTotalAll;
1680 reqNodeset = xmlXPathDebugObjTotalNodeset;
1681 reqString = xmlXPathDebugObjTotalString;
1682 reqBool = xmlXPathDebugObjTotalBool;
1683 reqNumber = xmlXPathDebugObjTotalNumber;
1684 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1685 reqUndefined = xmlXPathDebugObjTotalUndefined;
1686
1687 printf("# XPath object usage:\n");
1688
1689 if (ctxt != NULL) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001690 if (ctxt->cache != NULL) {
1691 xmlXPathContextCachePtr cache =
1692 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001693
1694 reAll = cache->dbgReusedAll;
1695 reqAll += reAll;
1696 reNodeset = cache->dbgReusedNodeset;
1697 reqNodeset += reNodeset;
1698 reString = cache->dbgReusedString;
1699 reqString += reString;
1700 reBool = cache->dbgReusedBool;
1701 reqBool += reBool;
1702 reNumber = cache->dbgReusedNumber;
1703 reqNumber += reNumber;
1704 reXSLTTree = cache->dbgReusedXSLTTree;
1705 reqXSLTTree += reXSLTTree;
1706 reUndefined = cache->dbgReusedUndefined;
1707 reqUndefined += reUndefined;
1708
1709 caAll = cache->dbgCachedAll;
1710 caBool = cache->dbgCachedBool;
1711 caNodeset = cache->dbgCachedNodeset;
1712 caString = cache->dbgCachedString;
1713 caNumber = cache->dbgCachedNumber;
1714 caXSLTTree = cache->dbgCachedXSLTTree;
1715 caUndefined = cache->dbgCachedUndefined;
1716
1717 if (cache->nodesetObjs)
1718 leftObjs -= cache->nodesetObjs->number;
1719 if (cache->stringObjs)
1720 leftObjs -= cache->stringObjs->number;
1721 if (cache->booleanObjs)
1722 leftObjs -= cache->booleanObjs->number;
1723 if (cache->numberObjs)
1724 leftObjs -= cache->numberObjs->number;
1725 if (cache->miscObjs)
1726 leftObjs -= cache->miscObjs->number;
1727 }
1728 }
1729
1730 printf("# all\n");
1731 printf("# total : %d\n", reqAll);
1732 printf("# left : %d\n", leftObjs);
1733 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1734 printf("# reused : %d\n", reAll);
1735 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1736
1737 printf("# node-sets\n");
1738 printf("# total : %d\n", reqNodeset);
1739 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1740 printf("# reused : %d\n", reNodeset);
1741 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1742
1743 printf("# strings\n");
1744 printf("# total : %d\n", reqString);
1745 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1746 printf("# reused : %d\n", reString);
1747 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1748
1749 printf("# booleans\n");
1750 printf("# total : %d\n", reqBool);
1751 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1752 printf("# reused : %d\n", reBool);
1753 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1754
1755 printf("# numbers\n");
1756 printf("# total : %d\n", reqNumber);
1757 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1758 printf("# reused : %d\n", reNumber);
1759 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1760
1761 printf("# XSLT result tree fragments\n");
1762 printf("# total : %d\n", reqXSLTTree);
1763 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1764 printf("# reused : %d\n", reXSLTTree);
1765 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1766
1767 printf("# undefined\n");
1768 printf("# total : %d\n", reqUndefined);
1769 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1770 printf("# reused : %d\n", reUndefined);
1771 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1772
1773}
1774
1775#endif /* XP_DEBUG_OBJ_USAGE */
1776
Daniel Veillard017b1082001-06-21 11:20:21 +00001777#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001778
1779/************************************************************************
1780 * *
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001781 * XPath object caching *
1782 * *
1783 ************************************************************************/
1784
1785/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001786 * xmlXPathNewCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001787 *
1788 * Create a new object cache
1789 *
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001790 * Returns the xmlXPathCache just allocated.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001791 */
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001792static xmlXPathContextCachePtr
1793xmlXPathNewCache(void)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001794{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001795 xmlXPathContextCachePtr ret;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001796
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001797 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001798 if (ret == NULL) {
1799 xmlXPathErrMemory(NULL, "creating object cache\n");
1800 return(NULL);
1801 }
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001802 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001803 ret->maxNodeset = 100;
1804 ret->maxString = 100;
1805 ret->maxBoolean = 100;
1806 ret->maxNumber = 100;
1807 ret->maxMisc = 100;
1808 return(ret);
1809}
1810
1811static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001812xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001813{
1814 int i;
1815 xmlXPathObjectPtr obj;
1816
1817 if (list == NULL)
1818 return;
1819
1820 for (i = 0; i < list->number; i++) {
1821 obj = list->items[i];
1822 /*
1823 * Note that it is already assured that we don't need to
1824 * look out for namespace nodes in the node-set.
1825 */
1826 if (obj->nodesetval != NULL) {
1827 if (obj->nodesetval->nodeTab != NULL)
1828 xmlFree(obj->nodesetval->nodeTab);
1829 xmlFree(obj->nodesetval);
1830 }
1831 xmlFree(obj);
1832#ifdef XP_DEBUG_OBJ_USAGE
1833 xmlXPathDebugObjCounterAll--;
1834#endif
1835 }
1836 xmlPointerListFree(list);
1837}
1838
1839static void
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001840xmlXPathFreeCache(xmlXPathContextCachePtr cache)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001841{
1842 if (cache == NULL)
1843 return;
1844 if (cache->nodesetObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001845 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001846 if (cache->stringObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001847 xmlXPathCacheFreeObjectList(cache->stringObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001848 if (cache->booleanObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001849 xmlXPathCacheFreeObjectList(cache->booleanObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001850 if (cache->numberObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001851 xmlXPathCacheFreeObjectList(cache->numberObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001852 if (cache->miscObjs)
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001853 xmlXPathCacheFreeObjectList(cache->miscObjs);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001854 xmlFree(cache);
1855}
1856
1857/**
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001858 * xmlXPathContextSetCache:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001859 *
1860 * @ctxt: the XPath context
1861 * @active: enables/disables (creates/frees) the cache
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001862 * @value: a value with semantics dependant on @options
1863 * @options: options (currently only the value 0 is used)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001864 *
1865 * Creates/frees an object cache on the XPath context.
1866 * If activates XPath objects (xmlXPathObject) will be cached internally
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001867 * to be reused.
1868 * @options:
1869 * 0: This will set the XPath object caching:
1870 * @value:
1871 * This will set the maximum number of XPath objects
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001872 * to be cached per slot
1873 * There are 5 slots for: node-set, string, number, boolean, and
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001874 * misc objects. Use <0 for the default number (100).
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001875 * Other values for @options have currently no effect.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001876 *
1877 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1878 */
1879int
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001880xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1881 int active,
1882 int value,
1883 int options)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001884{
1885 if (ctxt == NULL)
1886 return(-1);
1887 if (active) {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001888 xmlXPathContextCachePtr cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001889
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001890 if (ctxt->cache == NULL) {
1891 ctxt->cache = xmlXPathNewCache();
1892 if (ctxt->cache == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001893 return(-1);
1894 }
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001895 cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001896 if (options == 0) {
1897 if (value < 0)
1898 value = 100;
1899 cache->maxNodeset = value;
1900 cache->maxString = value;
1901 cache->maxNumber = value;
1902 cache->maxBoolean = value;
Aleksey Sanin1b2be102006-05-31 20:53:43 +00001903 cache->maxMisc = value;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001904 }
1905 } else if (ctxt->cache != NULL) {
1906 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1907 ctxt->cache = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001908 }
1909 return(0);
1910}
1911
1912/**
1913 * xmlXPathCacheWrapNodeSet:
1914 * @ctxt: the XPath context
1915 * @val: the NodePtr value
1916 *
1917 * This is the cached version of xmlXPathWrapNodeSet().
1918 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1919 *
1920 * Returns the created or reused object.
1921 */
1922static xmlXPathObjectPtr
1923xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1924{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001925 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1926 xmlXPathContextCachePtr cache =
1927 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001928
1929 if ((cache->miscObjs != NULL) &&
1930 (cache->miscObjs->number != 0))
1931 {
1932 xmlXPathObjectPtr ret;
1933
1934 ret = (xmlXPathObjectPtr)
1935 cache->miscObjs->items[--cache->miscObjs->number];
1936 ret->type = XPATH_NODESET;
1937 ret->nodesetval = val;
1938#ifdef XP_DEBUG_OBJ_USAGE
1939 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1940#endif
1941 return(ret);
1942 }
1943 }
1944
1945 return(xmlXPathWrapNodeSet(val));
1946
1947}
1948
1949/**
1950 * xmlXPathCacheWrapString:
1951 * @ctxt: the XPath context
1952 * @val: the xmlChar * value
1953 *
1954 * This is the cached version of xmlXPathWrapString().
1955 * Wraps the @val string into an XPath object.
1956 *
1957 * Returns the created or reused object.
1958 */
1959static xmlXPathObjectPtr
1960xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1961{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00001962 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1963 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00001964
1965 if ((cache->stringObjs != NULL) &&
1966 (cache->stringObjs->number != 0))
1967 {
1968
1969 xmlXPathObjectPtr ret;
1970
1971 ret = (xmlXPathObjectPtr)
1972 cache->stringObjs->items[--cache->stringObjs->number];
1973 ret->type = XPATH_STRING;
1974 ret->stringval = val;
1975#ifdef XP_DEBUG_OBJ_USAGE
1976 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1977#endif
1978 return(ret);
1979 } else if ((cache->miscObjs != NULL) &&
1980 (cache->miscObjs->number != 0))
1981 {
1982 xmlXPathObjectPtr ret;
1983 /*
1984 * Fallback to misc-cache.
1985 */
1986 ret = (xmlXPathObjectPtr)
1987 cache->miscObjs->items[--cache->miscObjs->number];
1988
1989 ret->type = XPATH_STRING;
1990 ret->stringval = val;
1991#ifdef XP_DEBUG_OBJ_USAGE
1992 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1993#endif
1994 return(ret);
1995 }
1996 }
1997 return(xmlXPathWrapString(val));
1998}
1999
2000/**
2001 * xmlXPathCacheNewNodeSet:
2002 * @ctxt: the XPath context
2003 * @val: the NodePtr value
2004 *
2005 * This is the cached version of xmlXPathNewNodeSet().
2006 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2007 * it with the single Node @val
2008 *
2009 * Returns the created or reused object.
2010 */
2011static xmlXPathObjectPtr
2012xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2013{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002014 if ((ctxt != NULL) && (ctxt->cache)) {
2015 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002016
2017 if ((cache->nodesetObjs != NULL) &&
2018 (cache->nodesetObjs->number != 0))
2019 {
2020 xmlXPathObjectPtr ret;
2021 /*
2022 * Use the nodset-cache.
2023 */
2024 ret = (xmlXPathObjectPtr)
2025 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2026 ret->type = XPATH_NODESET;
2027 ret->boolval = 0;
2028 if (val) {
2029 if ((ret->nodesetval->nodeMax == 0) ||
2030 (val->type == XML_NAMESPACE_DECL))
2031 {
2032 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2033 } else {
2034 ret->nodesetval->nodeTab[0] = val;
2035 ret->nodesetval->nodeNr = 1;
2036 }
2037 }
2038#ifdef XP_DEBUG_OBJ_USAGE
2039 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2040#endif
2041 return(ret);
2042 } else if ((cache->miscObjs != NULL) &&
2043 (cache->miscObjs->number != 0))
2044 {
2045 xmlXPathObjectPtr ret;
2046 /*
2047 * Fallback to misc-cache.
2048 */
2049
2050 ret = (xmlXPathObjectPtr)
2051 cache->miscObjs->items[--cache->miscObjs->number];
2052
2053 ret->type = XPATH_NODESET;
2054 ret->boolval = 0;
2055 ret->nodesetval = xmlXPathNodeSetCreate(val);
2056#ifdef XP_DEBUG_OBJ_USAGE
2057 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2058#endif
2059 return(ret);
2060 }
2061 }
2062 return(xmlXPathNewNodeSet(val));
2063}
2064
2065/**
2066 * xmlXPathCacheNewCString:
2067 * @ctxt: the XPath context
2068 * @val: the char * value
2069 *
2070 * This is the cached version of xmlXPathNewCString().
2071 * Acquire an xmlXPathObjectPtr of type string and of value @val
2072 *
2073 * Returns the created or reused object.
2074 */
2075static xmlXPathObjectPtr
2076xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2077{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002078 if ((ctxt != NULL) && (ctxt->cache)) {
2079 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002080
2081 if ((cache->stringObjs != NULL) &&
2082 (cache->stringObjs->number != 0))
2083 {
2084 xmlXPathObjectPtr ret;
2085
2086 ret = (xmlXPathObjectPtr)
2087 cache->stringObjs->items[--cache->stringObjs->number];
2088
2089 ret->type = XPATH_STRING;
2090 ret->stringval = xmlStrdup(BAD_CAST val);
2091#ifdef XP_DEBUG_OBJ_USAGE
2092 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2093#endif
2094 return(ret);
2095 } else if ((cache->miscObjs != NULL) &&
2096 (cache->miscObjs->number != 0))
2097 {
2098 xmlXPathObjectPtr ret;
2099
2100 ret = (xmlXPathObjectPtr)
2101 cache->miscObjs->items[--cache->miscObjs->number];
2102
2103 ret->type = XPATH_STRING;
2104 ret->stringval = xmlStrdup(BAD_CAST val);
2105#ifdef XP_DEBUG_OBJ_USAGE
2106 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2107#endif
2108 return(ret);
2109 }
2110 }
2111 return(xmlXPathNewCString(val));
2112}
2113
2114/**
2115 * xmlXPathCacheNewString:
2116 * @ctxt: the XPath context
2117 * @val: the xmlChar * value
2118 *
2119 * This is the cached version of xmlXPathNewString().
2120 * Acquire an xmlXPathObjectPtr of type string and of value @val
2121 *
2122 * Returns the created or reused object.
2123 */
2124static xmlXPathObjectPtr
2125xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2126{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002127 if ((ctxt != NULL) && (ctxt->cache)) {
2128 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002129
2130 if ((cache->stringObjs != NULL) &&
2131 (cache->stringObjs->number != 0))
2132 {
2133 xmlXPathObjectPtr ret;
2134
2135 ret = (xmlXPathObjectPtr)
2136 cache->stringObjs->items[--cache->stringObjs->number];
2137 ret->type = XPATH_STRING;
2138 if (val != NULL)
2139 ret->stringval = xmlStrdup(val);
2140 else
2141 ret->stringval = xmlStrdup((const xmlChar *)"");
2142#ifdef XP_DEBUG_OBJ_USAGE
2143 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2144#endif
2145 return(ret);
2146 } else if ((cache->miscObjs != NULL) &&
2147 (cache->miscObjs->number != 0))
2148 {
2149 xmlXPathObjectPtr ret;
2150
2151 ret = (xmlXPathObjectPtr)
2152 cache->miscObjs->items[--cache->miscObjs->number];
2153
2154 ret->type = XPATH_STRING;
2155 if (val != NULL)
2156 ret->stringval = xmlStrdup(val);
2157 else
2158 ret->stringval = xmlStrdup((const xmlChar *)"");
2159#ifdef XP_DEBUG_OBJ_USAGE
2160 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2161#endif
2162 return(ret);
2163 }
2164 }
2165 return(xmlXPathNewString(val));
2166}
2167
2168/**
2169 * xmlXPathCacheNewBoolean:
2170 * @ctxt: the XPath context
2171 * @val: the boolean value
2172 *
2173 * This is the cached version of xmlXPathNewBoolean().
2174 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2175 *
2176 * Returns the created or reused object.
2177 */
2178static xmlXPathObjectPtr
2179xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2180{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002181 if ((ctxt != NULL) && (ctxt->cache)) {
2182 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002183
2184 if ((cache->booleanObjs != NULL) &&
2185 (cache->booleanObjs->number != 0))
2186 {
2187 xmlXPathObjectPtr ret;
2188
2189 ret = (xmlXPathObjectPtr)
2190 cache->booleanObjs->items[--cache->booleanObjs->number];
2191 ret->type = XPATH_BOOLEAN;
2192 ret->boolval = (val != 0);
2193#ifdef XP_DEBUG_OBJ_USAGE
2194 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2195#endif
2196 return(ret);
2197 } else if ((cache->miscObjs != NULL) &&
2198 (cache->miscObjs->number != 0))
2199 {
2200 xmlXPathObjectPtr ret;
2201
2202 ret = (xmlXPathObjectPtr)
2203 cache->miscObjs->items[--cache->miscObjs->number];
2204
2205 ret->type = XPATH_BOOLEAN;
2206 ret->boolval = (val != 0);
2207#ifdef XP_DEBUG_OBJ_USAGE
2208 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2209#endif
2210 return(ret);
2211 }
2212 }
2213 return(xmlXPathNewBoolean(val));
2214}
2215
2216/**
2217 * xmlXPathCacheNewFloat:
2218 * @ctxt: the XPath context
2219 * @val: the double value
2220 *
2221 * This is the cached version of xmlXPathNewFloat().
2222 * Acquires an xmlXPathObjectPtr of type double and of value @val
2223 *
2224 * Returns the created or reused object.
2225 */
2226static xmlXPathObjectPtr
2227xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2228{
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00002229 if ((ctxt != NULL) && (ctxt->cache)) {
2230 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002231
2232 if ((cache->numberObjs != NULL) &&
2233 (cache->numberObjs->number != 0))
2234 {
2235 xmlXPathObjectPtr ret;
2236
2237 ret = (xmlXPathObjectPtr)
2238 cache->numberObjs->items[--cache->numberObjs->number];
2239 ret->type = XPATH_NUMBER;
2240 ret->floatval = val;
2241#ifdef XP_DEBUG_OBJ_USAGE
2242 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2243#endif
2244 return(ret);
2245 } else if ((cache->miscObjs != NULL) &&
2246 (cache->miscObjs->number != 0))
2247 {
2248 xmlXPathObjectPtr ret;
2249
2250 ret = (xmlXPathObjectPtr)
2251 cache->miscObjs->items[--cache->miscObjs->number];
2252
2253 ret->type = XPATH_NUMBER;
2254 ret->floatval = val;
2255#ifdef XP_DEBUG_OBJ_USAGE
2256 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2257#endif
2258 return(ret);
2259 }
2260 }
2261 return(xmlXPathNewFloat(val));
2262}
2263
2264/**
2265 * xmlXPathCacheConvertString:
2266 * @ctxt: the XPath context
2267 * @val: an XPath object
2268 *
2269 * This is the cached version of xmlXPathConvertString().
2270 * Converts an existing object to its string() equivalent
2271 *
2272 * Returns a created or reused object, the old one is freed (cached)
2273 * (or the operation is done directly on @val)
2274 */
2275
2276static xmlXPathObjectPtr
2277xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2278 xmlChar *res = NULL;
2279
2280 if (val == NULL)
2281 return(xmlXPathCacheNewCString(ctxt, ""));
2282
2283 switch (val->type) {
2284 case XPATH_UNDEFINED:
2285#ifdef DEBUG_EXPR
2286 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2287#endif
2288 break;
2289 case XPATH_NODESET:
2290 case XPATH_XSLT_TREE:
2291 res = xmlXPathCastNodeSetToString(val->nodesetval);
2292 break;
2293 case XPATH_STRING:
2294 return(val);
2295 case XPATH_BOOLEAN:
2296 res = xmlXPathCastBooleanToString(val->boolval);
2297 break;
2298 case XPATH_NUMBER:
2299 res = xmlXPathCastNumberToString(val->floatval);
2300 break;
2301 case XPATH_USERS:
2302 case XPATH_POINT:
2303 case XPATH_RANGE:
2304 case XPATH_LOCATIONSET:
2305 TODO;
2306 break;
2307 }
2308 xmlXPathReleaseObject(ctxt, val);
2309 if (res == NULL)
2310 return(xmlXPathCacheNewCString(ctxt, ""));
2311 return(xmlXPathCacheWrapString(ctxt, res));
2312}
2313
2314/**
2315 * xmlXPathCacheObjectCopy:
2316 * @ctxt: the XPath context
2317 * @val: the original object
2318 *
2319 * This is the cached version of xmlXPathObjectCopy().
2320 * Acquire a copy of a given object
2321 *
2322 * Returns a created or reused created object.
2323 */
2324static xmlXPathObjectPtr
2325xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2326{
2327 if (val == NULL)
2328 return(NULL);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002329
2330 switch (val->type) {
2331 case XPATH_NODESET:
2332 if (XP_HAS_CACHE(ctxt))
2333 return(xmlXPathCacheWrapNodeSet(ctxt,
2334 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2335 case XPATH_STRING:
2336 if (XP_HAS_CACHE(ctxt))
2337 return(xmlXPathCacheNewString(ctxt, val->stringval));
2338 case XPATH_BOOLEAN:
2339 if (XP_HAS_CACHE(ctxt))
2340 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2341 case XPATH_NUMBER:
2342 if (XP_HAS_CACHE(ctxt))
2343 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2344 default:
2345 break;
2346 }
2347 return(xmlXPathObjectCopy(val));
2348}
2349
2350/**
2351 * xmlXPathCacheConvertBoolean:
2352 * @ctxt: the XPath context
2353 * @val: an XPath object
2354 *
2355 * This is the cached version of xmlXPathConvertBoolean().
2356 * Converts an existing object to its boolean() equivalent
2357 *
2358 * Returns a created or reused object, the old one is freed (or the operation
2359 * is done directly on @val)
2360 */
2361static xmlXPathObjectPtr
2362xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2363 xmlXPathObjectPtr ret;
2364
2365 if (val == NULL)
2366 return(xmlXPathCacheNewBoolean(ctxt, 0));
2367 if (val->type == XPATH_BOOLEAN)
2368 return(val);
2369 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2370 xmlXPathReleaseObject(ctxt, val);
2371 return(ret);
2372}
2373
2374/**
2375 * xmlXPathCacheConvertNumber:
2376 * @ctxt: the XPath context
2377 * @val: an XPath object
2378 *
2379 * This is the cached version of xmlXPathConvertNumber().
2380 * Converts an existing object to its number() equivalent
2381 *
2382 * Returns a created or reused object, the old one is freed (or the operation
2383 * is done directly on @val)
2384 */
2385static xmlXPathObjectPtr
2386xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2387 xmlXPathObjectPtr ret;
2388
2389 if (val == NULL)
2390 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2391 if (val->type == XPATH_NUMBER)
2392 return(val);
2393 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2394 xmlXPathReleaseObject(ctxt, val);
2395 return(ret);
2396}
2397
2398/************************************************************************
2399 * *
Owen Taylor3473f882001-02-23 17:55:21 +00002400 * Parser stacks related functions and macros *
2401 * *
2402 ************************************************************************/
2403
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002404/**
2405 * valuePop:
2406 * @ctxt: an XPath evaluation context
2407 *
2408 * Pops the top XPath object from the value stack
2409 *
2410 * Returns the XPath object just removed
2411 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002412xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00002413valuePop(xmlXPathParserContextPtr ctxt)
2414{
2415 xmlXPathObjectPtr ret;
2416
Daniel Veillarda82b1822004-11-08 16:24:57 +00002417 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00002418 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002419 ctxt->valueNr--;
2420 if (ctxt->valueNr > 0)
2421 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2422 else
2423 ctxt->value = NULL;
2424 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00002425 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002426 return (ret);
2427}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002428/**
2429 * valuePush:
2430 * @ctxt: an XPath evaluation context
2431 * @value: the XPath object
2432 *
2433 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002434 *
2435 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002436 */
Daniel Veillard24505b02005-07-28 23:49:35 +00002437int
Daniel Veillard1c732d22002-11-30 11:22:59 +00002438valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2439{
Daniel Veillarda82b1822004-11-08 16:24:57 +00002440 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00002441 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002442 xmlXPathObjectPtr *tmp;
2443
2444 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2445 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00002446 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002447 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00002448 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2449 return (0);
2450 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00002451 ctxt->valueMax *= 2;
2452 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00002453 }
2454 ctxt->valueTab[ctxt->valueNr] = value;
2455 ctxt->value = value;
2456 return (ctxt->valueNr++);
2457}
Owen Taylor3473f882001-02-23 17:55:21 +00002458
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002459/**
2460 * xmlXPathPopBoolean:
2461 * @ctxt: an XPath parser context
2462 *
2463 * Pops a boolean from the stack, handling conversion if needed.
2464 * Check error with #xmlXPathCheckError.
2465 *
2466 * Returns the boolean
2467 */
2468int
2469xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2470 xmlXPathObjectPtr obj;
2471 int ret;
2472
2473 obj = valuePop(ctxt);
2474 if (obj == NULL) {
2475 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2476 return(0);
2477 }
William M. Brack08171912003-12-29 02:52:11 +00002478 if (obj->type != XPATH_BOOLEAN)
2479 ret = xmlXPathCastToBoolean(obj);
2480 else
2481 ret = obj->boolval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002482 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002483 return(ret);
2484}
2485
2486/**
2487 * xmlXPathPopNumber:
2488 * @ctxt: an XPath parser context
2489 *
2490 * Pops a number from the stack, handling conversion if needed.
2491 * Check error with #xmlXPathCheckError.
2492 *
2493 * Returns the number
2494 */
2495double
2496xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2497 xmlXPathObjectPtr obj;
2498 double ret;
2499
2500 obj = valuePop(ctxt);
2501 if (obj == NULL) {
2502 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2503 return(0);
2504 }
William M. Brack08171912003-12-29 02:52:11 +00002505 if (obj->type != XPATH_NUMBER)
2506 ret = xmlXPathCastToNumber(obj);
2507 else
2508 ret = obj->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002509 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002510 return(ret);
2511}
2512
2513/**
2514 * xmlXPathPopString:
2515 * @ctxt: an XPath parser context
2516 *
2517 * Pops a string from the stack, handling conversion if needed.
2518 * Check error with #xmlXPathCheckError.
2519 *
2520 * Returns the string
2521 */
2522xmlChar *
2523xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2524 xmlXPathObjectPtr obj;
2525 xmlChar * ret;
2526
2527 obj = valuePop(ctxt);
2528 if (obj == NULL) {
2529 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2530 return(NULL);
2531 }
William M. Brack08171912003-12-29 02:52:11 +00002532 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002533 /* TODO: needs refactoring somewhere else */
2534 if (obj->stringval == ret)
2535 obj->stringval = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002536 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002537 return(ret);
2538}
2539
2540/**
2541 * xmlXPathPopNodeSet:
2542 * @ctxt: an XPath parser context
2543 *
2544 * Pops a node-set from the stack, handling conversion if needed.
2545 * Check error with #xmlXPathCheckError.
2546 *
2547 * Returns the node-set
2548 */
2549xmlNodeSetPtr
2550xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2551 xmlXPathObjectPtr obj;
2552 xmlNodeSetPtr ret;
2553
Daniel Veillardf2a36f92004-11-08 17:55:01 +00002554 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002555 if (ctxt->value == NULL) {
2556 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2557 return(NULL);
2558 }
2559 if (!xmlXPathStackIsNodeSet(ctxt)) {
2560 xmlXPathSetTypeError(ctxt);
2561 return(NULL);
2562 }
2563 obj = valuePop(ctxt);
2564 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00002565#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00002566 /* to fix memory leak of not clearing obj->user */
2567 if (obj->boolval && obj->user != NULL)
2568 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00002569#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002570 obj->nodesetval = NULL;
2571 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002572 return(ret);
2573}
2574
2575/**
2576 * xmlXPathPopExternal:
2577 * @ctxt: an XPath parser context
2578 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002579 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002580 * Check error with #xmlXPathCheckError.
2581 *
2582 * Returns the object
2583 */
2584void *
2585xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2586 xmlXPathObjectPtr obj;
2587 void * ret;
2588
Daniel Veillarda82b1822004-11-08 16:24:57 +00002589 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002590 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2591 return(NULL);
2592 }
2593 if (ctxt->value->type != XPATH_USERS) {
2594 xmlXPathSetTypeError(ctxt);
2595 return(NULL);
2596 }
2597 obj = valuePop(ctxt);
2598 ret = obj->user;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00002599 obj->user = NULL;
2600 xmlXPathReleaseObject(ctxt->context, obj);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002601 return(ret);
2602}
2603
Owen Taylor3473f882001-02-23 17:55:21 +00002604/*
2605 * Macros for accessing the content. Those should be used only by the parser,
2606 * and not exported.
2607 *
2608 * Dirty macros, i.e. one need to make assumption on the context to use them
2609 *
2610 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2611 * CUR returns the current xmlChar value, i.e. a 8 bit value
2612 * in ISO-Latin or UTF-8.
2613 * This should be used internally by the parser
2614 * only to compare to ASCII values otherwise it would break when
2615 * running with UTF-8 encoding.
2616 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2617 * to compare on ASCII based substring.
2618 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2619 * strings within the parser.
2620 * CURRENT Returns the current char value, with the full decoding of
2621 * UTF-8 if we are using this mode. It returns an int.
2622 * NEXT Skip to the next character, this does the proper decoding
2623 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2624 * It returns the pointer to the current xmlChar.
2625 */
2626
2627#define CUR (*ctxt->cur)
2628#define SKIP(val) ctxt->cur += (val)
2629#define NXT(val) ctxt->cur[(val)]
2630#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00002631#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2632
2633#define COPY_BUF(l,b,i,v) \
2634 if (l == 1) b[i++] = (xmlChar) v; \
2635 else i += xmlCopyChar(l,&b[i],v)
2636
2637#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00002638
2639#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00002640 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00002641
2642#define CURRENT (*ctxt->cur)
2643#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2644
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002645
2646#ifndef DBL_DIG
2647#define DBL_DIG 16
2648#endif
2649#ifndef DBL_EPSILON
2650#define DBL_EPSILON 1E-9
2651#endif
2652
2653#define UPPER_DOUBLE 1E9
2654#define LOWER_DOUBLE 1E-5
2655
2656#define INTEGER_DIGITS DBL_DIG
2657#define FRACTION_DIGITS (DBL_DIG + 1)
2658#define EXPONENT_DIGITS (3 + 2)
2659
2660/**
2661 * xmlXPathFormatNumber:
2662 * @number: number to format
2663 * @buffer: output buffer
2664 * @buffersize: size of output buffer
2665 *
2666 * Convert the number into a string representation.
2667 */
2668static void
2669xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2670{
Daniel Veillardcda96922001-08-21 10:56:31 +00002671 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002672 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00002673 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002674 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002675 break;
2676 case -1:
2677 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002678 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002679 break;
2680 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00002681 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002682 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002683 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00002684 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002685 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002686 } else if (number == ((int) number)) {
2687 char work[30];
2688 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00002689 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002690
2691 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002692 if (value == 0) {
2693 *ptr++ = '0';
2694 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00002695 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002696 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00002697 while ((*cur) && (ptr - buffer < buffersize)) {
2698 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00002699 }
2700 }
2701 if (ptr - buffer < buffersize) {
2702 *ptr = 0;
2703 } else if (buffersize > 0) {
2704 ptr--;
2705 *ptr = 0;
2706 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002707 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00002708 /* 3 is sign, decimal point, and terminating zero */
2709 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2710 int integer_place, fraction_place;
2711 char *ptr;
2712 char *after_fraction;
2713 double absolute_value;
2714 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002715
Bjorn Reese70a9da52001-04-21 16:57:29 +00002716 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002717
Bjorn Reese70a9da52001-04-21 16:57:29 +00002718 /*
2719 * First choose format - scientific or regular floating point.
2720 * In either case, result is in work, and after_fraction points
2721 * just past the fractional part.
2722 */
2723 if ( ((absolute_value > UPPER_DOUBLE) ||
2724 (absolute_value < LOWER_DOUBLE)) &&
2725 (absolute_value != 0.0) ) {
2726 /* Use scientific notation */
2727 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2728 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00002729 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00002730 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00002731 while ((size > 0) && (work[size] != 'e')) size--;
2732 after_fraction = work + size;
2733
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002734 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00002735 else {
2736 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00002737 if (absolute_value > 0.0)
2738 integer_place = 1 + (int)log10(absolute_value);
2739 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00002740 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00002741 fraction_place = (integer_place > 0)
2742 ? DBL_DIG - integer_place
2743 : DBL_DIG;
2744 size = snprintf(work, sizeof(work), "%0.*f",
2745 fraction_place, number);
2746 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002747 }
2748
Bjorn Reese70a9da52001-04-21 16:57:29 +00002749 /* Remove fractional trailing zeroes */
2750 ptr = after_fraction;
2751 while (*(--ptr) == '0')
2752 ;
2753 if (*ptr != '.')
2754 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002755 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00002756
2757 /* Finally copy result back to caller */
2758 size = strlen(work) + 1;
2759 if (size > buffersize) {
2760 work[buffersize - 1] = 0;
2761 size = buffersize;
2762 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00002763 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002764 }
2765 break;
2766 }
2767}
2768
Owen Taylor3473f882001-02-23 17:55:21 +00002769
2770/************************************************************************
2771 * *
2772 * Routines to handle NodeSets *
2773 * *
2774 ************************************************************************/
2775
2776/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002777 * xmlXPathOrderDocElems:
2778 * @doc: an input document
2779 *
2780 * Call this routine to speed up XPath computation on static documents.
2781 * This stamps all the element nodes with the document order
2782 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00002783 * field, the value stored is actually - the node number (starting at -1)
2784 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002785 *
William M. Brack08171912003-12-29 02:52:11 +00002786 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002787 * of error.
2788 */
2789long
2790xmlXPathOrderDocElems(xmlDocPtr doc) {
2791 long count = 0;
2792 xmlNodePtr cur;
2793
2794 if (doc == NULL)
2795 return(-1);
2796 cur = doc->children;
2797 while (cur != NULL) {
2798 if (cur->type == XML_ELEMENT_NODE) {
2799 cur->content = (void *) (-(++count));
2800 if (cur->children != NULL) {
2801 cur = cur->children;
2802 continue;
2803 }
2804 }
2805 if (cur->next != NULL) {
2806 cur = cur->next;
2807 continue;
2808 }
2809 do {
2810 cur = cur->parent;
2811 if (cur == NULL)
2812 break;
2813 if (cur == (xmlNodePtr) doc) {
2814 cur = NULL;
2815 break;
2816 }
2817 if (cur->next != NULL) {
2818 cur = cur->next;
2819 break;
2820 }
2821 } while (cur != NULL);
2822 }
2823 return(count);
2824}
2825
2826/**
Owen Taylor3473f882001-02-23 17:55:21 +00002827 * xmlXPathCmpNodes:
2828 * @node1: the first node
2829 * @node2: the second node
2830 *
2831 * Compare two nodes w.r.t document order
2832 *
2833 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00002834 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00002835 */
2836int
2837xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2838 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002839 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002840 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002841 xmlNodePtr cur, root;
2842
2843 if ((node1 == NULL) || (node2 == NULL))
2844 return(-2);
2845 /*
2846 * a couple of optimizations which will avoid computations in most cases
2847 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00002848 if (node1->type == XML_ATTRIBUTE_NODE) {
2849 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002850 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002851 node1 = node1->parent;
2852 }
2853 if (node2->type == XML_ATTRIBUTE_NODE) {
2854 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00002855 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00002856 node2 = node2->parent;
2857 }
2858 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00002859 if (attr1 == attr2) {
2860 /* not required, but we keep attributes in order */
2861 if (attr1 != 0) {
2862 cur = attrNode2->prev;
2863 while (cur != NULL) {
2864 if (cur == attrNode1)
2865 return (1);
2866 cur = cur->prev;
2867 }
2868 return (-1);
2869 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002870 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00002871 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00002872 if (attr2 == 1)
2873 return(1);
2874 return(-1);
2875 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00002876 if ((node1->type == XML_NAMESPACE_DECL) ||
2877 (node2->type == XML_NAMESPACE_DECL))
2878 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002879 if (node1 == node2->prev)
2880 return(1);
2881 if (node1 == node2->next)
2882 return(-1);
2883
2884 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002885 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002886 */
2887 if ((node1->type == XML_ELEMENT_NODE) &&
2888 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002889 (0 > (long) node1->content) &&
2890 (0 > (long) node2->content) &&
2891 (node1->doc == node2->doc)) {
2892 long l1, l2;
2893
2894 l1 = -((long) node1->content);
2895 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002896 if (l1 < l2)
2897 return(1);
2898 if (l1 > l2)
2899 return(-1);
2900 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00002901
Daniel Veillard7216cfd2002-11-08 15:10:00 +00002902 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002903 * compute depth to root
2904 */
2905 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2906 if (cur == node1)
2907 return(1);
2908 depth2++;
2909 }
2910 root = cur;
2911 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2912 if (cur == node2)
2913 return(-1);
2914 depth1++;
2915 }
2916 /*
2917 * Distinct document (or distinct entities :-( ) case.
2918 */
2919 if (root != cur) {
2920 return(-2);
2921 }
2922 /*
2923 * get the nearest common ancestor.
2924 */
2925 while (depth1 > depth2) {
2926 depth1--;
2927 node1 = node1->parent;
2928 }
2929 while (depth2 > depth1) {
2930 depth2--;
2931 node2 = node2->parent;
2932 }
2933 while (node1->parent != node2->parent) {
2934 node1 = node1->parent;
2935 node2 = node2->parent;
2936 /* should not happen but just in case ... */
2937 if ((node1 == NULL) || (node2 == NULL))
2938 return(-2);
2939 }
2940 /*
2941 * Find who's first.
2942 */
Daniel Veillardf49be472004-02-17 11:48:18 +00002943 if (node1 == node2->prev)
2944 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00002945 if (node1 == node2->next)
2946 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00002947 /*
2948 * Speedup using document order if availble.
2949 */
2950 if ((node1->type == XML_ELEMENT_NODE) &&
2951 (node2->type == XML_ELEMENT_NODE) &&
2952 (0 > (long) node1->content) &&
2953 (0 > (long) node2->content) &&
2954 (node1->doc == node2->doc)) {
2955 long l1, l2;
2956
2957 l1 = -((long) node1->content);
2958 l2 = -((long) node2->content);
2959 if (l1 < l2)
2960 return(1);
2961 if (l1 > l2)
2962 return(-1);
2963 }
2964
Owen Taylor3473f882001-02-23 17:55:21 +00002965 for (cur = node1->next;cur != NULL;cur = cur->next)
2966 if (cur == node2)
2967 return(1);
2968 return(-1); /* assume there is no sibling list corruption */
2969}
2970
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002971#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002972/**
2973 * xmlXPathCmpNodesExt:
2974 * @node1: the first node
2975 * @node2: the second node
2976 *
2977 * Compare two nodes w.r.t document order.
2978 * This one is optimized for handling of non-element nodes.
2979 *
2980 * Returns -2 in case of error 1 if first point < second point, 0 if
2981 * it's the same node, -1 otherwise
2982 */
2983static int
2984xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2985 int depth1, depth2;
2986 int misc = 0, precedence1 = 0, precedence2 = 0;
2987 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2988 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002989 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002990
2991 if ((node1 == NULL) || (node2 == NULL))
2992 return(-2);
2993
2994 if (node1 == node2)
2995 return(0);
2996
2997 /*
2998 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00002999 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003000 switch (node1->type) {
3001 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003002 if (node2->type == XML_ELEMENT_NODE) {
3003 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3004 (0 > (long) node2->content) &&
3005 (node1->doc == node2->doc))
3006 {
3007 l1 = -((long) node1->content);
3008 l2 = -((long) node2->content);
3009 if (l1 < l2)
3010 return(1);
3011 if (l1 > l2)
3012 return(-1);
3013 } else
3014 goto turtle_comparison;
3015 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003016 break;
3017 case XML_ATTRIBUTE_NODE:
3018 precedence1 = 1; /* element is owner */
3019 miscNode1 = node1;
3020 node1 = node1->parent;
3021 misc = 1;
3022 break;
3023 case XML_TEXT_NODE:
3024 case XML_CDATA_SECTION_NODE:
3025 case XML_COMMENT_NODE:
3026 case XML_PI_NODE: {
3027 miscNode1 = node1;
3028 /*
3029 * Find nearest element node.
3030 */
3031 if (node1->prev != NULL) {
3032 do {
3033 node1 = node1->prev;
3034 if (node1->type == XML_ELEMENT_NODE) {
3035 precedence1 = 3; /* element in prev-sibl axis */
3036 break;
3037 }
3038 if (node1->prev == NULL) {
3039 precedence1 = 2; /* element is parent */
3040 /*
3041 * URGENT TODO: Are there any cases, where the
3042 * parent of such a node is not an element node?
3043 */
3044 node1 = node1->parent;
3045 break;
3046 }
3047 } while (1);
3048 } else {
3049 precedence1 = 2; /* element is parent */
3050 node1 = node1->parent;
3051 }
3052 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3053 /*
3054 * Fallback for whatever case.
3055 */
3056 node1 = miscNode1;
3057 precedence1 = 0;
3058 } else
3059 misc = 1;
3060 }
3061 break;
3062 case XML_NAMESPACE_DECL:
3063 /*
3064 * TODO: why do we return 1 for namespace nodes?
3065 */
3066 return(1);
3067 default:
3068 break;
3069 }
3070 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003071 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003072 break;
3073 case XML_ATTRIBUTE_NODE:
3074 precedence2 = 1; /* element is owner */
3075 miscNode2 = node2;
3076 node2 = node2->parent;
3077 misc = 1;
3078 break;
3079 case XML_TEXT_NODE:
3080 case XML_CDATA_SECTION_NODE:
3081 case XML_COMMENT_NODE:
3082 case XML_PI_NODE: {
3083 miscNode2 = node2;
3084 if (node2->prev != NULL) {
3085 do {
3086 node2 = node2->prev;
3087 if (node2->type == XML_ELEMENT_NODE) {
3088 precedence2 = 3; /* element in prev-sibl axis */
3089 break;
3090 }
3091 if (node2->prev == NULL) {
3092 precedence2 = 2; /* element is parent */
3093 node2 = node2->parent;
3094 break;
3095 }
3096 } while (1);
3097 } else {
3098 precedence2 = 2; /* element is parent */
3099 node2 = node2->parent;
3100 }
3101 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3102 (0 <= (long) node1->content))
3103 {
3104 node2 = miscNode2;
3105 precedence2 = 0;
3106 } else
3107 misc = 1;
3108 }
3109 break;
3110 case XML_NAMESPACE_DECL:
3111 return(1);
3112 default:
3113 break;
3114 }
3115 if (misc) {
3116 if (node1 == node2) {
3117 if (precedence1 == precedence2) {
3118 /*
3119 * The ugly case; but normally there aren't many
3120 * adjacent non-element nodes around.
3121 */
3122 cur = miscNode2->prev;
3123 while (cur != NULL) {
3124 if (cur == miscNode1)
3125 return(1);
3126 if (cur->type == XML_ELEMENT_NODE)
3127 return(-1);
3128 cur = cur->prev;
3129 }
3130 return (-1);
3131 } else {
3132 /*
3133 * Evaluate based on higher precedence wrt to the element.
3134 * TODO: This assumes attributes are sorted before content.
3135 * Is this 100% correct?
3136 */
3137 if (precedence1 < precedence2)
3138 return(1);
3139 else
3140 return(-1);
3141 }
3142 }
3143 /*
3144 * Special case: One of the helper-elements is contained by the other.
3145 * <foo>
3146 * <node2>
3147 * <node1>Text-1(precedence1 == 2)</node1>
3148 * </node2>
3149 * Text-6(precedence2 == 3)
3150 * </foo>
3151 */
3152 if ((precedence2 == 3) && (precedence1 > 1)) {
3153 cur = node1->parent;
3154 while (cur) {
3155 if (cur == node2)
3156 return(1);
3157 cur = cur->parent;
3158 }
3159 }
3160 if ((precedence1 == 3) && (precedence2 > 1)) {
3161 cur = node2->parent;
3162 while (cur) {
3163 if (cur == node1)
3164 return(-1);
3165 cur = cur->parent;
3166 }
3167 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003168 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003169
3170 /*
3171 * Speedup using document order if availble.
3172 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003173 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003174 (node2->type == XML_ELEMENT_NODE) &&
3175 (0 > (long) node1->content) &&
3176 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003177 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003178
3179 l1 = -((long) node1->content);
3180 l2 = -((long) node2->content);
3181 if (l1 < l2)
3182 return(1);
3183 if (l1 > l2)
3184 return(-1);
3185 }
3186
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003187turtle_comparison:
3188
3189 if (node1 == node2->prev)
3190 return(1);
3191 if (node1 == node2->next)
3192 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003193 /*
3194 * compute depth to root
3195 */
3196 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3197 if (cur == node1)
3198 return(1);
3199 depth2++;
3200 }
3201 root = cur;
3202 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3203 if (cur == node2)
3204 return(-1);
3205 depth1++;
3206 }
3207 /*
3208 * Distinct document (or distinct entities :-( ) case.
3209 */
3210 if (root != cur) {
3211 return(-2);
3212 }
3213 /*
3214 * get the nearest common ancestor.
3215 */
3216 while (depth1 > depth2) {
3217 depth1--;
3218 node1 = node1->parent;
3219 }
3220 while (depth2 > depth1) {
3221 depth2--;
3222 node2 = node2->parent;
3223 }
3224 while (node1->parent != node2->parent) {
3225 node1 = node1->parent;
3226 node2 = node2->parent;
3227 /* should not happen but just in case ... */
3228 if ((node1 == NULL) || (node2 == NULL))
3229 return(-2);
3230 }
3231 /*
3232 * Find who's first.
3233 */
3234 if (node1 == node2->prev)
3235 return(1);
3236 if (node1 == node2->next)
3237 return(-1);
3238 /*
3239 * Speedup using document order if availble.
3240 */
3241 if ((node1->type == XML_ELEMENT_NODE) &&
3242 (node2->type == XML_ELEMENT_NODE) &&
3243 (0 > (long) node1->content) &&
3244 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003245 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003246
3247 l1 = -((long) node1->content);
3248 l2 = -((long) node2->content);
3249 if (l1 < l2)
3250 return(1);
3251 if (l1 > l2)
3252 return(-1);
3253 }
3254
3255 for (cur = node1->next;cur != NULL;cur = cur->next)
3256 if (cur == node2)
3257 return(1);
3258 return(-1); /* assume there is no sibling list corruption */
3259}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003260#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003261
Owen Taylor3473f882001-02-23 17:55:21 +00003262/**
3263 * xmlXPathNodeSetSort:
3264 * @set: the node set
3265 *
3266 * Sort the node set in document order
3267 */
3268void
3269xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003270 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003271 xmlNodePtr tmp;
3272
3273 if (set == NULL)
3274 return;
3275
3276 /* Use Shell's sort to sort the node-set */
3277 len = set->nodeNr;
3278 for (incr = len / 2; incr > 0; incr /= 2) {
3279 for (i = incr; i < len; i++) {
3280 j = i - incr;
3281 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003282#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003283 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3284 set->nodeTab[j + incr]) == -1)
3285#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003286 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00003287 set->nodeTab[j + incr]) == -1)
3288#endif
3289 {
Owen Taylor3473f882001-02-23 17:55:21 +00003290 tmp = set->nodeTab[j];
3291 set->nodeTab[j] = set->nodeTab[j + incr];
3292 set->nodeTab[j + incr] = tmp;
3293 j -= incr;
3294 } else
3295 break;
3296 }
3297 }
3298 }
3299}
3300
3301#define XML_NODESET_DEFAULT 10
3302/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003303 * xmlXPathNodeSetDupNs:
3304 * @node: the parent node of the namespace XPath node
3305 * @ns: the libxml namespace declaration node.
3306 *
3307 * Namespace node in libxml don't match the XPath semantic. In a node set
3308 * the namespace nodes are duplicated and the next pointer is set to the
3309 * parent node in the XPath semantic.
3310 *
3311 * Returns the newly created object.
3312 */
3313static xmlNodePtr
3314xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3315 xmlNsPtr cur;
3316
3317 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3318 return(NULL);
3319 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3320 return((xmlNodePtr) ns);
3321
3322 /*
3323 * Allocate a new Namespace and fill the fields.
3324 */
3325 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3326 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003327 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003328 return(NULL);
3329 }
3330 memset(cur, 0, sizeof(xmlNs));
3331 cur->type = XML_NAMESPACE_DECL;
3332 if (ns->href != NULL)
3333 cur->href = xmlStrdup(ns->href);
3334 if (ns->prefix != NULL)
3335 cur->prefix = xmlStrdup(ns->prefix);
3336 cur->next = (xmlNsPtr) node;
3337 return((xmlNodePtr) cur);
3338}
3339
3340/**
3341 * xmlXPathNodeSetFreeNs:
3342 * @ns: the XPath namespace node found in a nodeset.
3343 *
William M. Brack08171912003-12-29 02:52:11 +00003344 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003345 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00003346 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003347 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00003348void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003349xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3350 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3351 return;
3352
3353 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3354 if (ns->href != NULL)
3355 xmlFree((xmlChar *)ns->href);
3356 if (ns->prefix != NULL)
3357 xmlFree((xmlChar *)ns->prefix);
3358 xmlFree(ns);
3359 }
3360}
3361
3362/**
Owen Taylor3473f882001-02-23 17:55:21 +00003363 * xmlXPathNodeSetCreate:
3364 * @val: an initial xmlNodePtr, or NULL
3365 *
3366 * Create a new xmlNodeSetPtr of type double and of value @val
3367 *
3368 * Returns the newly created object.
3369 */
3370xmlNodeSetPtr
3371xmlXPathNodeSetCreate(xmlNodePtr val) {
3372 xmlNodeSetPtr ret;
3373
3374 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3375 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003376 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003377 return(NULL);
3378 }
3379 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3380 if (val != NULL) {
3381 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3382 sizeof(xmlNodePtr));
3383 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003384 xmlXPathErrMemory(NULL, "creating nodeset\n");
3385 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003386 return(NULL);
3387 }
3388 memset(ret->nodeTab, 0 ,
3389 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3390 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003391 if (val->type == XML_NAMESPACE_DECL) {
3392 xmlNsPtr ns = (xmlNsPtr) val;
3393
3394 ret->nodeTab[ret->nodeNr++] =
3395 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3396 } else
3397 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003398 }
3399 return(ret);
3400}
3401
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003402/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003403 * xmlXPathNodeSetContains:
3404 * @cur: the node-set
3405 * @val: the node
3406 *
3407 * checks whether @cur contains @val
3408 *
3409 * Returns true (1) if @cur contains @val, false (0) otherwise
3410 */
3411int
3412xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3413 int i;
3414
Daniel Veillarda82b1822004-11-08 16:24:57 +00003415 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003416 if (val->type == XML_NAMESPACE_DECL) {
3417 for (i = 0; i < cur->nodeNr; i++) {
3418 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3419 xmlNsPtr ns1, ns2;
3420
3421 ns1 = (xmlNsPtr) val;
3422 ns2 = (xmlNsPtr) cur->nodeTab[i];
3423 if (ns1 == ns2)
3424 return(1);
3425 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3426 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3427 return(1);
3428 }
3429 }
3430 } else {
3431 for (i = 0; i < cur->nodeNr; i++) {
3432 if (cur->nodeTab[i] == val)
3433 return(1);
3434 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003435 }
3436 return(0);
3437}
3438
3439/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003440 * xmlXPathNodeSetAddNs:
3441 * @cur: the initial node set
3442 * @node: the hosting node
3443 * @ns: a the namespace node
3444 *
3445 * add a new namespace node to an existing NodeSet
3446 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00003447void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003448xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3449 int i;
3450
Daniel Veillarda82b1822004-11-08 16:24:57 +00003451
3452 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3453 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003454 (node->type != XML_ELEMENT_NODE))
3455 return;
3456
William M. Brack08171912003-12-29 02:52:11 +00003457 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003458 /*
William M. Brack08171912003-12-29 02:52:11 +00003459 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003460 */
3461 for (i = 0;i < cur->nodeNr;i++) {
3462 if ((cur->nodeTab[i] != NULL) &&
3463 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00003464 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003465 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3466 return;
3467 }
3468
3469 /*
3470 * grow the nodeTab if needed
3471 */
3472 if (cur->nodeMax == 0) {
3473 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3474 sizeof(xmlNodePtr));
3475 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003476 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003477 return;
3478 }
3479 memset(cur->nodeTab, 0 ,
3480 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3481 cur->nodeMax = XML_NODESET_DEFAULT;
3482 } else if (cur->nodeNr == cur->nodeMax) {
3483 xmlNodePtr *temp;
3484
3485 cur->nodeMax *= 2;
3486 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3487 sizeof(xmlNodePtr));
3488 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003489 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003490 return;
3491 }
3492 cur->nodeTab = temp;
3493 }
3494 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3495}
3496
3497/**
Owen Taylor3473f882001-02-23 17:55:21 +00003498 * xmlXPathNodeSetAdd:
3499 * @cur: the initial node set
3500 * @val: a new xmlNodePtr
3501 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003502 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00003503 */
3504void
3505xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3506 int i;
3507
Daniel Veillarda82b1822004-11-08 16:24:57 +00003508 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003509
Daniel Veillardef0b4502003-03-24 13:57:34 +00003510#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003511 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3512 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003513#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003514
William M. Brack08171912003-12-29 02:52:11 +00003515 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003516 /*
William M. Brack08171912003-12-29 02:52:11 +00003517 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00003518 */
3519 for (i = 0;i < cur->nodeNr;i++)
3520 if (cur->nodeTab[i] == val) return;
3521
3522 /*
3523 * grow the nodeTab if needed
3524 */
3525 if (cur->nodeMax == 0) {
3526 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3527 sizeof(xmlNodePtr));
3528 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003529 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003530 return;
3531 }
3532 memset(cur->nodeTab, 0 ,
3533 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3534 cur->nodeMax = XML_NODESET_DEFAULT;
3535 } else if (cur->nodeNr == cur->nodeMax) {
3536 xmlNodePtr *temp;
3537
3538 cur->nodeMax *= 2;
3539 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3540 sizeof(xmlNodePtr));
3541 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003542 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003543 return;
3544 }
3545 cur->nodeTab = temp;
3546 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003547 if (val->type == XML_NAMESPACE_DECL) {
3548 xmlNsPtr ns = (xmlNsPtr) val;
3549
3550 cur->nodeTab[cur->nodeNr++] =
3551 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3552 } else
3553 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003554}
3555
3556/**
3557 * xmlXPathNodeSetAddUnique:
3558 * @cur: the initial node set
3559 * @val: a new xmlNodePtr
3560 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003561 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00003562 * when we are sure the node is not already in the set.
3563 */
3564void
3565xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00003566 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003567
Daniel Veillardef0b4502003-03-24 13:57:34 +00003568#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00003569 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3570 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00003571#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00003572
William M. Brack08171912003-12-29 02:52:11 +00003573 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003574 /*
3575 * grow the nodeTab if needed
3576 */
3577 if (cur->nodeMax == 0) {
3578 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3579 sizeof(xmlNodePtr));
3580 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003581 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003582 return;
3583 }
3584 memset(cur->nodeTab, 0 ,
3585 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3586 cur->nodeMax = XML_NODESET_DEFAULT;
3587 } else if (cur->nodeNr == cur->nodeMax) {
3588 xmlNodePtr *temp;
3589
3590 cur->nodeMax *= 2;
3591 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3592 sizeof(xmlNodePtr));
3593 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003594 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003595 return;
3596 }
3597 cur->nodeTab = temp;
3598 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003599 if (val->type == XML_NAMESPACE_DECL) {
3600 xmlNsPtr ns = (xmlNsPtr) val;
3601
3602 cur->nodeTab[cur->nodeNr++] =
3603 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3604 } else
3605 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00003606}
3607
3608/**
3609 * xmlXPathNodeSetMerge:
3610 * @val1: the first NodeSet or NULL
3611 * @val2: the second NodeSet
3612 *
3613 * Merges two nodesets, all nodes from @val2 are added to @val1
3614 * if @val1 is NULL, a new set is created and copied from @val2
3615 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003616 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00003617 */
3618xmlNodeSetPtr
3619xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003620 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003621 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003622
3623 if (val2 == NULL) return(val1);
3624 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00003625 val1 = xmlXPathNodeSetCreate(NULL);
3626#if 0
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003627 /*
3628 * TODO: The optimization won't work in every case, since
3629 * those nasty namespace nodes need to be added with
3630 * xmlXPathNodeSetDupNs() to the set; thus a pure
3631 * memcpy is not possible.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00003632 * If there was a flag on the nodesetval, indicating that
3633 * some temporary nodes are in, that would be helpfull.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003634 */
3635 /*
3636 * Optimization: Create an equally sized node-set
3637 * and memcpy the content.
3638 */
3639 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3640 if (val1 == NULL)
3641 return(NULL);
3642 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003643 if (val2->nodeNr == 1)
3644 *(val1->nodeTab) = *(val2->nodeTab);
3645 else {
3646 memcpy(val1->nodeTab, val2->nodeTab,
3647 val2->nodeNr * sizeof(xmlNodePtr));
3648 }
3649 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003650 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003651 return(val1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003652#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003653 }
3654
William M. Brack08171912003-12-29 02:52:11 +00003655 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00003656 initNr = val1->nodeNr;
3657
3658 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003659 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00003660 /*
William M. Brack08171912003-12-29 02:52:11 +00003661 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00003662 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003663 skip = 0;
3664 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003665 n1 = val1->nodeTab[j];
3666 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003667 skip = 1;
3668 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003669 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3670 (n2->type == XML_NAMESPACE_DECL)) {
3671 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3672 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3673 ((xmlNsPtr) n2)->prefix)))
3674 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003675 skip = 1;
3676 break;
3677 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003678 }
3679 }
3680 if (skip)
3681 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00003682
3683 /*
3684 * grow the nodeTab if needed
3685 */
3686 if (val1->nodeMax == 0) {
3687 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3688 sizeof(xmlNodePtr));
3689 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003690 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003691 return(NULL);
3692 }
3693 memset(val1->nodeTab, 0 ,
3694 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3695 val1->nodeMax = XML_NODESET_DEFAULT;
3696 } else if (val1->nodeNr == val1->nodeMax) {
3697 xmlNodePtr *temp;
3698
3699 val1->nodeMax *= 2;
3700 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3701 sizeof(xmlNodePtr));
3702 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003703 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003704 return(NULL);
3705 }
3706 val1->nodeTab = temp;
3707 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003708 if (n2->type == XML_NAMESPACE_DECL) {
3709 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003710
3711 val1->nodeTab[val1->nodeNr++] =
3712 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3713 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00003714 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00003715 }
3716
3717 return(val1);
3718}
3719
3720/**
Daniel Veillard75be0132002-03-13 10:03:35 +00003721 * xmlXPathNodeSetMergeUnique:
3722 * @val1: the first NodeSet or NULL
3723 * @val2: the second NodeSet
3724 *
3725 * Merges two nodesets, all nodes from @val2 are added to @val1
3726 * if @val1 is NULL, a new set is created and copied from @val2
3727 *
3728 * Returns @val1 once extended or NULL in case of error.
3729 */
3730static xmlNodeSetPtr
3731xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00003732 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00003733
3734 if (val2 == NULL) return(val1);
3735 if (val1 == NULL) {
3736 val1 = xmlXPathNodeSetCreate(NULL);
3737 }
3738
William M. Brack08171912003-12-29 02:52:11 +00003739 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00003740
3741 for (i = 0;i < val2->nodeNr;i++) {
3742 /*
3743 * grow the nodeTab if needed
3744 */
3745 if (val1->nodeMax == 0) {
3746 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3747 sizeof(xmlNodePtr));
3748 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003749 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003750 return(NULL);
3751 }
3752 memset(val1->nodeTab, 0 ,
3753 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3754 val1->nodeMax = XML_NODESET_DEFAULT;
3755 } else if (val1->nodeNr == val1->nodeMax) {
3756 xmlNodePtr *temp;
3757
3758 val1->nodeMax *= 2;
3759 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3760 sizeof(xmlNodePtr));
3761 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003762 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00003763 return(NULL);
3764 }
3765 val1->nodeTab = temp;
3766 }
3767 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3768 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3769
3770 val1->nodeTab[val1->nodeNr++] =
3771 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3772 } else
3773 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3774 }
3775
3776 return(val1);
3777}
3778
3779/**
Owen Taylor3473f882001-02-23 17:55:21 +00003780 * xmlXPathNodeSetDel:
3781 * @cur: the initial node set
3782 * @val: an xmlNodePtr
3783 *
3784 * Removes an xmlNodePtr from an existing NodeSet
3785 */
3786void
3787xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3788 int i;
3789
3790 if (cur == NULL) return;
3791 if (val == NULL) return;
3792
3793 /*
William M. Brack08171912003-12-29 02:52:11 +00003794 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00003795 */
3796 for (i = 0;i < cur->nodeNr;i++)
3797 if (cur->nodeTab[i] == val) break;
3798
William M. Brack08171912003-12-29 02:52:11 +00003799 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00003800#ifdef DEBUG
3801 xmlGenericError(xmlGenericErrorContext,
3802 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
3803 val->name);
3804#endif
3805 return;
3806 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003807 if ((cur->nodeTab[i] != NULL) &&
3808 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3809 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003810 cur->nodeNr--;
3811 for (;i < cur->nodeNr;i++)
3812 cur->nodeTab[i] = cur->nodeTab[i + 1];
3813 cur->nodeTab[cur->nodeNr] = NULL;
3814}
3815
3816/**
3817 * xmlXPathNodeSetRemove:
3818 * @cur: the initial node set
3819 * @val: the index to remove
3820 *
3821 * Removes an entry from an existing NodeSet list.
3822 */
3823void
3824xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3825 if (cur == NULL) return;
3826 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003827 if ((cur->nodeTab[val] != NULL) &&
3828 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3829 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00003830 cur->nodeNr--;
3831 for (;val < cur->nodeNr;val++)
3832 cur->nodeTab[val] = cur->nodeTab[val + 1];
3833 cur->nodeTab[cur->nodeNr] = NULL;
3834}
3835
3836/**
3837 * xmlXPathFreeNodeSet:
3838 * @obj: the xmlNodeSetPtr to free
3839 *
3840 * Free the NodeSet compound (not the actual nodes !).
3841 */
3842void
3843xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3844 if (obj == NULL) return;
3845 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003846 int i;
3847
William M. Brack08171912003-12-29 02:52:11 +00003848 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003849 for (i = 0;i < obj->nodeNr;i++)
3850 if ((obj->nodeTab[i] != NULL) &&
3851 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3852 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003853 xmlFree(obj->nodeTab);
3854 }
Owen Taylor3473f882001-02-23 17:55:21 +00003855 xmlFree(obj);
3856}
3857
3858/**
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003859 * xmlXPathNodeSetClear:
3860 * @set: the xmlNodeSetPtr to free
3861 *
3862 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3863 * are feed), but does *not* free the list itself. Sets the length of the
3864 * list to 0.
3865 */
3866static void
3867xmlXPathNodeSetClear(xmlNodeSetPtr set)
3868{
3869 int i;
3870 xmlNodePtr node;
3871
3872 if ((set == NULL) || (set->nodeNr <= 0))
3873 return;
3874
3875 for (i = 0; i < set->nodeNr; i++) {
3876 node = set->nodeTab[i];
3877 if ((node != NULL) &&
3878 (node->type == XML_NAMESPACE_DECL))
3879 {
3880 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3881 }
3882 }
3883 set->nodeNr = 0;
3884}
3885
3886/**
Owen Taylor3473f882001-02-23 17:55:21 +00003887 * xmlXPathFreeValueTree:
3888 * @obj: the xmlNodeSetPtr to free
3889 *
3890 * Free the NodeSet compound and the actual tree, this is different
3891 * from xmlXPathFreeNodeSet()
3892 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003893static void
Owen Taylor3473f882001-02-23 17:55:21 +00003894xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3895 int i;
3896
3897 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00003898
3899 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00003900 for (i = 0;i < obj->nodeNr;i++) {
3901 if (obj->nodeTab[i] != NULL) {
3902 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3903 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3904 } else {
3905 xmlFreeNodeList(obj->nodeTab[i]);
3906 }
3907 }
3908 }
Owen Taylor3473f882001-02-23 17:55:21 +00003909 xmlFree(obj->nodeTab);
3910 }
Owen Taylor3473f882001-02-23 17:55:21 +00003911 xmlFree(obj);
3912}
3913
3914#if defined(DEBUG) || defined(DEBUG_STEP)
3915/**
3916 * xmlGenericErrorContextNodeSet:
3917 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00003918 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00003919 *
3920 * Quick display of a NodeSet
3921 */
3922void
3923xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
3924 int i;
3925
3926 if (output == NULL) output = xmlGenericErrorContext;
3927 if (obj == NULL) {
3928 fprintf(output, "NodeSet == NULL !\n");
3929 return;
3930 }
3931 if (obj->nodeNr == 0) {
3932 fprintf(output, "NodeSet is empty\n");
3933 return;
3934 }
3935 if (obj->nodeTab == NULL) {
3936 fprintf(output, " nodeTab == NULL !\n");
3937 return;
3938 }
3939 for (i = 0; i < obj->nodeNr; i++) {
3940 if (obj->nodeTab[i] == NULL) {
3941 fprintf(output, " NULL !\n");
3942 return;
3943 }
3944 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
3945 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
3946 fprintf(output, " /");
3947 else if (obj->nodeTab[i]->name == NULL)
3948 fprintf(output, " noname!");
3949 else fprintf(output, " %s", obj->nodeTab[i]->name);
3950 }
3951 fprintf(output, "\n");
3952}
3953#endif
3954
3955/**
3956 * xmlXPathNewNodeSet:
3957 * @val: the NodePtr value
3958 *
3959 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3960 * it with the single Node @val
3961 *
3962 * Returns the newly created object.
3963 */
3964xmlXPathObjectPtr
3965xmlXPathNewNodeSet(xmlNodePtr val) {
3966 xmlXPathObjectPtr ret;
3967
3968 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3969 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003970 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003971 return(NULL);
3972 }
3973 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3974 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00003975 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003976 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00003977 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00003978#ifdef XP_DEBUG_OBJ_USAGE
3979 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
3980#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003981 return(ret);
3982}
3983
3984/**
3985 * xmlXPathNewValueTree:
3986 * @val: the NodePtr value
3987 *
3988 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3989 * it with the tree root @val
3990 *
3991 * Returns the newly created object.
3992 */
3993xmlXPathObjectPtr
3994xmlXPathNewValueTree(xmlNodePtr val) {
3995 xmlXPathObjectPtr ret;
3996
3997 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3998 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003999 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004000 return(NULL);
4001 }
4002 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4003 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00004004 ret->boolval = 1;
4005 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00004006 ret->nodesetval = xmlXPathNodeSetCreate(val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004007#ifdef XP_DEBUG_OBJ_USAGE
4008 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4009#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004010 return(ret);
4011}
4012
4013/**
4014 * xmlXPathNewNodeSetList:
4015 * @val: an existing NodeSet
4016 *
4017 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4018 * it with the Nodeset @val
4019 *
4020 * Returns the newly created object.
4021 */
4022xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004023xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4024{
Owen Taylor3473f882001-02-23 17:55:21 +00004025 xmlXPathObjectPtr ret;
4026 int i;
4027
4028 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004029 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00004030 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004031 ret = xmlXPathNewNodeSet(NULL);
4032 else {
4033 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4034 for (i = 1; i < val->nodeNr; ++i)
4035 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4036 }
Owen Taylor3473f882001-02-23 17:55:21 +00004037
Daniel Veillard044fc6b2002-03-04 17:09:44 +00004038 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004039}
4040
4041/**
4042 * xmlXPathWrapNodeSet:
4043 * @val: the NodePtr value
4044 *
4045 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4046 *
4047 * Returns the newly created object.
4048 */
4049xmlXPathObjectPtr
4050xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4051 xmlXPathObjectPtr ret;
4052
4053 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4054 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004055 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004056 return(NULL);
4057 }
4058 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4059 ret->type = XPATH_NODESET;
4060 ret->nodesetval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004061#ifdef XP_DEBUG_OBJ_USAGE
4062 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4063#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004064 return(ret);
4065}
4066
4067/**
4068 * xmlXPathFreeNodeSetList:
4069 * @obj: an existing NodeSetList object
4070 *
4071 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4072 * the list contrary to xmlXPathFreeObject().
4073 */
4074void
4075xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4076 if (obj == NULL) return;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004077#ifdef XP_DEBUG_OBJ_USAGE
4078 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4079#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004080 xmlFree(obj);
4081}
4082
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004083/**
4084 * xmlXPathDifference:
4085 * @nodes1: a node-set
4086 * @nodes2: a node-set
4087 *
4088 * Implements the EXSLT - Sets difference() function:
4089 * node-set set:difference (node-set, node-set)
4090 *
4091 * Returns the difference between the two node sets, or nodes1 if
4092 * nodes2 is empty
4093 */
4094xmlNodeSetPtr
4095xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4096 xmlNodeSetPtr ret;
4097 int i, l1;
4098 xmlNodePtr cur;
4099
4100 if (xmlXPathNodeSetIsEmpty(nodes2))
4101 return(nodes1);
4102
4103 ret = xmlXPathNodeSetCreate(NULL);
4104 if (xmlXPathNodeSetIsEmpty(nodes1))
4105 return(ret);
4106
4107 l1 = xmlXPathNodeSetGetLength(nodes1);
4108
4109 for (i = 0; i < l1; i++) {
4110 cur = xmlXPathNodeSetItem(nodes1, i);
4111 if (!xmlXPathNodeSetContains(nodes2, cur))
4112 xmlXPathNodeSetAddUnique(ret, cur);
4113 }
4114 return(ret);
4115}
4116
4117/**
4118 * xmlXPathIntersection:
4119 * @nodes1: a node-set
4120 * @nodes2: a node-set
4121 *
4122 * Implements the EXSLT - Sets intersection() function:
4123 * node-set set:intersection (node-set, node-set)
4124 *
4125 * Returns a node set comprising the nodes that are within both the
4126 * node sets passed as arguments
4127 */
4128xmlNodeSetPtr
4129xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4130 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4131 int i, l1;
4132 xmlNodePtr cur;
4133
4134 if (xmlXPathNodeSetIsEmpty(nodes1))
4135 return(ret);
4136 if (xmlXPathNodeSetIsEmpty(nodes2))
4137 return(ret);
4138
4139 l1 = xmlXPathNodeSetGetLength(nodes1);
4140
4141 for (i = 0; i < l1; i++) {
4142 cur = xmlXPathNodeSetItem(nodes1, i);
4143 if (xmlXPathNodeSetContains(nodes2, cur))
4144 xmlXPathNodeSetAddUnique(ret, cur);
4145 }
4146 return(ret);
4147}
4148
4149/**
4150 * xmlXPathDistinctSorted:
4151 * @nodes: a node-set, sorted by document order
4152 *
4153 * Implements the EXSLT - Sets distinct() function:
4154 * node-set set:distinct (node-set)
4155 *
4156 * Returns a subset of the nodes contained in @nodes, or @nodes if
4157 * it is empty
4158 */
4159xmlNodeSetPtr
4160xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4161 xmlNodeSetPtr ret;
4162 xmlHashTablePtr hash;
4163 int i, l;
4164 xmlChar * strval;
4165 xmlNodePtr cur;
4166
4167 if (xmlXPathNodeSetIsEmpty(nodes))
4168 return(nodes);
4169
4170 ret = xmlXPathNodeSetCreate(NULL);
4171 l = xmlXPathNodeSetGetLength(nodes);
4172 hash = xmlHashCreate (l);
4173 for (i = 0; i < l; i++) {
4174 cur = xmlXPathNodeSetItem(nodes, i);
4175 strval = xmlXPathCastNodeToString(cur);
4176 if (xmlHashLookup(hash, strval) == NULL) {
4177 xmlHashAddEntry(hash, strval, strval);
4178 xmlXPathNodeSetAddUnique(ret, cur);
4179 } else {
4180 xmlFree(strval);
4181 }
4182 }
4183 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4184 return(ret);
4185}
4186
4187/**
4188 * xmlXPathDistinct:
4189 * @nodes: a node-set
4190 *
4191 * Implements the EXSLT - Sets distinct() function:
4192 * node-set set:distinct (node-set)
4193 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4194 * is called with the sorted node-set
4195 *
4196 * Returns a subset of the nodes contained in @nodes, or @nodes if
4197 * it is empty
4198 */
4199xmlNodeSetPtr
4200xmlXPathDistinct (xmlNodeSetPtr nodes) {
4201 if (xmlXPathNodeSetIsEmpty(nodes))
4202 return(nodes);
4203
4204 xmlXPathNodeSetSort(nodes);
4205 return(xmlXPathDistinctSorted(nodes));
4206}
4207
4208/**
4209 * xmlXPathHasSameNodes:
4210 * @nodes1: a node-set
4211 * @nodes2: a node-set
4212 *
4213 * Implements the EXSLT - Sets has-same-nodes function:
4214 * boolean set:has-same-node(node-set, node-set)
4215 *
4216 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4217 * otherwise
4218 */
4219int
4220xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4221 int i, l;
4222 xmlNodePtr cur;
4223
4224 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4225 xmlXPathNodeSetIsEmpty(nodes2))
4226 return(0);
4227
4228 l = xmlXPathNodeSetGetLength(nodes1);
4229 for (i = 0; i < l; i++) {
4230 cur = xmlXPathNodeSetItem(nodes1, i);
4231 if (xmlXPathNodeSetContains(nodes2, cur))
4232 return(1);
4233 }
4234 return(0);
4235}
4236
4237/**
4238 * xmlXPathNodeLeadingSorted:
4239 * @nodes: a node-set, sorted by document order
4240 * @node: a node
4241 *
4242 * Implements the EXSLT - Sets leading() function:
4243 * node-set set:leading (node-set, node-set)
4244 *
4245 * Returns the nodes in @nodes that precede @node in document order,
4246 * @nodes if @node is NULL or an empty node-set if @nodes
4247 * doesn't contain @node
4248 */
4249xmlNodeSetPtr
4250xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4251 int i, l;
4252 xmlNodePtr cur;
4253 xmlNodeSetPtr ret;
4254
4255 if (node == NULL)
4256 return(nodes);
4257
4258 ret = xmlXPathNodeSetCreate(NULL);
4259 if (xmlXPathNodeSetIsEmpty(nodes) ||
4260 (!xmlXPathNodeSetContains(nodes, node)))
4261 return(ret);
4262
4263 l = xmlXPathNodeSetGetLength(nodes);
4264 for (i = 0; i < l; i++) {
4265 cur = xmlXPathNodeSetItem(nodes, i);
4266 if (cur == node)
4267 break;
4268 xmlXPathNodeSetAddUnique(ret, cur);
4269 }
4270 return(ret);
4271}
4272
4273/**
4274 * xmlXPathNodeLeading:
4275 * @nodes: a node-set
4276 * @node: a node
4277 *
4278 * Implements the EXSLT - Sets leading() function:
4279 * node-set set:leading (node-set, node-set)
4280 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4281 * is called.
4282 *
4283 * Returns the nodes in @nodes that precede @node in document order,
4284 * @nodes if @node is NULL or an empty node-set if @nodes
4285 * doesn't contain @node
4286 */
4287xmlNodeSetPtr
4288xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4289 xmlXPathNodeSetSort(nodes);
4290 return(xmlXPathNodeLeadingSorted(nodes, node));
4291}
4292
4293/**
4294 * xmlXPathLeadingSorted:
4295 * @nodes1: a node-set, sorted by document order
4296 * @nodes2: a node-set, sorted by document order
4297 *
4298 * Implements the EXSLT - Sets leading() function:
4299 * node-set set:leading (node-set, node-set)
4300 *
4301 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4302 * in document order, @nodes1 if @nodes2 is NULL or empty or
4303 * an empty node-set if @nodes1 doesn't contain @nodes2
4304 */
4305xmlNodeSetPtr
4306xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4307 if (xmlXPathNodeSetIsEmpty(nodes2))
4308 return(nodes1);
4309 return(xmlXPathNodeLeadingSorted(nodes1,
4310 xmlXPathNodeSetItem(nodes2, 1)));
4311}
4312
4313/**
4314 * xmlXPathLeading:
4315 * @nodes1: a node-set
4316 * @nodes2: a node-set
4317 *
4318 * Implements the EXSLT - Sets leading() function:
4319 * node-set set:leading (node-set, node-set)
4320 * @nodes1 and @nodes2 are sorted by document order, then
4321 * #exslSetsLeadingSorted is called.
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
4328xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4329 if (xmlXPathNodeSetIsEmpty(nodes2))
4330 return(nodes1);
4331 if (xmlXPathNodeSetIsEmpty(nodes1))
4332 return(xmlXPathNodeSetCreate(NULL));
4333 xmlXPathNodeSetSort(nodes1);
4334 xmlXPathNodeSetSort(nodes2);
4335 return(xmlXPathNodeLeadingSorted(nodes1,
4336 xmlXPathNodeSetItem(nodes2, 1)));
4337}
4338
4339/**
4340 * xmlXPathNodeTrailingSorted:
4341 * @nodes: a node-set, sorted by document order
4342 * @node: a node
4343 *
4344 * Implements the EXSLT - Sets trailing() function:
4345 * node-set set:trailing (node-set, node-set)
4346 *
4347 * Returns the nodes in @nodes that follow @node in document order,
4348 * @nodes if @node is NULL or an empty node-set if @nodes
4349 * doesn't contain @node
4350 */
4351xmlNodeSetPtr
4352xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4353 int i, l;
4354 xmlNodePtr cur;
4355 xmlNodeSetPtr ret;
4356
4357 if (node == NULL)
4358 return(nodes);
4359
4360 ret = xmlXPathNodeSetCreate(NULL);
4361 if (xmlXPathNodeSetIsEmpty(nodes) ||
4362 (!xmlXPathNodeSetContains(nodes, node)))
4363 return(ret);
4364
4365 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00004366 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004367 cur = xmlXPathNodeSetItem(nodes, i);
4368 if (cur == node)
4369 break;
4370 xmlXPathNodeSetAddUnique(ret, cur);
4371 }
4372 return(ret);
4373}
4374
4375/**
4376 * xmlXPathNodeTrailing:
4377 * @nodes: a node-set
4378 * @node: a node
4379 *
4380 * Implements the EXSLT - Sets trailing() function:
4381 * node-set set:trailing (node-set, node-set)
4382 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4383 * is called.
4384 *
4385 * Returns the nodes in @nodes that follow @node in document order,
4386 * @nodes if @node is NULL or an empty node-set if @nodes
4387 * doesn't contain @node
4388 */
4389xmlNodeSetPtr
4390xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4391 xmlXPathNodeSetSort(nodes);
4392 return(xmlXPathNodeTrailingSorted(nodes, node));
4393}
4394
4395/**
4396 * xmlXPathTrailingSorted:
4397 * @nodes1: a node-set, sorted by document order
4398 * @nodes2: a node-set, sorted by document order
4399 *
4400 * Implements the EXSLT - Sets trailing() function:
4401 * node-set set:trailing (node-set, node-set)
4402 *
4403 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4404 * in document order, @nodes1 if @nodes2 is NULL or empty or
4405 * an empty node-set if @nodes1 doesn't contain @nodes2
4406 */
4407xmlNodeSetPtr
4408xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4409 if (xmlXPathNodeSetIsEmpty(nodes2))
4410 return(nodes1);
4411 return(xmlXPathNodeTrailingSorted(nodes1,
4412 xmlXPathNodeSetItem(nodes2, 0)));
4413}
4414
4415/**
4416 * xmlXPathTrailing:
4417 * @nodes1: a node-set
4418 * @nodes2: a node-set
4419 *
4420 * Implements the EXSLT - Sets trailing() function:
4421 * node-set set:trailing (node-set, node-set)
4422 * @nodes1 and @nodes2 are sorted by document order, then
4423 * #xmlXPathTrailingSorted is called.
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
4430xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4431 if (xmlXPathNodeSetIsEmpty(nodes2))
4432 return(nodes1);
4433 if (xmlXPathNodeSetIsEmpty(nodes1))
4434 return(xmlXPathNodeSetCreate(NULL));
4435 xmlXPathNodeSetSort(nodes1);
4436 xmlXPathNodeSetSort(nodes2);
4437 return(xmlXPathNodeTrailingSorted(nodes1,
4438 xmlXPathNodeSetItem(nodes2, 0)));
4439}
4440
Owen Taylor3473f882001-02-23 17:55:21 +00004441/************************************************************************
4442 * *
4443 * Routines to handle extra functions *
4444 * *
4445 ************************************************************************/
4446
4447/**
4448 * xmlXPathRegisterFunc:
4449 * @ctxt: the XPath context
4450 * @name: the function name
4451 * @f: the function implementation or NULL
4452 *
4453 * Register a new function. If @f is NULL it unregisters the function
4454 *
4455 * Returns 0 in case of success, -1 in case of error
4456 */
4457int
4458xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4459 xmlXPathFunction f) {
4460 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4461}
4462
4463/**
4464 * xmlXPathRegisterFuncNS:
4465 * @ctxt: the XPath context
4466 * @name: the function name
4467 * @ns_uri: the function namespace URI
4468 * @f: the function implementation or NULL
4469 *
4470 * Register a new function. If @f is NULL it unregisters the function
4471 *
4472 * Returns 0 in case of success, -1 in case of error
4473 */
4474int
4475xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4476 const xmlChar *ns_uri, xmlXPathFunction f) {
4477 if (ctxt == NULL)
4478 return(-1);
4479 if (name == NULL)
4480 return(-1);
4481
4482 if (ctxt->funcHash == NULL)
4483 ctxt->funcHash = xmlHashCreate(0);
4484 if (ctxt->funcHash == NULL)
4485 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004486 if (f == NULL)
4487 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00004488 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00004489}
4490
4491/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00004492 * xmlXPathRegisterFuncLookup:
4493 * @ctxt: the XPath context
4494 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004495 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00004496 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004497 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00004498 */
4499void
4500xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4501 xmlXPathFuncLookupFunc f,
4502 void *funcCtxt) {
4503 if (ctxt == NULL)
4504 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004505 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004506 ctxt->funcLookupData = funcCtxt;
4507}
4508
4509/**
Owen Taylor3473f882001-02-23 17:55:21 +00004510 * xmlXPathFunctionLookup:
4511 * @ctxt: the XPath context
4512 * @name: the function name
4513 *
4514 * Search in the Function array of the context for the given
4515 * function.
4516 *
4517 * Returns the xmlXPathFunction or NULL if not found
4518 */
4519xmlXPathFunction
4520xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00004521 if (ctxt == NULL)
4522 return (NULL);
4523
4524 if (ctxt->funcLookupFunc != NULL) {
4525 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004526 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004527
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004528 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004529 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004530 if (ret != NULL)
4531 return(ret);
4532 }
Owen Taylor3473f882001-02-23 17:55:21 +00004533 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4534}
4535
4536/**
4537 * xmlXPathFunctionLookupNS:
4538 * @ctxt: the XPath context
4539 * @name: the function name
4540 * @ns_uri: the function namespace URI
4541 *
4542 * Search in the Function array of the context for the given
4543 * function.
4544 *
4545 * Returns the xmlXPathFunction or NULL if not found
4546 */
4547xmlXPathFunction
4548xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4549 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00004550 xmlXPathFunction ret;
4551
Owen Taylor3473f882001-02-23 17:55:21 +00004552 if (ctxt == NULL)
4553 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004554 if (name == NULL)
4555 return(NULL);
4556
Thomas Broyerba4ad322001-07-26 16:55:21 +00004557 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00004558 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00004559
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004560 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00004561 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00004562 if (ret != NULL)
4563 return(ret);
4564 }
4565
4566 if (ctxt->funcHash == NULL)
4567 return(NULL);
4568
William M. Brackad0e67c2004-12-01 14:35:10 +00004569 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4570 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004571}
4572
4573/**
4574 * xmlXPathRegisteredFuncsCleanup:
4575 * @ctxt: the XPath context
4576 *
4577 * Cleanup the XPath context data associated to registered functions
4578 */
4579void
4580xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4581 if (ctxt == NULL)
4582 return;
4583
4584 xmlHashFree(ctxt->funcHash, NULL);
4585 ctxt->funcHash = NULL;
4586}
4587
4588/************************************************************************
4589 * *
William M. Brack08171912003-12-29 02:52:11 +00004590 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00004591 * *
4592 ************************************************************************/
4593
4594/**
4595 * xmlXPathRegisterVariable:
4596 * @ctxt: the XPath context
4597 * @name: the variable name
4598 * @value: the variable value or NULL
4599 *
4600 * Register a new variable value. If @value is NULL it unregisters
4601 * the variable
4602 *
4603 * Returns 0 in case of success, -1 in case of error
4604 */
4605int
4606xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4607 xmlXPathObjectPtr value) {
4608 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4609}
4610
4611/**
4612 * xmlXPathRegisterVariableNS:
4613 * @ctxt: the XPath context
4614 * @name: the variable name
4615 * @ns_uri: the variable namespace URI
4616 * @value: the variable value or NULL
4617 *
4618 * Register a new variable value. If @value is NULL it unregisters
4619 * the variable
4620 *
4621 * Returns 0 in case of success, -1 in case of error
4622 */
4623int
4624xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4625 const xmlChar *ns_uri,
4626 xmlXPathObjectPtr value) {
4627 if (ctxt == NULL)
4628 return(-1);
4629 if (name == NULL)
4630 return(-1);
4631
4632 if (ctxt->varHash == NULL)
4633 ctxt->varHash = xmlHashCreate(0);
4634 if (ctxt->varHash == NULL)
4635 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00004636 if (value == NULL)
4637 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4638 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00004639 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4640 (void *) value,
4641 (xmlHashDeallocator)xmlXPathFreeObject));
4642}
4643
4644/**
4645 * xmlXPathRegisterVariableLookup:
4646 * @ctxt: the XPath context
4647 * @f: the lookup function
4648 * @data: the lookup data
4649 *
4650 * register an external mechanism to do variable lookup
4651 */
4652void
4653xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4654 xmlXPathVariableLookupFunc f, void *data) {
4655 if (ctxt == NULL)
4656 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00004657 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00004658 ctxt->varLookupData = data;
4659}
4660
4661/**
4662 * xmlXPathVariableLookup:
4663 * @ctxt: the XPath context
4664 * @name: the variable name
4665 *
4666 * Search in the Variable array of the context for the given
4667 * variable value.
4668 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004669 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004670 */
4671xmlXPathObjectPtr
4672xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4673 if (ctxt == NULL)
4674 return(NULL);
4675
4676 if (ctxt->varLookupFunc != NULL) {
4677 xmlXPathObjectPtr ret;
4678
4679 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4680 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00004681 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004682 }
4683 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4684}
4685
4686/**
4687 * xmlXPathVariableLookupNS:
4688 * @ctxt: the XPath context
4689 * @name: the variable name
4690 * @ns_uri: the variable namespace URI
4691 *
4692 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00004693 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00004694 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00004695 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00004696 */
4697xmlXPathObjectPtr
4698xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4699 const xmlChar *ns_uri) {
4700 if (ctxt == NULL)
4701 return(NULL);
4702
4703 if (ctxt->varLookupFunc != NULL) {
4704 xmlXPathObjectPtr ret;
4705
4706 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4707 (ctxt->varLookupData, name, ns_uri);
4708 if (ret != NULL) return(ret);
4709 }
4710
4711 if (ctxt->varHash == NULL)
4712 return(NULL);
4713 if (name == NULL)
4714 return(NULL);
4715
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004716 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
Daniel Veillard8c357d52001-07-03 23:43:33 +00004717 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00004718}
4719
4720/**
4721 * xmlXPathRegisteredVariablesCleanup:
4722 * @ctxt: the XPath context
4723 *
4724 * Cleanup the XPath context data associated to registered variables
4725 */
4726void
4727xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4728 if (ctxt == NULL)
4729 return;
4730
Daniel Veillard76d66f42001-05-16 21:05:17 +00004731 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00004732 ctxt->varHash = NULL;
4733}
4734
4735/**
4736 * xmlXPathRegisterNs:
4737 * @ctxt: the XPath context
4738 * @prefix: the namespace prefix
4739 * @ns_uri: the namespace name
4740 *
4741 * Register a new namespace. If @ns_uri is NULL it unregisters
4742 * the namespace
4743 *
4744 * Returns 0 in case of success, -1 in case of error
4745 */
4746int
4747xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4748 const xmlChar *ns_uri) {
4749 if (ctxt == NULL)
4750 return(-1);
4751 if (prefix == NULL)
4752 return(-1);
4753
4754 if (ctxt->nsHash == NULL)
4755 ctxt->nsHash = xmlHashCreate(10);
4756 if (ctxt->nsHash == NULL)
4757 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00004758 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00004759 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00004760 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00004761 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00004762 (xmlHashDeallocator)xmlFree));
4763}
4764
4765/**
4766 * xmlXPathNsLookup:
4767 * @ctxt: the XPath context
4768 * @prefix: the namespace prefix value
4769 *
4770 * Search in the namespace declaration array of the context for the given
4771 * namespace name associated to the given prefix
4772 *
4773 * Returns the value or NULL if not found
4774 */
4775const xmlChar *
4776xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4777 if (ctxt == NULL)
4778 return(NULL);
4779 if (prefix == NULL)
4780 return(NULL);
4781
4782#ifdef XML_XML_NAMESPACE
4783 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4784 return(XML_XML_NAMESPACE);
4785#endif
4786
Daniel Veillardc8f620b2001-04-30 20:31:33 +00004787 if (ctxt->namespaces != NULL) {
4788 int i;
4789
4790 for (i = 0;i < ctxt->nsNr;i++) {
4791 if ((ctxt->namespaces[i] != NULL) &&
4792 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4793 return(ctxt->namespaces[i]->href);
4794 }
4795 }
Owen Taylor3473f882001-02-23 17:55:21 +00004796
4797 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4798}
4799
4800/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004801 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00004802 * @ctxt: the XPath context
4803 *
4804 * Cleanup the XPath context data associated to registered variables
4805 */
4806void
4807xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4808 if (ctxt == NULL)
4809 return;
4810
Daniel Veillard42766c02002-08-22 20:52:17 +00004811 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00004812 ctxt->nsHash = NULL;
4813}
4814
4815/************************************************************************
4816 * *
4817 * Routines to handle Values *
4818 * *
4819 ************************************************************************/
4820
William M. Brack08171912003-12-29 02:52:11 +00004821/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00004822
4823/**
4824 * xmlXPathNewFloat:
4825 * @val: the double value
4826 *
4827 * Create a new xmlXPathObjectPtr of type double and of value @val
4828 *
4829 * Returns the newly created object.
4830 */
4831xmlXPathObjectPtr
4832xmlXPathNewFloat(double val) {
4833 xmlXPathObjectPtr ret;
4834
4835 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4836 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004837 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004838 return(NULL);
4839 }
4840 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4841 ret->type = XPATH_NUMBER;
4842 ret->floatval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004843#ifdef XP_DEBUG_OBJ_USAGE
4844 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
4845#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004846 return(ret);
4847}
4848
4849/**
4850 * xmlXPathNewBoolean:
4851 * @val: the boolean value
4852 *
4853 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4854 *
4855 * Returns the newly created object.
4856 */
4857xmlXPathObjectPtr
4858xmlXPathNewBoolean(int val) {
4859 xmlXPathObjectPtr ret;
4860
4861 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4862 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004863 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004864 return(NULL);
4865 }
4866 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4867 ret->type = XPATH_BOOLEAN;
4868 ret->boolval = (val != 0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004869#ifdef XP_DEBUG_OBJ_USAGE
4870 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
4871#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004872 return(ret);
4873}
4874
4875/**
4876 * xmlXPathNewString:
4877 * @val: the xmlChar * value
4878 *
4879 * Create a new xmlXPathObjectPtr of type string and of value @val
4880 *
4881 * Returns the newly created object.
4882 */
4883xmlXPathObjectPtr
4884xmlXPathNewString(const xmlChar *val) {
4885 xmlXPathObjectPtr ret;
4886
4887 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4888 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004889 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004890 return(NULL);
4891 }
4892 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4893 ret->type = XPATH_STRING;
4894 if (val != NULL)
4895 ret->stringval = xmlStrdup(val);
4896 else
4897 ret->stringval = xmlStrdup((const xmlChar *)"");
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004898#ifdef XP_DEBUG_OBJ_USAGE
4899 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4900#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004901 return(ret);
4902}
4903
4904/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004905 * xmlXPathWrapString:
4906 * @val: the xmlChar * value
4907 *
4908 * Wraps the @val string into an XPath object.
4909 *
4910 * Returns the newly created object.
4911 */
4912xmlXPathObjectPtr
4913xmlXPathWrapString (xmlChar *val) {
4914 xmlXPathObjectPtr ret;
4915
4916 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4917 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004918 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004919 return(NULL);
4920 }
4921 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4922 ret->type = XPATH_STRING;
4923 ret->stringval = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004924#ifdef XP_DEBUG_OBJ_USAGE
4925 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4926#endif
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004927 return(ret);
4928}
4929
4930/**
Owen Taylor3473f882001-02-23 17:55:21 +00004931 * xmlXPathNewCString:
4932 * @val: the char * value
4933 *
4934 * Create a new xmlXPathObjectPtr of type string and of value @val
4935 *
4936 * Returns the newly created object.
4937 */
4938xmlXPathObjectPtr
4939xmlXPathNewCString(const char *val) {
4940 xmlXPathObjectPtr ret;
4941
4942 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4943 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004944 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004945 return(NULL);
4946 }
4947 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4948 ret->type = XPATH_STRING;
4949 ret->stringval = xmlStrdup(BAD_CAST val);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004950#ifdef XP_DEBUG_OBJ_USAGE
4951 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
4952#endif
Owen Taylor3473f882001-02-23 17:55:21 +00004953 return(ret);
4954}
4955
4956/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004957 * xmlXPathWrapCString:
4958 * @val: the char * value
4959 *
4960 * Wraps a string into an XPath object.
4961 *
4962 * Returns the newly created object.
4963 */
4964xmlXPathObjectPtr
4965xmlXPathWrapCString (char * val) {
4966 return(xmlXPathWrapString((xmlChar *)(val)));
4967}
4968
4969/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004970 * xmlXPathWrapExternal:
4971 * @val: the user data
4972 *
4973 * Wraps the @val data into an XPath object.
4974 *
4975 * Returns the newly created object.
4976 */
4977xmlXPathObjectPtr
4978xmlXPathWrapExternal (void *val) {
4979 xmlXPathObjectPtr ret;
4980
4981 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4982 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004983 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004984 return(NULL);
4985 }
4986 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4987 ret->type = XPATH_USERS;
4988 ret->user = val;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00004989#ifdef XP_DEBUG_OBJ_USAGE
4990 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
4991#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00004992 return(ret);
4993}
4994
4995/**
Owen Taylor3473f882001-02-23 17:55:21 +00004996 * xmlXPathObjectCopy:
4997 * @val: the original object
4998 *
4999 * allocate a new copy of a given object
5000 *
5001 * Returns the newly created object.
5002 */
5003xmlXPathObjectPtr
5004xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5005 xmlXPathObjectPtr ret;
5006
5007 if (val == NULL)
5008 return(NULL);
5009
5010 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5011 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005012 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005013 return(NULL);
5014 }
5015 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005016#ifdef XP_DEBUG_OBJ_USAGE
5017 xmlXPathDebugObjUsageRequested(NULL, val->type);
5018#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005019 switch (val->type) {
5020 case XPATH_BOOLEAN:
5021 case XPATH_NUMBER:
5022 case XPATH_POINT:
5023 case XPATH_RANGE:
5024 break;
5025 case XPATH_STRING:
5026 ret->stringval = xmlStrdup(val->stringval);
5027 break;
5028 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00005029#if 0
5030/*
5031 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5032 this previous handling is no longer correct, and can cause some serious
5033 problems (ref. bug 145547)
5034*/
Owen Taylor3473f882001-02-23 17:55:21 +00005035 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005036 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005037 xmlNodePtr cur, tmp;
5038 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005039
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005040 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00005041 top = xmlNewDoc(NULL);
5042 top->name = (char *)
5043 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005044 ret->user = top;
5045 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005046 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00005047 cur = val->nodesetval->nodeTab[0]->children;
5048 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00005049 tmp = xmlDocCopyNode(cur, top, 1);
5050 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00005051 cur = cur->next;
5052 }
5053 }
William M. Bracke9449c52004-07-11 14:41:20 +00005054
Daniel Veillard9adc0462003-03-24 18:39:54 +00005055 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005056 } else
Owen Taylor3473f882001-02-23 17:55:21 +00005057 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005058 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00005059 break;
William M. Bracke9449c52004-07-11 14:41:20 +00005060#endif
Owen Taylor3473f882001-02-23 17:55:21 +00005061 case XPATH_NODESET:
5062 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005063 /* Do not deallocate the copied tree value */
5064 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005065 break;
5066 case XPATH_LOCATIONSET:
5067#ifdef LIBXML_XPTR_ENABLED
5068 {
5069 xmlLocationSetPtr loc = val->user;
5070 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5071 break;
5072 }
5073#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00005074 case XPATH_USERS:
5075 ret->user = val->user;
5076 break;
5077 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00005078 xmlGenericError(xmlGenericErrorContext,
5079 "xmlXPathObjectCopy: unsupported type %d\n",
5080 val->type);
5081 break;
5082 }
5083 return(ret);
5084}
5085
5086/**
5087 * xmlXPathFreeObject:
5088 * @obj: the object to free
5089 *
5090 * Free up an xmlXPathObjectPtr object.
5091 */
5092void
5093xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5094 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005095 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00005096 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00005097#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005098 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00005099 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00005100 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00005101 } else
5102#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005103 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
William M. Bracke9449c52004-07-11 14:41:20 +00005104 if (obj->nodesetval != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005105 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillard77851712001-02-27 21:54:07 +00005106 } else {
5107 if (obj->nodesetval != NULL)
5108 xmlXPathFreeNodeSet(obj->nodesetval);
5109 }
Owen Taylor3473f882001-02-23 17:55:21 +00005110#ifdef LIBXML_XPTR_ENABLED
5111 } else if (obj->type == XPATH_LOCATIONSET) {
5112 if (obj->user != NULL)
5113 xmlXPtrFreeLocationSet(obj->user);
5114#endif
5115 } else if (obj->type == XPATH_STRING) {
5116 if (obj->stringval != NULL)
5117 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00005118 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005119#ifdef XP_DEBUG_OBJ_USAGE
5120 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5121#endif
5122 xmlFree(obj);
5123}
Owen Taylor3473f882001-02-23 17:55:21 +00005124
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005125/**
5126 * xmlXPathReleaseObject:
5127 * @obj: the xmlXPathObjectPtr to free or to cache
5128 *
5129 * Depending on the state of the cache this frees the given
5130 * XPath object or stores it in the cache.
5131 */
5132static void
5133xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5134{
5135#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5136 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5137 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5138
5139#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5140
5141 if (obj == NULL)
5142 return;
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005143 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005144 xmlXPathFreeObject(obj);
5145 } else {
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005146 xmlXPathContextCachePtr cache =
5147 (xmlXPathContextCachePtr) ctxt->cache;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005148
5149 switch (obj->type) {
5150 case XPATH_NODESET:
5151 case XPATH_XSLT_TREE:
5152 if (obj->nodesetval != NULL) {
5153 if (obj->boolval) {
5154 /*
5155 * It looks like the @boolval is used for
5156 * evaluation if this an XSLT Result Tree Fragment.
5157 * TODO: Check if this assumption is correct.
5158 */
5159 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5160 xmlXPathFreeValueTree(obj->nodesetval);
5161 obj->nodesetval = NULL;
5162 } else if ((obj->nodesetval->nodeMax <= 40) &&
5163 (XP_CACHE_WANTS(cache->nodesetObjs,
5164 cache->maxNodeset)))
5165 {
5166 XP_CACHE_ADD(cache->nodesetObjs, obj);
5167 goto obj_cached;
5168 } else {
5169 xmlXPathFreeNodeSet(obj->nodesetval);
5170 obj->nodesetval = NULL;
5171 }
5172 }
5173 break;
5174 case XPATH_STRING:
5175 if (obj->stringval != NULL)
5176 xmlFree(obj->stringval);
5177
5178 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5179 XP_CACHE_ADD(cache->stringObjs, obj);
5180 goto obj_cached;
5181 }
5182 break;
5183 case XPATH_BOOLEAN:
5184 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5185 XP_CACHE_ADD(cache->booleanObjs, obj);
5186 goto obj_cached;
5187 }
5188 break;
5189 case XPATH_NUMBER:
5190 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5191 XP_CACHE_ADD(cache->numberObjs, obj);
5192 goto obj_cached;
5193 }
5194 break;
5195#ifdef LIBXML_XPTR_ENABLED
5196 case XPATH_LOCATIONSET:
5197 if (obj->user != NULL) {
5198 xmlXPtrFreeLocationSet(obj->user);
5199 }
5200 goto free_obj;
5201#endif
5202 default:
5203 goto free_obj;
5204 }
5205
5206 /*
5207 * Fallback to adding to the misc-objects slot.
5208 */
5209 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5210 XP_CACHE_ADD(cache->miscObjs, obj);
5211 } else
5212 goto free_obj;
5213
5214obj_cached:
5215
5216#ifdef XP_DEBUG_OBJ_USAGE
5217 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5218#endif
5219
5220 if (obj->nodesetval != NULL) {
5221 xmlNodeSetPtr tmpset = obj->nodesetval;
5222
5223 /*
5224 * TODO: Due to those nasty ns-nodes, we need to traverse
5225 * the list and free the ns-nodes.
5226 * URGENT TODO: Check if it's actually slowing things down.
5227 * Maybe we shouldn't try to preserve the list.
5228 */
5229 if (tmpset->nodeNr > 1) {
5230 int i;
5231 xmlNodePtr node;
5232
5233 for (i = 0; i < tmpset->nodeNr; i++) {
5234 node = tmpset->nodeTab[i];
5235 if ((node != NULL) &&
5236 (node->type == XML_NAMESPACE_DECL))
5237 {
5238 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5239 }
5240 }
5241 } else if (tmpset->nodeNr == 1) {
5242 if ((tmpset->nodeTab[0] != NULL) &&
5243 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5244 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5245 }
5246 tmpset->nodeNr = 0;
5247 memset(obj, 0, sizeof(xmlXPathObject));
5248 obj->nodesetval = tmpset;
5249 } else
5250 memset(obj, 0, sizeof(xmlXPathObject));
5251
5252 return;
5253
5254free_obj:
5255 /*
5256 * Cache is full; free the object.
5257 */
5258 if (obj->nodesetval != NULL)
5259 xmlXPathFreeNodeSet(obj->nodesetval);
5260#ifdef XP_DEBUG_OBJ_USAGE
5261 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5262#endif
5263 xmlFree(obj);
5264 }
5265 return;
Owen Taylor3473f882001-02-23 17:55:21 +00005266}
5267
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005268
5269/************************************************************************
5270 * *
5271 * Type Casting Routines *
5272 * *
5273 ************************************************************************/
5274
5275/**
5276 * xmlXPathCastBooleanToString:
5277 * @val: a boolean
5278 *
5279 * Converts a boolean to its string value.
5280 *
5281 * Returns a newly allocated string.
5282 */
5283xmlChar *
5284xmlXPathCastBooleanToString (int val) {
5285 xmlChar *ret;
5286 if (val)
5287 ret = xmlStrdup((const xmlChar *) "true");
5288 else
5289 ret = xmlStrdup((const xmlChar *) "false");
5290 return(ret);
5291}
5292
5293/**
5294 * xmlXPathCastNumberToString:
5295 * @val: a number
5296 *
5297 * Converts a number to its string value.
5298 *
5299 * Returns a newly allocated string.
5300 */
5301xmlChar *
5302xmlXPathCastNumberToString (double val) {
5303 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00005304 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005305 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005306 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005307 break;
5308 case -1:
5309 ret = xmlStrdup((const xmlChar *) "-Infinity");
5310 break;
5311 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00005312 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005313 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005314 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5315 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005316 } else {
5317 /* could be improved */
5318 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00005319 xmlXPathFormatNumber(val, buf, 99);
5320 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005321 ret = xmlStrdup((const xmlChar *) buf);
5322 }
5323 }
5324 return(ret);
5325}
5326
5327/**
5328 * xmlXPathCastNodeToString:
5329 * @node: a node
5330 *
5331 * Converts a node to its string value.
5332 *
5333 * Returns a newly allocated string.
5334 */
5335xmlChar *
5336xmlXPathCastNodeToString (xmlNodePtr node) {
5337 return(xmlNodeGetContent(node));
5338}
5339
5340/**
5341 * xmlXPathCastNodeSetToString:
5342 * @ns: a node-set
5343 *
5344 * Converts a node-set to its string value.
5345 *
5346 * Returns a newly allocated string.
5347 */
5348xmlChar *
5349xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5350 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5351 return(xmlStrdup((const xmlChar *) ""));
5352
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00005353 if (ns->nodeNr > 1)
5354 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005355 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5356}
5357
5358/**
5359 * xmlXPathCastToString:
5360 * @val: an XPath object
5361 *
5362 * Converts an existing object to its string() equivalent
5363 *
5364 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005365 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005366 * string object).
5367 */
5368xmlChar *
5369xmlXPathCastToString(xmlXPathObjectPtr val) {
5370 xmlChar *ret = NULL;
5371
5372 if (val == NULL)
5373 return(xmlStrdup((const xmlChar *) ""));
5374 switch (val->type) {
5375 case XPATH_UNDEFINED:
5376#ifdef DEBUG_EXPR
5377 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5378#endif
5379 ret = xmlStrdup((const xmlChar *) "");
5380 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005381 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005382 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005383 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5384 break;
5385 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00005386 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005387 case XPATH_BOOLEAN:
5388 ret = xmlXPathCastBooleanToString(val->boolval);
5389 break;
5390 case XPATH_NUMBER: {
5391 ret = xmlXPathCastNumberToString(val->floatval);
5392 break;
5393 }
5394 case XPATH_USERS:
5395 case XPATH_POINT:
5396 case XPATH_RANGE:
5397 case XPATH_LOCATIONSET:
5398 TODO
5399 ret = xmlStrdup((const xmlChar *) "");
5400 break;
5401 }
5402 return(ret);
5403}
5404
5405/**
5406 * xmlXPathConvertString:
5407 * @val: an XPath object
5408 *
5409 * Converts an existing object to its string() equivalent
5410 *
5411 * Returns the new object, the old one is freed (or the operation
5412 * is done directly on @val)
5413 */
5414xmlXPathObjectPtr
5415xmlXPathConvertString(xmlXPathObjectPtr val) {
5416 xmlChar *res = NULL;
5417
5418 if (val == NULL)
5419 return(xmlXPathNewCString(""));
5420
5421 switch (val->type) {
5422 case XPATH_UNDEFINED:
5423#ifdef DEBUG_EXPR
5424 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5425#endif
5426 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005427 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005428 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005429 res = xmlXPathCastNodeSetToString(val->nodesetval);
5430 break;
5431 case XPATH_STRING:
5432 return(val);
5433 case XPATH_BOOLEAN:
5434 res = xmlXPathCastBooleanToString(val->boolval);
5435 break;
5436 case XPATH_NUMBER:
5437 res = xmlXPathCastNumberToString(val->floatval);
5438 break;
5439 case XPATH_USERS:
5440 case XPATH_POINT:
5441 case XPATH_RANGE:
5442 case XPATH_LOCATIONSET:
5443 TODO;
5444 break;
5445 }
5446 xmlXPathFreeObject(val);
5447 if (res == NULL)
5448 return(xmlXPathNewCString(""));
5449 return(xmlXPathWrapString(res));
5450}
5451
5452/**
5453 * xmlXPathCastBooleanToNumber:
5454 * @val: a boolean
5455 *
5456 * Converts a boolean to its number value
5457 *
5458 * Returns the number value
5459 */
5460double
5461xmlXPathCastBooleanToNumber(int val) {
5462 if (val)
5463 return(1.0);
5464 return(0.0);
5465}
5466
5467/**
5468 * xmlXPathCastStringToNumber:
5469 * @val: a string
5470 *
5471 * Converts a string to its number value
5472 *
5473 * Returns the number value
5474 */
5475double
5476xmlXPathCastStringToNumber(const xmlChar * val) {
5477 return(xmlXPathStringEvalNumber(val));
5478}
5479
5480/**
5481 * xmlXPathCastNodeToNumber:
5482 * @node: a node
5483 *
5484 * Converts a node to its number value
5485 *
5486 * Returns the number value
5487 */
5488double
5489xmlXPathCastNodeToNumber (xmlNodePtr node) {
5490 xmlChar *strval;
5491 double ret;
5492
5493 if (node == NULL)
5494 return(xmlXPathNAN);
5495 strval = xmlXPathCastNodeToString(node);
5496 if (strval == NULL)
5497 return(xmlXPathNAN);
5498 ret = xmlXPathCastStringToNumber(strval);
5499 xmlFree(strval);
5500
5501 return(ret);
5502}
5503
5504/**
5505 * xmlXPathCastNodeSetToNumber:
5506 * @ns: a node-set
5507 *
5508 * Converts a node-set to its number value
5509 *
5510 * Returns the number value
5511 */
5512double
5513xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5514 xmlChar *str;
5515 double ret;
5516
5517 if (ns == NULL)
5518 return(xmlXPathNAN);
5519 str = xmlXPathCastNodeSetToString(ns);
5520 ret = xmlXPathCastStringToNumber(str);
5521 xmlFree(str);
5522 return(ret);
5523}
5524
5525/**
5526 * xmlXPathCastToNumber:
5527 * @val: an XPath object
5528 *
5529 * Converts an XPath object to its number value
5530 *
5531 * Returns the number value
5532 */
5533double
5534xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5535 double ret = 0.0;
5536
5537 if (val == NULL)
5538 return(xmlXPathNAN);
5539 switch (val->type) {
5540 case XPATH_UNDEFINED:
5541#ifdef DEGUB_EXPR
5542 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5543#endif
5544 ret = xmlXPathNAN;
5545 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005546 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005547 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005548 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5549 break;
5550 case XPATH_STRING:
5551 ret = xmlXPathCastStringToNumber(val->stringval);
5552 break;
5553 case XPATH_NUMBER:
5554 ret = val->floatval;
5555 break;
5556 case XPATH_BOOLEAN:
5557 ret = xmlXPathCastBooleanToNumber(val->boolval);
5558 break;
5559 case XPATH_USERS:
5560 case XPATH_POINT:
5561 case XPATH_RANGE:
5562 case XPATH_LOCATIONSET:
5563 TODO;
5564 ret = xmlXPathNAN;
5565 break;
5566 }
5567 return(ret);
5568}
5569
5570/**
5571 * xmlXPathConvertNumber:
5572 * @val: an XPath object
5573 *
5574 * Converts an existing object to its number() equivalent
5575 *
5576 * Returns the new object, the old one is freed (or the operation
5577 * is done directly on @val)
5578 */
5579xmlXPathObjectPtr
5580xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5581 xmlXPathObjectPtr ret;
5582
5583 if (val == NULL)
5584 return(xmlXPathNewFloat(0.0));
5585 if (val->type == XPATH_NUMBER)
5586 return(val);
5587 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5588 xmlXPathFreeObject(val);
5589 return(ret);
5590}
5591
5592/**
5593 * xmlXPathCastNumberToBoolean:
5594 * @val: a number
5595 *
5596 * Converts a number to its boolean value
5597 *
5598 * Returns the boolean value
5599 */
5600int
5601xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00005602 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005603 return(0);
5604 return(1);
5605}
5606
5607/**
5608 * xmlXPathCastStringToBoolean:
5609 * @val: a string
5610 *
5611 * Converts a string to its boolean value
5612 *
5613 * Returns the boolean value
5614 */
5615int
5616xmlXPathCastStringToBoolean (const xmlChar *val) {
5617 if ((val == NULL) || (xmlStrlen(val) == 0))
5618 return(0);
5619 return(1);
5620}
5621
5622/**
5623 * xmlXPathCastNodeSetToBoolean:
5624 * @ns: a node-set
5625 *
5626 * Converts a node-set to its boolean value
5627 *
5628 * Returns the boolean value
5629 */
5630int
5631xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5632 if ((ns == NULL) || (ns->nodeNr == 0))
5633 return(0);
5634 return(1);
5635}
5636
5637/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00005638 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005639 * @val: an XPath object
5640 *
5641 * Converts an XPath object to its boolean value
5642 *
5643 * Returns the boolean value
5644 */
5645int
5646xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5647 int ret = 0;
5648
5649 if (val == NULL)
5650 return(0);
5651 switch (val->type) {
5652 case XPATH_UNDEFINED:
5653#ifdef DEBUG_EXPR
5654 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5655#endif
5656 ret = 0;
5657 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005658 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00005659 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005660 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5661 break;
5662 case XPATH_STRING:
5663 ret = xmlXPathCastStringToBoolean(val->stringval);
5664 break;
5665 case XPATH_NUMBER:
5666 ret = xmlXPathCastNumberToBoolean(val->floatval);
5667 break;
5668 case XPATH_BOOLEAN:
5669 ret = val->boolval;
5670 break;
5671 case XPATH_USERS:
5672 case XPATH_POINT:
5673 case XPATH_RANGE:
5674 case XPATH_LOCATIONSET:
5675 TODO;
5676 ret = 0;
5677 break;
5678 }
5679 return(ret);
5680}
5681
5682
5683/**
5684 * xmlXPathConvertBoolean:
5685 * @val: an XPath object
5686 *
5687 * Converts an existing object to its boolean() equivalent
5688 *
5689 * Returns the new object, the old one is freed (or the operation
5690 * is done directly on @val)
5691 */
5692xmlXPathObjectPtr
5693xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5694 xmlXPathObjectPtr ret;
5695
5696 if (val == NULL)
5697 return(xmlXPathNewBoolean(0));
5698 if (val->type == XPATH_BOOLEAN)
5699 return(val);
5700 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5701 xmlXPathFreeObject(val);
5702 return(ret);
5703}
5704
Owen Taylor3473f882001-02-23 17:55:21 +00005705/************************************************************************
5706 * *
5707 * Routines to handle XPath contexts *
5708 * *
5709 ************************************************************************/
5710
5711/**
5712 * xmlXPathNewContext:
5713 * @doc: the XML document
5714 *
5715 * Create a new xmlXPathContext
5716 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00005717 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00005718 */
5719xmlXPathContextPtr
5720xmlXPathNewContext(xmlDocPtr doc) {
5721 xmlXPathContextPtr ret;
5722
5723 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5724 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005725 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005726 return(NULL);
5727 }
5728 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5729 ret->doc = doc;
5730 ret->node = NULL;
5731
5732 ret->varHash = NULL;
5733
5734 ret->nb_types = 0;
5735 ret->max_types = 0;
5736 ret->types = NULL;
5737
5738 ret->funcHash = xmlHashCreate(0);
5739
5740 ret->nb_axis = 0;
5741 ret->max_axis = 0;
5742 ret->axis = NULL;
5743
5744 ret->nsHash = NULL;
5745 ret->user = NULL;
5746
5747 ret->contextSize = -1;
5748 ret->proximityPosition = -1;
5749
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005750#ifdef XP_DEFAULT_CACHE_ON
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005751 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00005752 xmlXPathFreeContext(ret);
5753 return(NULL);
5754 }
5755#endif
5756
5757 xmlXPathRegisterAllFunctions(ret);
5758
Owen Taylor3473f882001-02-23 17:55:21 +00005759 return(ret);
5760}
5761
5762/**
5763 * xmlXPathFreeContext:
5764 * @ctxt: the context to free
5765 *
5766 * Free up an xmlXPathContext
5767 */
5768void
5769xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005770 if (ctxt == NULL) return;
5771
Kasimier T. Buchcik58694692006-05-31 12:37:28 +00005772 if (ctxt->cache != NULL)
5773 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
Owen Taylor3473f882001-02-23 17:55:21 +00005774 xmlXPathRegisteredNsCleanup(ctxt);
5775 xmlXPathRegisteredFuncsCleanup(ctxt);
5776 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00005777 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00005778 xmlFree(ctxt);
5779}
5780
5781/************************************************************************
5782 * *
5783 * Routines to handle XPath parser contexts *
5784 * *
5785 ************************************************************************/
5786
5787#define CHECK_CTXT(ctxt) \
5788 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00005789 __xmlRaiseError(NULL, NULL, NULL, \
5790 NULL, NULL, XML_FROM_XPATH, \
5791 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5792 __FILE__, __LINE__, \
5793 NULL, NULL, NULL, 0, 0, \
5794 "NULL context pointer\n"); \
5795 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00005796 } \
5797
5798
5799#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00005800 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
5801 (ctxt->doc->children == NULL)) { \
5802 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00005803 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00005804 }
Owen Taylor3473f882001-02-23 17:55:21 +00005805
5806
5807/**
5808 * xmlXPathNewParserContext:
5809 * @str: the XPath expression
5810 * @ctxt: the XPath context
5811 *
5812 * Create a new xmlXPathParserContext
5813 *
5814 * Returns the xmlXPathParserContext just allocated.
5815 */
5816xmlXPathParserContextPtr
5817xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5818 xmlXPathParserContextPtr ret;
5819
5820 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5821 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005822 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005823 return(NULL);
5824 }
5825 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5826 ret->cur = ret->base = str;
5827 ret->context = ctxt;
5828
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005829 ret->comp = xmlXPathNewCompExpr();
5830 if (ret->comp == NULL) {
5831 xmlFree(ret->valueTab);
5832 xmlFree(ret);
5833 return(NULL);
5834 }
Daniel Veillard4773df22004-01-23 13:15:13 +00005835 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5836 ret->comp->dict = ctxt->dict;
5837 xmlDictReference(ret->comp->dict);
5838 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005839
5840 return(ret);
5841}
5842
5843/**
5844 * xmlXPathCompParserContext:
5845 * @comp: the XPath compiled expression
5846 * @ctxt: the XPath context
5847 *
5848 * Create a new xmlXPathParserContext when processing a compiled expression
5849 *
5850 * Returns the xmlXPathParserContext just allocated.
5851 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005852static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005853xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5854 xmlXPathParserContextPtr ret;
5855
5856 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5857 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005858 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005859 return(NULL);
5860 }
5861 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
5862
Owen Taylor3473f882001-02-23 17:55:21 +00005863 /* Allocate the value stack */
5864 ret->valueTab = (xmlXPathObjectPtr *)
5865 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005866 if (ret->valueTab == NULL) {
5867 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005868 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005869 return(NULL);
5870 }
Owen Taylor3473f882001-02-23 17:55:21 +00005871 ret->valueNr = 0;
5872 ret->valueMax = 10;
5873 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005874
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005875 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005876 ret->comp = comp;
5877
Owen Taylor3473f882001-02-23 17:55:21 +00005878 return(ret);
5879}
5880
5881/**
5882 * xmlXPathFreeParserContext:
5883 * @ctxt: the context to free
5884 *
5885 * Free up an xmlXPathParserContext
5886 */
5887void
5888xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5889 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00005890 xmlFree(ctxt->valueTab);
5891 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00005892 if (ctxt->comp != NULL) {
5893#ifdef XPATH_STREAMING
5894 if (ctxt->comp->stream != NULL) {
5895 xmlFreePatternList(ctxt->comp->stream);
5896 ctxt->comp->stream = NULL;
5897 }
5898#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005899 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00005900 }
Owen Taylor3473f882001-02-23 17:55:21 +00005901 xmlFree(ctxt);
5902}
5903
5904/************************************************************************
5905 * *
5906 * The implicit core function library *
5907 * *
5908 ************************************************************************/
5909
Owen Taylor3473f882001-02-23 17:55:21 +00005910/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00005911 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00005912 * @node: a node pointer
5913 *
5914 * Function computing the beginning of the string value of the node,
5915 * used to speed up comparisons
5916 *
5917 * Returns an int usable as a hash
5918 */
5919static unsigned int
5920xmlXPathNodeValHash(xmlNodePtr node) {
5921 int len = 2;
5922 const xmlChar * string = NULL;
5923 xmlNodePtr tmp = NULL;
5924 unsigned int ret = 0;
5925
5926 if (node == NULL)
5927 return(0);
5928
Daniel Veillard9adc0462003-03-24 18:39:54 +00005929 if (node->type == XML_DOCUMENT_NODE) {
5930 tmp = xmlDocGetRootElement((xmlDocPtr) node);
5931 if (tmp == NULL)
5932 node = node->children;
5933 else
5934 node = tmp;
5935
5936 if (node == NULL)
5937 return(0);
5938 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005939
5940 switch (node->type) {
5941 case XML_COMMENT_NODE:
5942 case XML_PI_NODE:
5943 case XML_CDATA_SECTION_NODE:
5944 case XML_TEXT_NODE:
5945 string = node->content;
5946 if (string == NULL)
5947 return(0);
5948 if (string[0] == 0)
5949 return(0);
5950 return(((unsigned int) string[0]) +
5951 (((unsigned int) string[1]) << 8));
5952 case XML_NAMESPACE_DECL:
5953 string = ((xmlNsPtr)node)->href;
5954 if (string == NULL)
5955 return(0);
5956 if (string[0] == 0)
5957 return(0);
5958 return(((unsigned int) string[0]) +
5959 (((unsigned int) string[1]) << 8));
5960 case XML_ATTRIBUTE_NODE:
5961 tmp = ((xmlAttrPtr) node)->children;
5962 break;
5963 case XML_ELEMENT_NODE:
5964 tmp = node->children;
5965 break;
5966 default:
5967 return(0);
5968 }
5969 while (tmp != NULL) {
5970 switch (tmp->type) {
5971 case XML_COMMENT_NODE:
5972 case XML_PI_NODE:
5973 case XML_CDATA_SECTION_NODE:
5974 case XML_TEXT_NODE:
5975 string = tmp->content;
5976 break;
5977 case XML_NAMESPACE_DECL:
5978 string = ((xmlNsPtr)tmp)->href;
5979 break;
5980 default:
5981 break;
5982 }
5983 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005984 if (len == 1) {
5985 return(ret + (((unsigned int) string[0]) << 8));
5986 }
5987 if (string[1] == 0) {
5988 len = 1;
5989 ret = (unsigned int) string[0];
5990 } else {
5991 return(((unsigned int) string[0]) +
5992 (((unsigned int) string[1]) << 8));
5993 }
5994 }
5995 /*
5996 * Skip to next node
5997 */
5998 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
5999 if (tmp->children->type != XML_ENTITY_DECL) {
6000 tmp = tmp->children;
6001 continue;
6002 }
6003 }
6004 if (tmp == node)
6005 break;
6006
6007 if (tmp->next != NULL) {
6008 tmp = tmp->next;
6009 continue;
6010 }
6011
6012 do {
6013 tmp = tmp->parent;
6014 if (tmp == NULL)
6015 break;
6016 if (tmp == node) {
6017 tmp = NULL;
6018 break;
6019 }
6020 if (tmp->next != NULL) {
6021 tmp = tmp->next;
6022 break;
6023 }
6024 } while (tmp != NULL);
6025 }
6026 return(ret);
6027}
6028
6029/**
6030 * xmlXPathStringHash:
6031 * @string: a string
6032 *
6033 * Function computing the beginning of the string value of the node,
6034 * used to speed up comparisons
6035 *
6036 * Returns an int usable as a hash
6037 */
6038static unsigned int
6039xmlXPathStringHash(const xmlChar * string) {
6040 if (string == NULL)
6041 return((unsigned int) 0);
6042 if (string[0] == 0)
6043 return(0);
6044 return(((unsigned int) string[0]) +
6045 (((unsigned int) string[1]) << 8));
6046}
6047
6048/**
Owen Taylor3473f882001-02-23 17:55:21 +00006049 * xmlXPathCompareNodeSetFloat:
6050 * @ctxt: the XPath Parser context
6051 * @inf: less than (1) or greater than (0)
6052 * @strict: is the comparison strict
6053 * @arg: the node set
6054 * @f: the value
6055 *
6056 * Implement the compare operation between a nodeset and a number
6057 * @ns < @val (1, 1, ...
6058 * @ns <= @val (1, 0, ...
6059 * @ns > @val (0, 1, ...
6060 * @ns >= @val (0, 0, ...
6061 *
6062 * If one object to be compared is a node-set and the other is a number,
6063 * then the comparison will be true if and only if there is a node in the
6064 * node-set such that the result of performing the comparison on the number
6065 * to be compared and on the result of converting the string-value of that
6066 * node to a number using the number function is true.
6067 *
6068 * Returns 0 or 1 depending on the results of the test.
6069 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006070static int
Owen Taylor3473f882001-02-23 17:55:21 +00006071xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6072 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6073 int i, ret = 0;
6074 xmlNodeSetPtr ns;
6075 xmlChar *str2;
6076
6077 if ((f == NULL) || (arg == NULL) ||
6078 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006079 xmlXPathReleaseObject(ctxt->context, arg);
6080 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006081 return(0);
6082 }
6083 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006084 if (ns != NULL) {
6085 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006086 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006087 if (str2 != NULL) {
6088 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006089 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006090 xmlFree(str2);
6091 xmlXPathNumberFunction(ctxt, 1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006092 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006093 ret = xmlXPathCompareValues(ctxt, inf, strict);
6094 if (ret)
6095 break;
6096 }
6097 }
Owen Taylor3473f882001-02-23 17:55:21 +00006098 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006099 xmlXPathReleaseObject(ctxt->context, arg);
6100 xmlXPathReleaseObject(ctxt->context, f);
Owen Taylor3473f882001-02-23 17:55:21 +00006101 return(ret);
6102}
6103
6104/**
6105 * xmlXPathCompareNodeSetString:
6106 * @ctxt: the XPath Parser context
6107 * @inf: less than (1) or greater than (0)
6108 * @strict: is the comparison strict
6109 * @arg: the node set
6110 * @s: the value
6111 *
6112 * Implement the compare operation between a nodeset and a string
6113 * @ns < @val (1, 1, ...
6114 * @ns <= @val (1, 0, ...
6115 * @ns > @val (0, 1, ...
6116 * @ns >= @val (0, 0, ...
6117 *
6118 * If one object to be compared is a node-set and the other is a string,
6119 * then the comparison will be true if and only if there is a node in
6120 * the node-set such that the result of performing the comparison on the
6121 * string-value of the node and the other string is true.
6122 *
6123 * Returns 0 or 1 depending on the results of the test.
6124 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006125static int
Owen Taylor3473f882001-02-23 17:55:21 +00006126xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6127 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6128 int i, ret = 0;
6129 xmlNodeSetPtr ns;
6130 xmlChar *str2;
6131
6132 if ((s == NULL) || (arg == NULL) ||
6133 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006134 xmlXPathReleaseObject(ctxt->context, arg);
6135 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006136 return(0);
6137 }
6138 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00006139 if (ns != NULL) {
6140 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006141 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006142 if (str2 != NULL) {
6143 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006144 xmlXPathCacheNewString(ctxt->context, str2));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006145 xmlFree(str2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006146 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
Daniel Veillard911f49a2001-04-07 15:39:35 +00006147 ret = xmlXPathCompareValues(ctxt, inf, strict);
6148 if (ret)
6149 break;
6150 }
6151 }
Owen Taylor3473f882001-02-23 17:55:21 +00006152 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006153 xmlXPathReleaseObject(ctxt->context, arg);
6154 xmlXPathReleaseObject(ctxt->context, s);
Owen Taylor3473f882001-02-23 17:55:21 +00006155 return(ret);
6156}
6157
6158/**
6159 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006160 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00006161 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006162 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00006163 * @arg2: the second node set object
6164 *
6165 * Implement the compare operation on nodesets:
6166 *
6167 * If both objects to be compared are node-sets, then the comparison
6168 * will be true if and only if there is a node in the first node-set
6169 * and a node in the second node-set such that the result of performing
6170 * the comparison on the string-values of the two nodes is true.
6171 * ....
6172 * When neither object to be compared is a node-set and the operator
6173 * is <=, <, >= or >, then the objects are compared by converting both
6174 * objects to numbers and comparing the numbers according to IEEE 754.
6175 * ....
6176 * The number function converts its argument to a number as follows:
6177 * - a string that consists of optional whitespace followed by an
6178 * optional minus sign followed by a Number followed by whitespace
6179 * is converted to the IEEE 754 number that is nearest (according
6180 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6181 * represented by the string; any other string is converted to NaN
6182 *
6183 * Conclusion all nodes need to be converted first to their string value
6184 * and then the comparison must be done when possible
6185 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006186static int
6187xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00006188 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6189 int i, j, init = 0;
6190 double val1;
6191 double *values2;
6192 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006193 xmlNodeSetPtr ns1;
6194 xmlNodeSetPtr ns2;
6195
6196 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006197 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6198 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006199 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006200 }
Owen Taylor3473f882001-02-23 17:55:21 +00006201 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00006202 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6203 xmlXPathFreeObject(arg1);
6204 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006205 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006206 }
Owen Taylor3473f882001-02-23 17:55:21 +00006207
6208 ns1 = arg1->nodesetval;
6209 ns2 = arg2->nodesetval;
6210
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006211 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006212 xmlXPathFreeObject(arg1);
6213 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006214 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006215 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006216 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00006217 xmlXPathFreeObject(arg1);
6218 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006219 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006220 }
Owen Taylor3473f882001-02-23 17:55:21 +00006221
6222 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6223 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006224 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00006225 xmlXPathFreeObject(arg1);
6226 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006227 return(0);
6228 }
6229 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006230 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00006231 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00006232 continue;
6233 for (j = 0;j < ns2->nodeNr;j++) {
6234 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006235 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00006236 }
Daniel Veillardcda96922001-08-21 10:56:31 +00006237 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00006238 continue;
6239 if (inf && strict)
6240 ret = (val1 < values2[j]);
6241 else if (inf && !strict)
6242 ret = (val1 <= values2[j]);
6243 else if (!inf && strict)
6244 ret = (val1 > values2[j]);
6245 else if (!inf && !strict)
6246 ret = (val1 >= values2[j]);
6247 if (ret)
6248 break;
6249 }
6250 if (ret)
6251 break;
6252 init = 1;
6253 }
6254 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00006255 xmlXPathFreeObject(arg1);
6256 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006257 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006258}
6259
6260/**
6261 * xmlXPathCompareNodeSetValue:
6262 * @ctxt: the XPath Parser context
6263 * @inf: less than (1) or greater than (0)
6264 * @strict: is the comparison strict
6265 * @arg: the node set
6266 * @val: the value
6267 *
6268 * Implement the compare operation between a nodeset and a value
6269 * @ns < @val (1, 1, ...
6270 * @ns <= @val (1, 0, ...
6271 * @ns > @val (0, 1, ...
6272 * @ns >= @val (0, 0, ...
6273 *
6274 * If one object to be compared is a node-set and the other is a boolean,
6275 * then the comparison will be true if and only if the result of performing
6276 * the comparison on the boolean and on the result of converting
6277 * the node-set to a boolean using the boolean function is true.
6278 *
6279 * Returns 0 or 1 depending on the results of the test.
6280 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006281static int
Owen Taylor3473f882001-02-23 17:55:21 +00006282xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6283 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6284 if ((val == NULL) || (arg == NULL) ||
6285 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6286 return(0);
6287
6288 switch(val->type) {
6289 case XPATH_NUMBER:
6290 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6291 case XPATH_NODESET:
6292 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006293 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00006294 case XPATH_STRING:
6295 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6296 case XPATH_BOOLEAN:
6297 valuePush(ctxt, arg);
6298 xmlXPathBooleanFunction(ctxt, 1);
6299 valuePush(ctxt, val);
6300 return(xmlXPathCompareValues(ctxt, inf, strict));
6301 default:
6302 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00006303 }
6304 return(0);
6305}
6306
6307/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006308 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00006309 * @arg: the nodeset object argument
6310 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00006311 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006312 *
6313 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6314 * If one object to be compared is a node-set and the other is a string,
6315 * then the comparison will be true if and only if there is a node in
6316 * the node-set such that the result of performing the comparison on the
6317 * string-value of the node and the other string is true.
6318 *
6319 * Returns 0 or 1 depending on the results of the test.
6320 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006321static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006322xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006323{
Owen Taylor3473f882001-02-23 17:55:21 +00006324 int i;
6325 xmlNodeSetPtr ns;
6326 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006327 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00006328
6329 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00006330 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6331 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006332 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00006333 /*
6334 * A NULL nodeset compared with a string is always false
6335 * (since there is no node equal, and no node not equal)
6336 */
6337 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00006338 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00006339 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006340 for (i = 0; i < ns->nodeNr; i++) {
6341 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6342 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6343 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6344 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006345 if (neq)
6346 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006347 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00006348 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6349 if (neq)
6350 continue;
6351 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006352 } else if (neq) {
6353 if (str2 != NULL)
6354 xmlFree(str2);
6355 return (1);
6356 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006357 if (str2 != NULL)
6358 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006359 } else if (neq)
6360 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00006361 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006362 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00006363}
6364
6365/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006366 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00006367 * @arg: the nodeset object argument
6368 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00006369 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006370 *
6371 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6372 * If one object to be compared is a node-set and the other is a number,
6373 * then the comparison will be true if and only if there is a node in
6374 * the node-set such that the result of performing the comparison on the
6375 * number to be compared and on the result of converting the string-value
6376 * of that node to a number using the number function is true.
6377 *
6378 * Returns 0 or 1 depending on the results of the test.
6379 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006380static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006381xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6382 xmlXPathObjectPtr arg, double f, int neq) {
6383 int i, ret=0;
6384 xmlNodeSetPtr ns;
6385 xmlChar *str2;
6386 xmlXPathObjectPtr val;
6387 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00006388
6389 if ((arg == NULL) ||
6390 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6391 return(0);
6392
William M. Brack0c022ad2002-07-12 00:56:01 +00006393 ns = arg->nodesetval;
6394 if (ns != NULL) {
6395 for (i=0;i<ns->nodeNr;i++) {
6396 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6397 if (str2 != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006398 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
William M. Brack0c022ad2002-07-12 00:56:01 +00006399 xmlFree(str2);
6400 xmlXPathNumberFunction(ctxt, 1);
6401 val = valuePop(ctxt);
6402 v = val->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006403 xmlXPathReleaseObject(ctxt->context, val);
William M. Brack0c022ad2002-07-12 00:56:01 +00006404 if (!xmlXPathIsNaN(v)) {
6405 if ((!neq) && (v==f)) {
6406 ret = 1;
6407 break;
6408 } else if ((neq) && (v!=f)) {
6409 ret = 1;
6410 break;
6411 }
William M. Brack32f0f712005-07-14 07:00:33 +00006412 } else { /* NaN is unequal to any value */
6413 if (neq)
6414 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00006415 }
6416 }
6417 }
6418 }
6419
6420 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00006421}
6422
6423
6424/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00006425 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00006426 * @arg1: first nodeset object argument
6427 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00006428 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00006429 *
William M. Brack0c022ad2002-07-12 00:56:01 +00006430 * Implement the equal / not equal operation on XPath nodesets:
6431 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00006432 * If both objects to be compared are node-sets, then the comparison
6433 * will be true if and only if there is a node in the first node-set and
6434 * a node in the second node-set such that the result of performing the
6435 * comparison on the string-values of the two nodes is true.
6436 *
6437 * (needless to say, this is a costly operation)
6438 *
6439 * Returns 0 or 1 depending on the results of the test.
6440 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006441static int
William M. Brack0c022ad2002-07-12 00:56:01 +00006442xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00006443 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006444 unsigned int *hashs1;
6445 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00006446 xmlChar **values1;
6447 xmlChar **values2;
6448 int ret = 0;
6449 xmlNodeSetPtr ns1;
6450 xmlNodeSetPtr ns2;
6451
6452 if ((arg1 == NULL) ||
6453 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6454 return(0);
6455 if ((arg2 == NULL) ||
6456 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6457 return(0);
6458
6459 ns1 = arg1->nodesetval;
6460 ns2 = arg2->nodesetval;
6461
Daniel Veillard911f49a2001-04-07 15:39:35 +00006462 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006463 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006464 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00006465 return(0);
6466
6467 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00006468 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00006469 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006470 if (neq == 0)
6471 for (i = 0;i < ns1->nodeNr;i++)
6472 for (j = 0;j < ns2->nodeNr;j++)
6473 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6474 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00006475
6476 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006477 if (values1 == NULL) {
6478 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00006479 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006480 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006481 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6482 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006483 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006484 xmlFree(values1);
6485 return(0);
6486 }
Owen Taylor3473f882001-02-23 17:55:21 +00006487 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6488 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6489 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006490 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006491 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00006492 xmlFree(values1);
6493 return(0);
6494 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00006495 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6496 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00006497 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00006498 xmlFree(hashs1);
6499 xmlFree(values1);
6500 xmlFree(values2);
6501 return(0);
6502 }
Owen Taylor3473f882001-02-23 17:55:21 +00006503 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6504 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006505 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00006506 for (j = 0;j < ns2->nodeNr;j++) {
6507 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006508 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006509 if (hashs1[i] != hashs2[j]) {
6510 if (neq) {
6511 ret = 1;
6512 break;
6513 }
6514 }
6515 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006516 if (values1[i] == NULL)
6517 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6518 if (values2[j] == NULL)
6519 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00006520 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006521 if (ret)
6522 break;
6523 }
Owen Taylor3473f882001-02-23 17:55:21 +00006524 }
6525 if (ret)
6526 break;
6527 }
6528 for (i = 0;i < ns1->nodeNr;i++)
6529 if (values1[i] != NULL)
6530 xmlFree(values1[i]);
6531 for (j = 0;j < ns2->nodeNr;j++)
6532 if (values2[j] != NULL)
6533 xmlFree(values2[j]);
6534 xmlFree(values1);
6535 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006536 xmlFree(hashs1);
6537 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00006538 return(ret);
6539}
6540
William M. Brack0c022ad2002-07-12 00:56:01 +00006541static int
6542xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6543 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00006544 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00006545 /*
6546 *At this point we are assured neither arg1 nor arg2
6547 *is a nodeset, so we can just pick the appropriate routine.
6548 */
Owen Taylor3473f882001-02-23 17:55:21 +00006549 switch (arg1->type) {
6550 case XPATH_UNDEFINED:
6551#ifdef DEBUG_EXPR
6552 xmlGenericError(xmlGenericErrorContext,
6553 "Equal: undefined\n");
6554#endif
6555 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006556 case XPATH_BOOLEAN:
6557 switch (arg2->type) {
6558 case XPATH_UNDEFINED:
6559#ifdef DEBUG_EXPR
6560 xmlGenericError(xmlGenericErrorContext,
6561 "Equal: undefined\n");
6562#endif
6563 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006564 case XPATH_BOOLEAN:
6565#ifdef DEBUG_EXPR
6566 xmlGenericError(xmlGenericErrorContext,
6567 "Equal: %d boolean %d \n",
6568 arg1->boolval, arg2->boolval);
6569#endif
6570 ret = (arg1->boolval == arg2->boolval);
6571 break;
6572 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00006573 ret = (arg1->boolval ==
6574 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006575 break;
6576 case XPATH_STRING:
6577 if ((arg2->stringval == NULL) ||
6578 (arg2->stringval[0] == 0)) ret = 0;
6579 else
6580 ret = 1;
6581 ret = (arg1->boolval == ret);
6582 break;
6583 case XPATH_USERS:
6584 case XPATH_POINT:
6585 case XPATH_RANGE:
6586 case XPATH_LOCATIONSET:
6587 TODO
6588 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006589 case XPATH_NODESET:
6590 case XPATH_XSLT_TREE:
6591 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006592 }
6593 break;
6594 case XPATH_NUMBER:
6595 switch (arg2->type) {
6596 case XPATH_UNDEFINED:
6597#ifdef DEBUG_EXPR
6598 xmlGenericError(xmlGenericErrorContext,
6599 "Equal: undefined\n");
6600#endif
6601 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006602 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00006603 ret = (arg2->boolval==
6604 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00006605 break;
6606 case XPATH_STRING:
6607 valuePush(ctxt, arg2);
6608 xmlXPathNumberFunction(ctxt, 1);
6609 arg2 = valuePop(ctxt);
6610 /* no break on purpose */
6611 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006612 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006613 if (xmlXPathIsNaN(arg1->floatval) ||
6614 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006615 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006616 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6617 if (xmlXPathIsInf(arg2->floatval) == 1)
6618 ret = 1;
6619 else
6620 ret = 0;
6621 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6622 if (xmlXPathIsInf(arg2->floatval) == -1)
6623 ret = 1;
6624 else
6625 ret = 0;
6626 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6627 if (xmlXPathIsInf(arg1->floatval) == 1)
6628 ret = 1;
6629 else
6630 ret = 0;
6631 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6632 if (xmlXPathIsInf(arg1->floatval) == -1)
6633 ret = 1;
6634 else
6635 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006636 } else {
6637 ret = (arg1->floatval == arg2->floatval);
6638 }
Owen Taylor3473f882001-02-23 17:55:21 +00006639 break;
6640 case XPATH_USERS:
6641 case XPATH_POINT:
6642 case XPATH_RANGE:
6643 case XPATH_LOCATIONSET:
6644 TODO
6645 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006646 case XPATH_NODESET:
6647 case XPATH_XSLT_TREE:
6648 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006649 }
6650 break;
6651 case XPATH_STRING:
6652 switch (arg2->type) {
6653 case XPATH_UNDEFINED:
6654#ifdef DEBUG_EXPR
6655 xmlGenericError(xmlGenericErrorContext,
6656 "Equal: undefined\n");
6657#endif
6658 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006659 case XPATH_BOOLEAN:
6660 if ((arg1->stringval == NULL) ||
6661 (arg1->stringval[0] == 0)) ret = 0;
6662 else
6663 ret = 1;
6664 ret = (arg2->boolval == ret);
6665 break;
6666 case XPATH_STRING:
6667 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6668 break;
6669 case XPATH_NUMBER:
6670 valuePush(ctxt, arg1);
6671 xmlXPathNumberFunction(ctxt, 1);
6672 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006673 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00006674 if (xmlXPathIsNaN(arg1->floatval) ||
6675 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00006676 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006677 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6678 if (xmlXPathIsInf(arg2->floatval) == 1)
6679 ret = 1;
6680 else
6681 ret = 0;
6682 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6683 if (xmlXPathIsInf(arg2->floatval) == -1)
6684 ret = 1;
6685 else
6686 ret = 0;
6687 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6688 if (xmlXPathIsInf(arg1->floatval) == 1)
6689 ret = 1;
6690 else
6691 ret = 0;
6692 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6693 if (xmlXPathIsInf(arg1->floatval) == -1)
6694 ret = 1;
6695 else
6696 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006697 } else {
6698 ret = (arg1->floatval == arg2->floatval);
6699 }
Owen Taylor3473f882001-02-23 17:55:21 +00006700 break;
6701 case XPATH_USERS:
6702 case XPATH_POINT:
6703 case XPATH_RANGE:
6704 case XPATH_LOCATIONSET:
6705 TODO
6706 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006707 case XPATH_NODESET:
6708 case XPATH_XSLT_TREE:
6709 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006710 }
6711 break;
6712 case XPATH_USERS:
6713 case XPATH_POINT:
6714 case XPATH_RANGE:
6715 case XPATH_LOCATIONSET:
6716 TODO
6717 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00006718 case XPATH_NODESET:
6719 case XPATH_XSLT_TREE:
6720 break;
Owen Taylor3473f882001-02-23 17:55:21 +00006721 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006722 xmlXPathReleaseObject(ctxt->context, arg1);
6723 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006724 return(ret);
6725}
6726
William M. Brack0c022ad2002-07-12 00:56:01 +00006727/**
6728 * xmlXPathEqualValues:
6729 * @ctxt: the XPath Parser context
6730 *
6731 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6732 *
6733 * Returns 0 or 1 depending on the results of the test.
6734 */
6735int
6736xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6737 xmlXPathObjectPtr arg1, arg2, argtmp;
6738 int ret = 0;
6739
Daniel Veillard6128c012004-11-08 17:16:15 +00006740 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006741 arg2 = valuePop(ctxt);
6742 arg1 = valuePop(ctxt);
6743 if ((arg1 == NULL) || (arg2 == NULL)) {
6744 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006745 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006746 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006747 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006748 XP_ERROR0(XPATH_INVALID_OPERAND);
6749 }
6750
6751 if (arg1 == arg2) {
6752#ifdef DEBUG_EXPR
6753 xmlGenericError(xmlGenericErrorContext,
6754 "Equal: by pointer\n");
6755#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00006756 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006757 return(1);
6758 }
6759
6760 /*
6761 *If either argument is a nodeset, it's a 'special case'
6762 */
6763 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6764 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6765 /*
6766 *Hack it to assure arg1 is the nodeset
6767 */
6768 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6769 argtmp = arg2;
6770 arg2 = arg1;
6771 arg1 = argtmp;
6772 }
6773 switch (arg2->type) {
6774 case XPATH_UNDEFINED:
6775#ifdef DEBUG_EXPR
6776 xmlGenericError(xmlGenericErrorContext,
6777 "Equal: undefined\n");
6778#endif
6779 break;
6780 case XPATH_NODESET:
6781 case XPATH_XSLT_TREE:
6782 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6783 break;
6784 case XPATH_BOOLEAN:
6785 if ((arg1->nodesetval == NULL) ||
6786 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6787 else
6788 ret = 1;
6789 ret = (ret == arg2->boolval);
6790 break;
6791 case XPATH_NUMBER:
6792 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6793 break;
6794 case XPATH_STRING:
6795 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6796 break;
6797 case XPATH_USERS:
6798 case XPATH_POINT:
6799 case XPATH_RANGE:
6800 case XPATH_LOCATIONSET:
6801 TODO
6802 break;
6803 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006804 xmlXPathReleaseObject(ctxt->context, arg1);
6805 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006806 return(ret);
6807 }
6808
6809 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6810}
6811
6812/**
6813 * xmlXPathNotEqualValues:
6814 * @ctxt: the XPath Parser context
6815 *
6816 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6817 *
6818 * Returns 0 or 1 depending on the results of the test.
6819 */
6820int
6821xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6822 xmlXPathObjectPtr arg1, arg2, argtmp;
6823 int ret = 0;
6824
Daniel Veillard6128c012004-11-08 17:16:15 +00006825 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006826 arg2 = valuePop(ctxt);
6827 arg1 = valuePop(ctxt);
6828 if ((arg1 == NULL) || (arg2 == NULL)) {
6829 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006830 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006831 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006832 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006833 XP_ERROR0(XPATH_INVALID_OPERAND);
6834 }
6835
6836 if (arg1 == arg2) {
6837#ifdef DEBUG_EXPR
6838 xmlGenericError(xmlGenericErrorContext,
6839 "NotEqual: by pointer\n");
6840#endif
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006841 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006842 return(0);
6843 }
6844
6845 /*
6846 *If either argument is a nodeset, it's a 'special case'
6847 */
6848 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6849 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6850 /*
6851 *Hack it to assure arg1 is the nodeset
6852 */
6853 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6854 argtmp = arg2;
6855 arg2 = arg1;
6856 arg1 = argtmp;
6857 }
6858 switch (arg2->type) {
6859 case XPATH_UNDEFINED:
6860#ifdef DEBUG_EXPR
6861 xmlGenericError(xmlGenericErrorContext,
6862 "NotEqual: undefined\n");
6863#endif
6864 break;
6865 case XPATH_NODESET:
6866 case XPATH_XSLT_TREE:
6867 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6868 break;
6869 case XPATH_BOOLEAN:
6870 if ((arg1->nodesetval == NULL) ||
6871 (arg1->nodesetval->nodeNr == 0)) ret = 0;
6872 else
6873 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00006874 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00006875 break;
6876 case XPATH_NUMBER:
6877 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6878 break;
6879 case XPATH_STRING:
6880 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6881 break;
6882 case XPATH_USERS:
6883 case XPATH_POINT:
6884 case XPATH_RANGE:
6885 case XPATH_LOCATIONSET:
6886 TODO
6887 break;
6888 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006889 xmlXPathReleaseObject(ctxt->context, arg1);
6890 xmlXPathReleaseObject(ctxt->context, arg2);
William M. Brack0c022ad2002-07-12 00:56:01 +00006891 return(ret);
6892 }
6893
6894 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6895}
Owen Taylor3473f882001-02-23 17:55:21 +00006896
6897/**
6898 * xmlXPathCompareValues:
6899 * @ctxt: the XPath Parser context
6900 * @inf: less than (1) or greater than (0)
6901 * @strict: is the comparison strict
6902 *
6903 * Implement the compare operation on XPath objects:
6904 * @arg1 < @arg2 (1, 1, ...
6905 * @arg1 <= @arg2 (1, 0, ...
6906 * @arg1 > @arg2 (0, 1, ...
6907 * @arg1 >= @arg2 (0, 0, ...
6908 *
6909 * When neither object to be compared is a node-set and the operator is
6910 * <=, <, >=, >, then the objects are compared by converted both objects
6911 * to numbers and comparing the numbers according to IEEE 754. The <
6912 * comparison will be true if and only if the first number is less than the
6913 * second number. The <= comparison will be true if and only if the first
6914 * number is less than or equal to the second number. The > comparison
6915 * will be true if and only if the first number is greater than the second
6916 * number. The >= comparison will be true if and only if the first number
6917 * is greater than or equal to the second number.
6918 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006919 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00006920 */
6921int
6922xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006923 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006924 xmlXPathObjectPtr arg1, arg2;
6925
Daniel Veillard6128c012004-11-08 17:16:15 +00006926 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00006927 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006928 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00006929 if ((arg1 == NULL) || (arg2 == NULL)) {
6930 if (arg1 != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006931 xmlXPathReleaseObject(ctxt->context, arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00006932 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006933 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006934 XP_ERROR0(XPATH_INVALID_OPERAND);
6935 }
6936
William M. Brack0c022ad2002-07-12 00:56:01 +00006937 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6938 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00006939 /*
6940 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6941 * are not freed from within this routine; they will be freed from the
6942 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6943 */
William M. Brack0c022ad2002-07-12 00:56:01 +00006944 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6945 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006946 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006947 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00006948 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006949 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6950 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006951 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00006952 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6953 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00006954 }
6955 }
6956 return(ret);
6957 }
6958
6959 if (arg1->type != XPATH_NUMBER) {
6960 valuePush(ctxt, arg1);
6961 xmlXPathNumberFunction(ctxt, 1);
6962 arg1 = valuePop(ctxt);
6963 }
6964 if (arg1->type != XPATH_NUMBER) {
6965 xmlXPathFreeObject(arg1);
6966 xmlXPathFreeObject(arg2);
6967 XP_ERROR0(XPATH_INVALID_OPERAND);
6968 }
6969 if (arg2->type != XPATH_NUMBER) {
6970 valuePush(ctxt, arg2);
6971 xmlXPathNumberFunction(ctxt, 1);
6972 arg2 = valuePop(ctxt);
6973 }
6974 if (arg2->type != XPATH_NUMBER) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00006975 xmlXPathReleaseObject(ctxt->context, arg1);
6976 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00006977 XP_ERROR0(XPATH_INVALID_OPERAND);
6978 }
6979 /*
6980 * Add tests for infinity and nan
6981 * => feedback on 3.4 for Inf and NaN
6982 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006983 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00006984 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006985 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00006986 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00006987 arg1i=xmlXPathIsInf(arg1->floatval);
6988 arg2i=xmlXPathIsInf(arg2->floatval);
6989 if (inf && strict) {
6990 if ((arg1i == -1 && arg2i != -1) ||
6991 (arg2i == 1 && arg1i != 1)) {
6992 ret = 1;
6993 } else if (arg1i == 0 && arg2i == 0) {
6994 ret = (arg1->floatval < arg2->floatval);
6995 } else {
6996 ret = 0;
6997 }
6998 }
6999 else if (inf && !strict) {
7000 if (arg1i == -1 || arg2i == 1) {
7001 ret = 1;
7002 } else if (arg1i == 0 && arg2i == 0) {
7003 ret = (arg1->floatval <= arg2->floatval);
7004 } else {
7005 ret = 0;
7006 }
7007 }
7008 else if (!inf && strict) {
7009 if ((arg1i == 1 && arg2i != 1) ||
7010 (arg2i == -1 && arg1i != -1)) {
7011 ret = 1;
7012 } else if (arg1i == 0 && arg2i == 0) {
7013 ret = (arg1->floatval > arg2->floatval);
7014 } else {
7015 ret = 0;
7016 }
7017 }
7018 else if (!inf && !strict) {
7019 if (arg1i == 1 || arg2i == -1) {
7020 ret = 1;
7021 } else if (arg1i == 0 && arg2i == 0) {
7022 ret = (arg1->floatval >= arg2->floatval);
7023 } else {
7024 ret = 0;
7025 }
7026 }
Daniel Veillard21458c82002-03-27 16:12:22 +00007027 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007028 xmlXPathReleaseObject(ctxt->context, arg1);
7029 xmlXPathReleaseObject(ctxt->context, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00007030 return(ret);
7031}
7032
7033/**
7034 * xmlXPathValueFlipSign:
7035 * @ctxt: the XPath Parser context
7036 *
7037 * Implement the unary - operation on an XPath object
7038 * The numeric operators convert their operands to numbers as if
7039 * by calling the number function.
7040 */
7041void
7042xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007043 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007044 CAST_TO_NUMBER;
7045 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007046 if (xmlXPathIsNaN(ctxt->value->floatval))
7047 ctxt->value->floatval=xmlXPathNAN;
7048 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7049 ctxt->value->floatval=xmlXPathNINF;
7050 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7051 ctxt->value->floatval=xmlXPathPINF;
7052 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007053 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7054 ctxt->value->floatval = xmlXPathNZERO;
7055 else
7056 ctxt->value->floatval = 0;
7057 }
7058 else
7059 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00007060}
7061
7062/**
7063 * xmlXPathAddValues:
7064 * @ctxt: the XPath Parser context
7065 *
7066 * Implement the add operation on XPath objects:
7067 * The numeric operators convert their operands to numbers as if
7068 * by calling the number function.
7069 */
7070void
7071xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7072 xmlXPathObjectPtr arg;
7073 double val;
7074
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007075 arg = valuePop(ctxt);
7076 if (arg == NULL)
7077 XP_ERROR(XPATH_INVALID_OPERAND);
7078 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007079 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007080 CAST_TO_NUMBER;
7081 CHECK_TYPE(XPATH_NUMBER);
7082 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00007083}
7084
7085/**
7086 * xmlXPathSubValues:
7087 * @ctxt: the XPath Parser context
7088 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007089 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00007090 * The numeric operators convert their operands to numbers as if
7091 * by calling the number function.
7092 */
7093void
7094xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7095 xmlXPathObjectPtr arg;
7096 double val;
7097
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007098 arg = valuePop(ctxt);
7099 if (arg == NULL)
7100 XP_ERROR(XPATH_INVALID_OPERAND);
7101 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007102 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007103 CAST_TO_NUMBER;
7104 CHECK_TYPE(XPATH_NUMBER);
7105 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007106}
7107
7108/**
7109 * xmlXPathMultValues:
7110 * @ctxt: the XPath Parser context
7111 *
7112 * Implement the multiply operation on XPath objects:
7113 * The numeric operators convert their operands to numbers as if
7114 * by calling the number function.
7115 */
7116void
7117xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7118 xmlXPathObjectPtr arg;
7119 double val;
7120
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007121 arg = valuePop(ctxt);
7122 if (arg == NULL)
7123 XP_ERROR(XPATH_INVALID_OPERAND);
7124 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007125 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007126 CAST_TO_NUMBER;
7127 CHECK_TYPE(XPATH_NUMBER);
7128 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007129}
7130
7131/**
7132 * xmlXPathDivValues:
7133 * @ctxt: the XPath Parser context
7134 *
7135 * Implement the div operation on XPath objects @arg1 / @arg2:
7136 * The numeric operators convert their operands to numbers as if
7137 * by calling the number function.
7138 */
7139void
7140xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7141 xmlXPathObjectPtr arg;
7142 double val;
7143
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007144 arg = valuePop(ctxt);
7145 if (arg == NULL)
7146 XP_ERROR(XPATH_INVALID_OPERAND);
7147 val = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007148 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007149 CAST_TO_NUMBER;
7150 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00007151 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7152 ctxt->value->floatval = xmlXPathNAN;
7153 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007154 if (ctxt->value->floatval == 0)
7155 ctxt->value->floatval = xmlXPathNAN;
7156 else if (ctxt->value->floatval > 0)
7157 ctxt->value->floatval = xmlXPathNINF;
7158 else if (ctxt->value->floatval < 0)
7159 ctxt->value->floatval = xmlXPathPINF;
7160 }
7161 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00007162 if (ctxt->value->floatval == 0)
7163 ctxt->value->floatval = xmlXPathNAN;
7164 else if (ctxt->value->floatval > 0)
7165 ctxt->value->floatval = xmlXPathPINF;
7166 else if (ctxt->value->floatval < 0)
7167 ctxt->value->floatval = xmlXPathNINF;
7168 } else
7169 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00007170}
7171
7172/**
7173 * xmlXPathModValues:
7174 * @ctxt: the XPath Parser context
7175 *
7176 * Implement the mod operation on XPath objects: @arg1 / @arg2
7177 * The numeric operators convert their operands to numbers as if
7178 * by calling the number function.
7179 */
7180void
7181xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7182 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007183 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00007184
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007185 arg = valuePop(ctxt);
7186 if (arg == NULL)
7187 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007188 arg2 = xmlXPathCastToNumber(arg);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00007189 xmlXPathReleaseObject(ctxt->context, arg);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007190 CAST_TO_NUMBER;
7191 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007192 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00007193 if (arg2 == 0)
7194 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007195 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00007196 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007197 }
Owen Taylor3473f882001-02-23 17:55:21 +00007198}
7199
7200/************************************************************************
7201 * *
7202 * The traversal functions *
7203 * *
7204 ************************************************************************/
7205
Owen Taylor3473f882001-02-23 17:55:21 +00007206/*
7207 * A traversal function enumerates nodes along an axis.
7208 * Initially it must be called with NULL, and it indicates
7209 * termination on the axis by returning NULL.
7210 */
7211typedef xmlNodePtr (*xmlXPathTraversalFunction)
7212 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7213
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007214/*
7215 * xmlXPathTraversalFunctionExt:
7216 * A traversal function enumerates nodes along an axis.
7217 * Initially it must be called with NULL, and it indicates
7218 * termination on the axis by returning NULL.
7219 * The context node of the traversal is specified via @contextNode.
7220 */
7221typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7222 (xmlNodePtr cur, xmlNodePtr contextNode);
7223
7224
Owen Taylor3473f882001-02-23 17:55:21 +00007225/**
7226 * xmlXPathNextSelf:
7227 * @ctxt: the XPath Parser context
7228 * @cur: the current node in the traversal
7229 *
7230 * Traversal function for the "self" direction
7231 * The self axis contains just the context node itself
7232 *
7233 * Returns the next element following that axis
7234 */
7235xmlNodePtr
7236xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007237 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007238 if (cur == NULL)
7239 return(ctxt->context->node);
7240 return(NULL);
7241}
7242
7243/**
7244 * xmlXPathNextChild:
7245 * @ctxt: the XPath Parser context
7246 * @cur: the current node in the traversal
7247 *
7248 * Traversal function for the "child" direction
7249 * The child axis contains the children of the context node in document order.
7250 *
7251 * Returns the next element following that axis
7252 */
7253xmlNodePtr
7254xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007255 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007256 if (cur == NULL) {
7257 if (ctxt->context->node == NULL) return(NULL);
7258 switch (ctxt->context->node->type) {
7259 case XML_ELEMENT_NODE:
7260 case XML_TEXT_NODE:
7261 case XML_CDATA_SECTION_NODE:
7262 case XML_ENTITY_REF_NODE:
7263 case XML_ENTITY_NODE:
7264 case XML_PI_NODE:
7265 case XML_COMMENT_NODE:
7266 case XML_NOTATION_NODE:
7267 case XML_DTD_NODE:
7268 return(ctxt->context->node->children);
7269 case XML_DOCUMENT_NODE:
7270 case XML_DOCUMENT_TYPE_NODE:
7271 case XML_DOCUMENT_FRAG_NODE:
7272 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007273#ifdef LIBXML_DOCB_ENABLED
7274 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007275#endif
7276 return(((xmlDocPtr) ctxt->context->node)->children);
7277 case XML_ELEMENT_DECL:
7278 case XML_ATTRIBUTE_DECL:
7279 case XML_ENTITY_DECL:
7280 case XML_ATTRIBUTE_NODE:
7281 case XML_NAMESPACE_DECL:
7282 case XML_XINCLUDE_START:
7283 case XML_XINCLUDE_END:
7284 return(NULL);
7285 }
7286 return(NULL);
7287 }
7288 if ((cur->type == XML_DOCUMENT_NODE) ||
7289 (cur->type == XML_HTML_DOCUMENT_NODE))
7290 return(NULL);
7291 return(cur->next);
7292}
7293
7294/**
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +00007295 * xmlXPathNextChildElement:
7296 * @ctxt: the XPath Parser context
7297 * @cur: the current node in the traversal
7298 *
7299 * Traversal function for the "child" direction and nodes of type element.
7300 * The child axis contains the children of the context node in document order.
7301 *
7302 * Returns the next element following that axis
7303 */
7304static xmlNodePtr
7305xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7306 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7307 if (cur == NULL) {
7308 cur = ctxt->context->node;
7309 if (cur == NULL) return(NULL);
7310 /*
7311 * Get the first element child.
7312 */
7313 switch (cur->type) {
7314 case XML_ELEMENT_NODE:
7315 case XML_DOCUMENT_FRAG_NODE:
7316 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7317 case XML_ENTITY_NODE:
7318 cur = cur->children;
7319 if (cur != NULL) {
7320 if (cur->type == XML_ELEMENT_NODE)
7321 return(cur);
7322 do {
7323 cur = cur->next;
7324 } while ((cur != NULL) &&
7325 (cur->type != XML_ELEMENT_NODE));
7326 return(cur);
7327 }
7328 return(NULL);
7329 case XML_DOCUMENT_NODE:
7330 case XML_HTML_DOCUMENT_NODE:
7331#ifdef LIBXML_DOCB_ENABLED
7332 case XML_DOCB_DOCUMENT_NODE:
7333#endif
7334 return(xmlDocGetRootElement((xmlDocPtr) cur));
7335 default:
7336 return(NULL);
7337 }
7338 return(NULL);
7339 }
7340 /*
7341 * Get the next sibling element node.
7342 */
7343 switch (cur->type) {
7344 case XML_ELEMENT_NODE:
7345 case XML_TEXT_NODE:
7346 case XML_ENTITY_REF_NODE:
7347 case XML_ENTITY_NODE:
7348 case XML_CDATA_SECTION_NODE:
7349 case XML_PI_NODE:
7350 case XML_COMMENT_NODE:
7351 case XML_XINCLUDE_END:
7352 break;
7353 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7354 default:
7355 return(NULL);
7356 }
7357 if (cur->next != NULL) {
7358 if (cur->next->type == XML_ELEMENT_NODE)
7359 return(cur->next);
7360 cur = cur->next;
7361 do {
7362 cur = cur->next;
7363 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7364 return(cur);
7365 }
7366 return(NULL);
7367}
7368
7369/**
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +00007370 * xmlXPathNextDescendantOrSelfElemParent:
7371 * @ctxt: the XPath Parser context
7372 * @cur: the current node in the traversal
7373 *
7374 * Traversal function for the "descendant-or-self" axis.
7375 * Additionally it returns only nodes which can be parents of
7376 * element nodes.
7377 *
7378 *
7379 * Returns the next element following that axis
7380 */
7381static xmlNodePtr
7382xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7383 xmlNodePtr contextNode)
7384{
7385 if (cur == NULL) {
7386 if (contextNode == NULL)
7387 return(NULL);
7388 switch (contextNode->type) {
7389 case XML_ELEMENT_NODE:
7390 case XML_XINCLUDE_START:
7391 case XML_DOCUMENT_FRAG_NODE:
7392 case XML_DOCUMENT_NODE:
7393#ifdef LIBXML_DOCB_ENABLED
7394 case XML_DOCB_DOCUMENT_NODE:
7395#endif
7396 case XML_HTML_DOCUMENT_NODE:
7397 return(contextNode);
7398 default:
7399 return(NULL);
7400 }
7401 return(NULL);
7402 } else {
7403 xmlNodePtr start = cur;
7404
7405 while (cur != NULL) {
7406 switch (cur->type) {
7407 case XML_ELEMENT_NODE:
7408 /* TODO: OK to have XInclude here? */
7409 case XML_XINCLUDE_START:
7410 case XML_DOCUMENT_FRAG_NODE:
7411 if (cur != start)
7412 return(cur);
7413 if (cur->children != NULL) {
7414 cur = cur->children;
7415 continue;
7416 }
7417 break;
7418#ifdef LIBXML_DOCB_ENABLED
7419 /* Not sure if we need those here. */
7420 case XML_DOCUMENT_NODE:
7421 case XML_DOCB_DOCUMENT_NODE:
7422#endif
7423 case XML_HTML_DOCUMENT_NODE:
7424 if (cur != start)
7425 return(cur);
7426 return(xmlDocGetRootElement((xmlDocPtr) cur));
7427 default:
7428 break;
7429 }
7430
7431next_sibling:
7432 if ((cur == NULL) || (cur == contextNode))
7433 return(NULL);
7434 if (cur->next != NULL) {
7435 cur = cur->next;
7436 } else {
7437 cur = cur->parent;
7438 goto next_sibling;
7439 }
7440 }
7441 }
7442 return(NULL);
7443}
7444
7445/**
Owen Taylor3473f882001-02-23 17:55:21 +00007446 * xmlXPathNextDescendant:
7447 * @ctxt: the XPath Parser context
7448 * @cur: the current node in the traversal
7449 *
7450 * Traversal function for the "descendant" direction
7451 * the descendant axis contains the descendants of the context node in document
7452 * order; a descendant is a child or a child of a child and so on.
7453 *
7454 * Returns the next element following that axis
7455 */
7456xmlNodePtr
7457xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007458 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007459 if (cur == NULL) {
7460 if (ctxt->context->node == NULL)
7461 return(NULL);
7462 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7463 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7464 return(NULL);
7465
7466 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7467 return(ctxt->context->doc->children);
7468 return(ctxt->context->node->children);
7469 }
7470
Daniel Veillard567e1b42001-08-01 15:53:47 +00007471 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00007472 /*
7473 * Do not descend on entities declarations
7474 */
7475 if (cur->children->type != XML_ENTITY_DECL) {
7476 cur = cur->children;
7477 /*
7478 * Skip DTDs
7479 */
7480 if (cur->type != XML_DTD_NODE)
7481 return(cur);
7482 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00007483 }
7484
7485 if (cur == ctxt->context->node) return(NULL);
7486
Daniel Veillard68e9e742002-11-16 15:35:11 +00007487 while (cur->next != NULL) {
7488 cur = cur->next;
7489 if ((cur->type != XML_ENTITY_DECL) &&
7490 (cur->type != XML_DTD_NODE))
7491 return(cur);
7492 }
Owen Taylor3473f882001-02-23 17:55:21 +00007493
7494 do {
7495 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007496 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007497 if (cur == ctxt->context->node) return(NULL);
7498 if (cur->next != NULL) {
7499 cur = cur->next;
7500 return(cur);
7501 }
7502 } while (cur != NULL);
7503 return(cur);
7504}
7505
7506/**
7507 * xmlXPathNextDescendantOrSelf:
7508 * @ctxt: the XPath Parser context
7509 * @cur: the current node in the traversal
7510 *
7511 * Traversal function for the "descendant-or-self" direction
7512 * the descendant-or-self axis contains the context node and the descendants
7513 * of the context node in document order; thus the context node is the first
7514 * node on the axis, and the first child of the context node is the second node
7515 * on the axis
7516 *
7517 * Returns the next element following that axis
7518 */
7519xmlNodePtr
7520xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007521 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007522 if (cur == NULL) {
7523 if (ctxt->context->node == NULL)
7524 return(NULL);
7525 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7526 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7527 return(NULL);
7528 return(ctxt->context->node);
7529 }
7530
7531 return(xmlXPathNextDescendant(ctxt, cur));
7532}
7533
7534/**
7535 * xmlXPathNextParent:
7536 * @ctxt: the XPath Parser context
7537 * @cur: the current node in the traversal
7538 *
7539 * Traversal function for the "parent" direction
7540 * The parent axis contains the parent of the context node, if there is one.
7541 *
7542 * Returns the next element following that axis
7543 */
7544xmlNodePtr
7545xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007546 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007547 /*
7548 * the parent of an attribute or namespace node is the element
7549 * to which the attribute or namespace node is attached
7550 * Namespace handling !!!
7551 */
7552 if (cur == NULL) {
7553 if (ctxt->context->node == NULL) return(NULL);
7554 switch (ctxt->context->node->type) {
7555 case XML_ELEMENT_NODE:
7556 case XML_TEXT_NODE:
7557 case XML_CDATA_SECTION_NODE:
7558 case XML_ENTITY_REF_NODE:
7559 case XML_ENTITY_NODE:
7560 case XML_PI_NODE:
7561 case XML_COMMENT_NODE:
7562 case XML_NOTATION_NODE:
7563 case XML_DTD_NODE:
7564 case XML_ELEMENT_DECL:
7565 case XML_ATTRIBUTE_DECL:
7566 case XML_XINCLUDE_START:
7567 case XML_XINCLUDE_END:
7568 case XML_ENTITY_DECL:
7569 if (ctxt->context->node->parent == NULL)
7570 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007571 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007572 ((ctxt->context->node->parent->name[0] == ' ') ||
7573 (xmlStrEqual(ctxt->context->node->parent->name,
7574 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007575 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007576 return(ctxt->context->node->parent);
7577 case XML_ATTRIBUTE_NODE: {
7578 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7579
7580 return(att->parent);
7581 }
7582 case XML_DOCUMENT_NODE:
7583 case XML_DOCUMENT_TYPE_NODE:
7584 case XML_DOCUMENT_FRAG_NODE:
7585 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007586#ifdef LIBXML_DOCB_ENABLED
7587 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007588#endif
7589 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007590 case XML_NAMESPACE_DECL: {
7591 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7592
7593 if ((ns->next != NULL) &&
7594 (ns->next->type != XML_NAMESPACE_DECL))
7595 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00007596 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007597 }
Owen Taylor3473f882001-02-23 17:55:21 +00007598 }
7599 }
7600 return(NULL);
7601}
7602
7603/**
7604 * xmlXPathNextAncestor:
7605 * @ctxt: the XPath Parser context
7606 * @cur: the current node in the traversal
7607 *
7608 * Traversal function for the "ancestor" direction
7609 * the ancestor axis contains the ancestors of the context node; the ancestors
7610 * of the context node consist of the parent of context node and the parent's
7611 * parent and so on; the nodes are ordered in reverse document order; thus the
7612 * parent is the first node on the axis, and the parent's parent is the second
7613 * node on the axis
7614 *
7615 * Returns the next element following that axis
7616 */
7617xmlNodePtr
7618xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007619 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007620 /*
7621 * the parent of an attribute or namespace node is the element
7622 * to which the attribute or namespace node is attached
7623 * !!!!!!!!!!!!!
7624 */
7625 if (cur == NULL) {
7626 if (ctxt->context->node == NULL) return(NULL);
7627 switch (ctxt->context->node->type) {
7628 case XML_ELEMENT_NODE:
7629 case XML_TEXT_NODE:
7630 case XML_CDATA_SECTION_NODE:
7631 case XML_ENTITY_REF_NODE:
7632 case XML_ENTITY_NODE:
7633 case XML_PI_NODE:
7634 case XML_COMMENT_NODE:
7635 case XML_DTD_NODE:
7636 case XML_ELEMENT_DECL:
7637 case XML_ATTRIBUTE_DECL:
7638 case XML_ENTITY_DECL:
7639 case XML_NOTATION_NODE:
7640 case XML_XINCLUDE_START:
7641 case XML_XINCLUDE_END:
7642 if (ctxt->context->node->parent == NULL)
7643 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007644 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007645 ((ctxt->context->node->parent->name[0] == ' ') ||
7646 (xmlStrEqual(ctxt->context->node->parent->name,
7647 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007648 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007649 return(ctxt->context->node->parent);
7650 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007651 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00007652
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007653 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00007654 }
7655 case XML_DOCUMENT_NODE:
7656 case XML_DOCUMENT_TYPE_NODE:
7657 case XML_DOCUMENT_FRAG_NODE:
7658 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007659#ifdef LIBXML_DOCB_ENABLED
7660 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007661#endif
7662 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007663 case XML_NAMESPACE_DECL: {
7664 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7665
7666 if ((ns->next != NULL) &&
7667 (ns->next->type != XML_NAMESPACE_DECL))
7668 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007669 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00007670 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00007671 }
Owen Taylor3473f882001-02-23 17:55:21 +00007672 }
7673 return(NULL);
7674 }
7675 if (cur == ctxt->context->doc->children)
7676 return((xmlNodePtr) ctxt->context->doc);
7677 if (cur == (xmlNodePtr) ctxt->context->doc)
7678 return(NULL);
7679 switch (cur->type) {
7680 case XML_ELEMENT_NODE:
7681 case XML_TEXT_NODE:
7682 case XML_CDATA_SECTION_NODE:
7683 case XML_ENTITY_REF_NODE:
7684 case XML_ENTITY_NODE:
7685 case XML_PI_NODE:
7686 case XML_COMMENT_NODE:
7687 case XML_NOTATION_NODE:
7688 case XML_DTD_NODE:
7689 case XML_ELEMENT_DECL:
7690 case XML_ATTRIBUTE_DECL:
7691 case XML_ENTITY_DECL:
7692 case XML_XINCLUDE_START:
7693 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007694 if (cur->parent == NULL)
7695 return(NULL);
7696 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00007697 ((cur->parent->name[0] == ' ') ||
7698 (xmlStrEqual(cur->parent->name,
7699 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00007700 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007701 return(cur->parent);
7702 case XML_ATTRIBUTE_NODE: {
7703 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7704
7705 return(att->parent);
7706 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007707 case XML_NAMESPACE_DECL: {
7708 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7709
7710 if ((ns->next != NULL) &&
7711 (ns->next->type != XML_NAMESPACE_DECL))
7712 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00007713 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00007714 return(NULL);
7715 }
Owen Taylor3473f882001-02-23 17:55:21 +00007716 case XML_DOCUMENT_NODE:
7717 case XML_DOCUMENT_TYPE_NODE:
7718 case XML_DOCUMENT_FRAG_NODE:
7719 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00007720#ifdef LIBXML_DOCB_ENABLED
7721 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00007722#endif
7723 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007724 }
7725 return(NULL);
7726}
7727
7728/**
7729 * xmlXPathNextAncestorOrSelf:
7730 * @ctxt: the XPath Parser context
7731 * @cur: the current node in the traversal
7732 *
7733 * Traversal function for the "ancestor-or-self" direction
7734 * he ancestor-or-self axis contains the context node and ancestors of
7735 * the context node in reverse document order; thus the context node is
7736 * the first node on the axis, and the context node's parent the second;
7737 * parent here is defined the same as with the parent axis.
7738 *
7739 * Returns the next element following that axis
7740 */
7741xmlNodePtr
7742xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007743 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007744 if (cur == NULL)
7745 return(ctxt->context->node);
7746 return(xmlXPathNextAncestor(ctxt, cur));
7747}
7748
7749/**
7750 * xmlXPathNextFollowingSibling:
7751 * @ctxt: the XPath Parser context
7752 * @cur: the current node in the traversal
7753 *
7754 * Traversal function for the "following-sibling" direction
7755 * The following-sibling axis contains the following siblings of the context
7756 * node in document order.
7757 *
7758 * Returns the next element following that axis
7759 */
7760xmlNodePtr
7761xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007762 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007763 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7764 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7765 return(NULL);
7766 if (cur == (xmlNodePtr) ctxt->context->doc)
7767 return(NULL);
7768 if (cur == NULL)
7769 return(ctxt->context->node->next);
7770 return(cur->next);
7771}
7772
7773/**
7774 * xmlXPathNextPrecedingSibling:
7775 * @ctxt: the XPath Parser context
7776 * @cur: the current node in the traversal
7777 *
7778 * Traversal function for the "preceding-sibling" direction
7779 * The preceding-sibling axis contains the preceding siblings of the context
7780 * node in reverse document order; the first preceding sibling is first on the
7781 * axis; the sibling preceding that node is the second on the axis and so on.
7782 *
7783 * Returns the next element following that axis
7784 */
7785xmlNodePtr
7786xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007787 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007788 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7789 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7790 return(NULL);
7791 if (cur == (xmlNodePtr) ctxt->context->doc)
7792 return(NULL);
7793 if (cur == NULL)
7794 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007795 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7796 cur = cur->prev;
7797 if (cur == NULL)
7798 return(ctxt->context->node->prev);
7799 }
Owen Taylor3473f882001-02-23 17:55:21 +00007800 return(cur->prev);
7801}
7802
7803/**
7804 * xmlXPathNextFollowing:
7805 * @ctxt: the XPath Parser context
7806 * @cur: the current node in the traversal
7807 *
7808 * Traversal function for the "following" direction
7809 * The following axis contains all nodes in the same document as the context
7810 * node that are after the context node in document order, excluding any
7811 * descendants and excluding attribute nodes and namespace nodes; the nodes
7812 * are ordered in document order
7813 *
7814 * Returns the next element following that axis
7815 */
7816xmlNodePtr
7817xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007818 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007819 if (cur != NULL && cur->children != NULL)
7820 return cur->children ;
7821 if (cur == NULL) cur = ctxt->context->node;
7822 if (cur == NULL) return(NULL) ; /* ERROR */
7823 if (cur->next != NULL) return(cur->next) ;
7824 do {
7825 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00007826 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00007827 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7828 if (cur->next != NULL) return(cur->next);
7829 } while (cur != NULL);
7830 return(cur);
7831}
7832
7833/*
7834 * xmlXPathIsAncestor:
7835 * @ancestor: the ancestor node
7836 * @node: the current node
7837 *
7838 * Check that @ancestor is a @node's ancestor
7839 *
7840 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7841 */
7842static int
7843xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7844 if ((ancestor == NULL) || (node == NULL)) return(0);
7845 /* nodes need to be in the same document */
7846 if (ancestor->doc != node->doc) return(0);
7847 /* avoid searching if ancestor or node is the root node */
7848 if (ancestor == (xmlNodePtr) node->doc) return(1);
7849 if (node == (xmlNodePtr) ancestor->doc) return(0);
7850 while (node->parent != NULL) {
7851 if (node->parent == ancestor)
7852 return(1);
7853 node = node->parent;
7854 }
7855 return(0);
7856}
7857
7858/**
7859 * xmlXPathNextPreceding:
7860 * @ctxt: the XPath Parser context
7861 * @cur: the current node in the traversal
7862 *
7863 * Traversal function for the "preceding" direction
7864 * the preceding axis contains all nodes in the same document as the context
7865 * node that are before the context node in document order, excluding any
7866 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7867 * ordered in reverse document order
7868 *
7869 * Returns the next element following that axis
7870 */
7871xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00007872xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7873{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007874 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007875 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00007876 cur = ctxt->context->node;
7877 if (cur == NULL)
7878 return (NULL);
7879 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7880 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00007881 do {
7882 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00007883 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7884 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007885 }
7886
7887 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007888 if (cur == NULL)
7889 return (NULL);
7890 if (cur == ctxt->context->doc->children)
7891 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007892 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00007893 return (cur);
7894}
7895
7896/**
7897 * xmlXPathNextPrecedingInternal:
7898 * @ctxt: the XPath Parser context
7899 * @cur: the current node in the traversal
7900 *
7901 * Traversal function for the "preceding" direction
7902 * the preceding axis contains all nodes in the same document as the context
7903 * node that are before the context node in document order, excluding any
7904 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7905 * ordered in reverse document order
7906 * This is a faster implementation but internal only since it requires a
7907 * state kept in the parser context: ctxt->ancestor.
7908 *
7909 * Returns the next element following that axis
7910 */
7911static xmlNodePtr
7912xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7913 xmlNodePtr cur)
7914{
Daniel Veillarda82b1822004-11-08 16:24:57 +00007915 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00007916 if (cur == NULL) {
7917 cur = ctxt->context->node;
7918 if (cur == NULL)
7919 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00007920 if (cur->type == XML_NAMESPACE_DECL)
7921 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00007922 ctxt->ancestor = cur->parent;
7923 }
7924 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7925 cur = cur->prev;
7926 while (cur->prev == NULL) {
7927 cur = cur->parent;
7928 if (cur == NULL)
7929 return (NULL);
7930 if (cur == ctxt->context->doc->children)
7931 return (NULL);
7932 if (cur != ctxt->ancestor)
7933 return (cur);
7934 ctxt->ancestor = cur->parent;
7935 }
7936 cur = cur->prev;
7937 while (cur->last != NULL)
7938 cur = cur->last;
7939 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007940}
7941
7942/**
7943 * xmlXPathNextNamespace:
7944 * @ctxt: the XPath Parser context
7945 * @cur: the current attribute in the traversal
7946 *
7947 * Traversal function for the "namespace" direction
7948 * the namespace axis contains the namespace nodes of the context node;
7949 * the order of nodes on this axis is implementation-defined; the axis will
7950 * be empty unless the context node is an element
7951 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007952 * We keep the XML namespace node at the end of the list.
7953 *
Owen Taylor3473f882001-02-23 17:55:21 +00007954 * Returns the next element following that axis
7955 */
7956xmlNodePtr
7957xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007958 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007959 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00007960 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007961 if (ctxt->context->tmpNsList != NULL)
7962 xmlFree(ctxt->context->tmpNsList);
7963 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00007964 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007965 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00007966 if (ctxt->context->tmpNsList != NULL) {
7967 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7968 ctxt->context->tmpNsNr++;
7969 }
7970 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00007971 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00007972 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00007973 if (ctxt->context->tmpNsNr > 0) {
7974 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7975 } else {
7976 if (ctxt->context->tmpNsList != NULL)
7977 xmlFree(ctxt->context->tmpNsList);
7978 ctxt->context->tmpNsList = NULL;
7979 return(NULL);
7980 }
Owen Taylor3473f882001-02-23 17:55:21 +00007981}
7982
7983/**
7984 * xmlXPathNextAttribute:
7985 * @ctxt: the XPath Parser context
7986 * @cur: the current attribute in the traversal
7987 *
7988 * Traversal function for the "attribute" direction
7989 * TODO: support DTD inherited default attributes
7990 *
7991 * Returns the next element following that axis
7992 */
7993xmlNodePtr
7994xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00007995 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00007996 if (ctxt->context->node == NULL)
7997 return(NULL);
7998 if (ctxt->context->node->type != XML_ELEMENT_NODE)
7999 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008000 if (cur == NULL) {
8001 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8002 return(NULL);
8003 return((xmlNodePtr)ctxt->context->node->properties);
8004 }
8005 return((xmlNodePtr)cur->next);
8006}
8007
8008/************************************************************************
8009 * *
8010 * NodeTest Functions *
8011 * *
8012 ************************************************************************/
8013
Owen Taylor3473f882001-02-23 17:55:21 +00008014#define IS_FUNCTION 200
8015
Owen Taylor3473f882001-02-23 17:55:21 +00008016
8017/************************************************************************
8018 * *
8019 * Implicit tree core function library *
8020 * *
8021 ************************************************************************/
8022
8023/**
8024 * xmlXPathRoot:
8025 * @ctxt: the XPath Parser context
8026 *
8027 * Initialize the context to the root of the document
8028 */
8029void
8030xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008031 if ((ctxt == NULL) || (ctxt->context == NULL))
8032 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008033 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008034 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8035 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008036}
8037
8038/************************************************************************
8039 * *
8040 * The explicit core function library *
8041 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8042 * *
8043 ************************************************************************/
8044
8045
8046/**
8047 * xmlXPathLastFunction:
8048 * @ctxt: the XPath Parser context
8049 * @nargs: the number of arguments
8050 *
8051 * Implement the last() XPath function
8052 * number last()
8053 * The last function returns the number of nodes in the context node list.
8054 */
8055void
8056xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8057 CHECK_ARITY(0);
8058 if (ctxt->context->contextSize >= 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008059 valuePush(ctxt,
8060 xmlXPathCacheNewFloat(ctxt->context,
8061 (double) ctxt->context->contextSize));
Owen Taylor3473f882001-02-23 17:55:21 +00008062#ifdef DEBUG_EXPR
8063 xmlGenericError(xmlGenericErrorContext,
8064 "last() : %d\n", ctxt->context->contextSize);
8065#endif
8066 } else {
8067 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8068 }
8069}
8070
8071/**
8072 * xmlXPathPositionFunction:
8073 * @ctxt: the XPath Parser context
8074 * @nargs: the number of arguments
8075 *
8076 * Implement the position() XPath function
8077 * number position()
8078 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008079 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00008080 * will be equal to last().
8081 */
8082void
8083xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8084 CHECK_ARITY(0);
8085 if (ctxt->context->proximityPosition >= 0) {
8086 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008087 xmlXPathCacheNewFloat(ctxt->context,
8088 (double) ctxt->context->proximityPosition));
Owen Taylor3473f882001-02-23 17:55:21 +00008089#ifdef DEBUG_EXPR
8090 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8091 ctxt->context->proximityPosition);
8092#endif
8093 } else {
8094 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8095 }
8096}
8097
8098/**
8099 * xmlXPathCountFunction:
8100 * @ctxt: the XPath Parser context
8101 * @nargs: the number of arguments
8102 *
8103 * Implement the count() XPath function
8104 * number count(node-set)
8105 */
8106void
8107xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8108 xmlXPathObjectPtr cur;
8109
8110 CHECK_ARITY(1);
8111 if ((ctxt->value == NULL) ||
8112 ((ctxt->value->type != XPATH_NODESET) &&
8113 (ctxt->value->type != XPATH_XSLT_TREE)))
8114 XP_ERROR(XPATH_INVALID_TYPE);
8115 cur = valuePop(ctxt);
8116
Daniel Veillard911f49a2001-04-07 15:39:35 +00008117 if ((cur == NULL) || (cur->nodesetval == NULL))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008118 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00008119 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008120 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8121 (double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00008122 } else {
8123 if ((cur->nodesetval->nodeNr != 1) ||
8124 (cur->nodesetval->nodeTab == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008125 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
Daniel Veillardfe703322001-08-14 12:18:09 +00008126 } else {
8127 xmlNodePtr tmp;
8128 int i = 0;
8129
8130 tmp = cur->nodesetval->nodeTab[0];
8131 if (tmp != NULL) {
8132 tmp = tmp->children;
8133 while (tmp != NULL) {
8134 tmp = tmp->next;
8135 i++;
8136 }
8137 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008138 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
Daniel Veillardfe703322001-08-14 12:18:09 +00008139 }
8140 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008141 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008142}
8143
8144/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008145 * xmlXPathGetElementsByIds:
8146 * @doc: the document
8147 * @ids: a whitespace separated list of IDs
8148 *
8149 * Selects elements by their unique ID.
8150 *
8151 * Returns a node-set of selected elements.
8152 */
8153static xmlNodeSetPtr
8154xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8155 xmlNodeSetPtr ret;
8156 const xmlChar *cur = ids;
8157 xmlChar *ID;
8158 xmlAttrPtr attr;
8159 xmlNodePtr elem = NULL;
8160
Daniel Veillard7a985a12003-07-06 17:57:42 +00008161 if (ids == NULL) return(NULL);
8162
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008163 ret = xmlXPathNodeSetCreate(NULL);
8164
William M. Brack76e95df2003-10-18 16:20:14 +00008165 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008166 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00008167 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00008168 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008169
8170 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00008171 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00008172 /*
8173 * We used to check the fact that the value passed
8174 * was an NCName, but this generated much troubles for
8175 * me and Aleksey Sanin, people blatantly violated that
8176 * constaint, like Visa3D spec.
8177 * if (xmlValidateNCName(ID, 1) == 0)
8178 */
8179 attr = xmlGetID(doc, ID);
8180 if (attr != NULL) {
8181 if (attr->type == XML_ATTRIBUTE_NODE)
8182 elem = attr->parent;
8183 else if (attr->type == XML_ELEMENT_NODE)
8184 elem = (xmlNodePtr) attr;
8185 else
8186 elem = NULL;
8187 if (elem != NULL)
8188 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00008189 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008190 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00008191 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008192
William M. Brack76e95df2003-10-18 16:20:14 +00008193 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008194 ids = cur;
8195 }
8196 return(ret);
8197}
8198
8199/**
Owen Taylor3473f882001-02-23 17:55:21 +00008200 * xmlXPathIdFunction:
8201 * @ctxt: the XPath Parser context
8202 * @nargs: the number of arguments
8203 *
8204 * Implement the id() XPath function
8205 * node-set id(object)
8206 * The id function selects elements by their unique ID
8207 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8208 * then the result is the union of the result of applying id to the
8209 * string value of each of the nodes in the argument node-set. When the
8210 * argument to id is of any other type, the argument is converted to a
8211 * string as if by a call to the string function; the string is split
8212 * into a whitespace-separated list of tokens (whitespace is any sequence
8213 * of characters matching the production S); the result is a node-set
8214 * containing the elements in the same document as the context node that
8215 * have a unique ID equal to any of the tokens in the list.
8216 */
8217void
8218xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008219 xmlChar *tokens;
8220 xmlNodeSetPtr ret;
8221 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00008222
8223 CHECK_ARITY(1);
8224 obj = valuePop(ctxt);
8225 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00008226 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008227 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00008228 int i;
8229
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008230 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008231
Daniel Veillard911f49a2001-04-07 15:39:35 +00008232 if (obj->nodesetval != NULL) {
8233 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008234 tokens =
8235 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8236 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8237 ret = xmlXPathNodeSetMerge(ret, ns);
8238 xmlXPathFreeNodeSet(ns);
8239 if (tokens != NULL)
8240 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00008241 }
Owen Taylor3473f882001-02-23 17:55:21 +00008242 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008243 xmlXPathReleaseObject(ctxt->context, obj);
8244 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008245 return;
8246 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008247 obj = xmlXPathCacheConvertString(ctxt->context, obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008248 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008249 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8250 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008251 return;
8252}
8253
8254/**
8255 * xmlXPathLocalNameFunction:
8256 * @ctxt: the XPath Parser context
8257 * @nargs: the number of arguments
8258 *
8259 * Implement the local-name() XPath function
8260 * string local-name(node-set?)
8261 * The local-name function returns a string containing the local part
8262 * of the name of the node in the argument node-set that is first in
8263 * document order. If the node-set is empty or the first node has no
8264 * name, an empty string is returned. If the argument is omitted it
8265 * defaults to the context node.
8266 */
8267void
8268xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8269 xmlXPathObjectPtr cur;
8270
Daniel Veillarda82b1822004-11-08 16:24:57 +00008271 if (ctxt == NULL) return;
8272
Owen Taylor3473f882001-02-23 17:55:21 +00008273 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008274 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8275 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008276 nargs = 1;
8277 }
8278
8279 CHECK_ARITY(1);
8280 if ((ctxt->value == NULL) ||
8281 ((ctxt->value->type != XPATH_NODESET) &&
8282 (ctxt->value->type != XPATH_XSLT_TREE)))
8283 XP_ERROR(XPATH_INVALID_TYPE);
8284 cur = valuePop(ctxt);
8285
Daniel Veillard911f49a2001-04-07 15:39:35 +00008286 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008287 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008288 } else {
8289 int i = 0; /* Should be first in document order !!!!! */
8290 switch (cur->nodesetval->nodeTab[i]->type) {
8291 case XML_ELEMENT_NODE:
8292 case XML_ATTRIBUTE_NODE:
8293 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008294 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008295 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008296 else
8297 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008298 xmlXPathCacheNewString(ctxt->context,
8299 cur->nodesetval->nodeTab[i]->name));
Owen Taylor3473f882001-02-23 17:55:21 +00008300 break;
8301 case XML_NAMESPACE_DECL:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008302 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008303 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8304 break;
8305 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008306 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008307 }
8308 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008309 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008310}
8311
8312/**
8313 * xmlXPathNamespaceURIFunction:
8314 * @ctxt: the XPath Parser context
8315 * @nargs: the number of arguments
8316 *
8317 * Implement the namespace-uri() XPath function
8318 * string namespace-uri(node-set?)
8319 * The namespace-uri function returns a string containing the
8320 * namespace URI of the expanded name of the node in the argument
8321 * node-set that is first in document order. If the node-set is empty,
8322 * the first node has no name, or the expanded name has no namespace
8323 * URI, an empty string is returned. If the argument is omitted it
8324 * defaults to the context node.
8325 */
8326void
8327xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8328 xmlXPathObjectPtr cur;
8329
Daniel Veillarda82b1822004-11-08 16:24:57 +00008330 if (ctxt == NULL) return;
8331
Owen Taylor3473f882001-02-23 17:55:21 +00008332 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008333 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8334 ctxt->context->node));
Owen Taylor3473f882001-02-23 17:55:21 +00008335 nargs = 1;
8336 }
8337 CHECK_ARITY(1);
8338 if ((ctxt->value == NULL) ||
8339 ((ctxt->value->type != XPATH_NODESET) &&
8340 (ctxt->value->type != XPATH_XSLT_TREE)))
8341 XP_ERROR(XPATH_INVALID_TYPE);
8342 cur = valuePop(ctxt);
8343
Daniel Veillard911f49a2001-04-07 15:39:35 +00008344 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008345 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008346 } else {
8347 int i = 0; /* Should be first in document order !!!!! */
8348 switch (cur->nodesetval->nodeTab[i]->type) {
8349 case XML_ELEMENT_NODE:
8350 case XML_ATTRIBUTE_NODE:
8351 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008352 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008353 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008354 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
Owen Taylor3473f882001-02-23 17:55:21 +00008355 cur->nodesetval->nodeTab[i]->ns->href));
8356 break;
8357 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008358 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008359 }
8360 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008361 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008362}
8363
8364/**
8365 * xmlXPathNameFunction:
8366 * @ctxt: the XPath Parser context
8367 * @nargs: the number of arguments
8368 *
8369 * Implement the name() XPath function
8370 * string name(node-set?)
8371 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008372 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00008373 * order. The QName must represent the name with respect to the namespace
8374 * declarations in effect on the node whose name is being represented.
8375 * Typically, this will be the form in which the name occurred in the XML
8376 * source. This need not be the case if there are namespace declarations
8377 * in effect on the node that associate multiple prefixes with the same
8378 * namespace. However, an implementation may include information about
8379 * the original prefix in its representation of nodes; in this case, an
8380 * implementation can ensure that the returned string is always the same
8381 * as the QName used in the XML source. If the argument it omitted it
8382 * defaults to the context node.
8383 * Libxml keep the original prefix so the "real qualified name" used is
8384 * returned.
8385 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008386static void
Daniel Veillard04383752001-07-08 14:27:15 +00008387xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8388{
Owen Taylor3473f882001-02-23 17:55:21 +00008389 xmlXPathObjectPtr cur;
8390
8391 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008392 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8393 ctxt->context->node));
Daniel Veillard04383752001-07-08 14:27:15 +00008394 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008395 }
8396
8397 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00008398 if ((ctxt->value == NULL) ||
8399 ((ctxt->value->type != XPATH_NODESET) &&
8400 (ctxt->value->type != XPATH_XSLT_TREE)))
8401 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00008402 cur = valuePop(ctxt);
8403
Daniel Veillard911f49a2001-04-07 15:39:35 +00008404 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008405 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008406 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00008407 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00008408
Daniel Veillard04383752001-07-08 14:27:15 +00008409 switch (cur->nodesetval->nodeTab[i]->type) {
8410 case XML_ELEMENT_NODE:
8411 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00008412 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008413 valuePush(ctxt,
8414 xmlXPathCacheNewCString(ctxt->context, ""));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008415 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8416 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008417 valuePush(ctxt,
8418 xmlXPathCacheNewString(ctxt->context,
8419 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard652d8a92003-02-04 19:28:49 +00008420 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00008421 xmlChar *fullname;
8422
8423 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8424 cur->nodesetval->nodeTab[i]->ns->prefix,
8425 NULL, 0);
8426 if (fullname == cur->nodesetval->nodeTab[i]->name)
8427 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8428 if (fullname == NULL) {
8429 XP_ERROR(XPATH_MEMORY_ERROR);
8430 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008431 valuePush(ctxt, xmlXPathCacheWrapString(
8432 ctxt->context, fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00008433 }
8434 break;
8435 default:
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008436 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8437 cur->nodesetval->nodeTab[i]));
Daniel Veillard04383752001-07-08 14:27:15 +00008438 xmlXPathLocalNameFunction(ctxt, 1);
8439 }
Owen Taylor3473f882001-02-23 17:55:21 +00008440 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008441 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008442}
8443
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008444
8445/**
Owen Taylor3473f882001-02-23 17:55:21 +00008446 * xmlXPathStringFunction:
8447 * @ctxt: the XPath Parser context
8448 * @nargs: the number of arguments
8449 *
8450 * Implement the string() XPath function
8451 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00008452 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00008453 * - A node-set is converted to a string by returning the value of
8454 * the node in the node-set that is first in document order.
8455 * If the node-set is empty, an empty string is returned.
8456 * - A number is converted to a string as follows
8457 * + NaN is converted to the string NaN
8458 * + positive zero is converted to the string 0
8459 * + negative zero is converted to the string 0
8460 * + positive infinity is converted to the string Infinity
8461 * + negative infinity is converted to the string -Infinity
8462 * + if the number is an integer, the number is represented in
8463 * decimal form as a Number with no decimal point and no leading
8464 * zeros, preceded by a minus sign (-) if the number is negative
8465 * + otherwise, the number is represented in decimal form as a
8466 * Number including a decimal point with at least one digit
8467 * before the decimal point and at least one digit after the
8468 * decimal point, preceded by a minus sign (-) if the number
8469 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00008470 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00008471 * before the decimal point; beyond the one required digit
8472 * after the decimal point there must be as many, but only as
8473 * many, more digits as are needed to uniquely distinguish the
8474 * number from all other IEEE 754 numeric values.
8475 * - The boolean false value is converted to the string false.
8476 * The boolean true value is converted to the string true.
8477 *
8478 * If the argument is omitted, it defaults to a node-set with the
8479 * context node as its only member.
8480 */
8481void
8482xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8483 xmlXPathObjectPtr cur;
8484
Daniel Veillarda82b1822004-11-08 16:24:57 +00008485 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008486 if (nargs == 0) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008487 valuePush(ctxt,
8488 xmlXPathCacheWrapString(ctxt->context,
8489 xmlXPathCastNodeToString(ctxt->context->node)));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008490 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008491 }
8492
8493 CHECK_ARITY(1);
8494 cur = valuePop(ctxt);
8495 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008496 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00008497}
8498
8499/**
8500 * xmlXPathStringLengthFunction:
8501 * @ctxt: the XPath Parser context
8502 * @nargs: the number of arguments
8503 *
8504 * Implement the string-length() XPath function
8505 * number string-length(string?)
8506 * The string-length returns the number of characters in the string
8507 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8508 * the context node converted to a string, in other words the value
8509 * of the context node.
8510 */
8511void
8512xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8513 xmlXPathObjectPtr cur;
8514
8515 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00008516 if ((ctxt == NULL) || (ctxt->context == NULL))
8517 return;
Owen Taylor3473f882001-02-23 17:55:21 +00008518 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008519 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008520 } else {
8521 xmlChar *content;
8522
Daniel Veillardba0b8c92001-05-15 09:43:47 +00008523 content = xmlXPathCastNodeToString(ctxt->context->node);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008524 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8525 xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00008526 xmlFree(content);
8527 }
8528 return;
8529 }
8530 CHECK_ARITY(1);
8531 CAST_TO_STRING;
8532 CHECK_TYPE(XPATH_STRING);
8533 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008534 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8535 xmlUTF8Strlen(cur->stringval)));
8536 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008537}
8538
8539/**
8540 * xmlXPathConcatFunction:
8541 * @ctxt: the XPath Parser context
8542 * @nargs: the number of arguments
8543 *
8544 * Implement the concat() XPath function
8545 * string concat(string, string, string*)
8546 * The concat function returns the concatenation of its arguments.
8547 */
8548void
8549xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8550 xmlXPathObjectPtr cur, newobj;
8551 xmlChar *tmp;
8552
Daniel Veillarda82b1822004-11-08 16:24:57 +00008553 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008554 if (nargs < 2) {
8555 CHECK_ARITY(2);
8556 }
8557
8558 CAST_TO_STRING;
8559 cur = valuePop(ctxt);
8560 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008561 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008562 return;
8563 }
8564 nargs--;
8565
8566 while (nargs > 0) {
8567 CAST_TO_STRING;
8568 newobj = valuePop(ctxt);
8569 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008570 xmlXPathReleaseObject(ctxt->context, newobj);
8571 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00008572 XP_ERROR(XPATH_INVALID_TYPE);
8573 }
8574 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8575 newobj->stringval = cur->stringval;
8576 cur->stringval = tmp;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008577 xmlXPathReleaseObject(ctxt->context, newobj);
Owen Taylor3473f882001-02-23 17:55:21 +00008578 nargs--;
8579 }
8580 valuePush(ctxt, cur);
8581}
8582
8583/**
8584 * xmlXPathContainsFunction:
8585 * @ctxt: the XPath Parser context
8586 * @nargs: the number of arguments
8587 *
8588 * Implement the contains() XPath function
8589 * boolean contains(string, string)
8590 * The contains function returns true if the first argument string
8591 * contains the second argument string, and otherwise returns false.
8592 */
8593void
8594xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8595 xmlXPathObjectPtr hay, needle;
8596
8597 CHECK_ARITY(2);
8598 CAST_TO_STRING;
8599 CHECK_TYPE(XPATH_STRING);
8600 needle = valuePop(ctxt);
8601 CAST_TO_STRING;
8602 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008603
Owen Taylor3473f882001-02-23 17:55:21 +00008604 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008605 xmlXPathReleaseObject(ctxt->context, hay);
8606 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008607 XP_ERROR(XPATH_INVALID_TYPE);
8608 }
8609 if (xmlStrstr(hay->stringval, needle->stringval))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008610 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00008611 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008612 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8613 xmlXPathReleaseObject(ctxt->context, hay);
8614 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008615}
8616
8617/**
8618 * xmlXPathStartsWithFunction:
8619 * @ctxt: the XPath Parser context
8620 * @nargs: the number of arguments
8621 *
8622 * Implement the starts-with() XPath function
8623 * boolean starts-with(string, string)
8624 * The starts-with function returns true if the first argument string
8625 * starts with the second argument string, and otherwise returns false.
8626 */
8627void
8628xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8629 xmlXPathObjectPtr hay, needle;
8630 int n;
8631
8632 CHECK_ARITY(2);
8633 CAST_TO_STRING;
8634 CHECK_TYPE(XPATH_STRING);
8635 needle = valuePop(ctxt);
8636 CAST_TO_STRING;
8637 hay = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008638
Owen Taylor3473f882001-02-23 17:55:21 +00008639 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008640 xmlXPathReleaseObject(ctxt->context, hay);
8641 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008642 XP_ERROR(XPATH_INVALID_TYPE);
8643 }
8644 n = xmlStrlen(needle->stringval);
8645 if (xmlStrncmp(hay->stringval, needle->stringval, n))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008646 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00008647 else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008648 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8649 xmlXPathReleaseObject(ctxt->context, hay);
8650 xmlXPathReleaseObject(ctxt->context, needle);
Owen Taylor3473f882001-02-23 17:55:21 +00008651}
8652
8653/**
8654 * xmlXPathSubstringFunction:
8655 * @ctxt: the XPath Parser context
8656 * @nargs: the number of arguments
8657 *
8658 * Implement the substring() XPath function
8659 * string substring(string, number, number?)
8660 * The substring function returns the substring of the first argument
8661 * starting at the position specified in the second argument with
8662 * length specified in the third argument. For example,
8663 * substring("12345",2,3) returns "234". If the third argument is not
8664 * specified, it returns the substring starting at the position specified
8665 * in the second argument and continuing to the end of the string. For
8666 * example, substring("12345",2) returns "2345". More precisely, each
8667 * character in the string (see [3.6 Strings]) is considered to have a
8668 * numeric position: the position of the first character is 1, the position
8669 * of the second character is 2 and so on. The returned substring contains
8670 * those characters for which the position of the character is greater than
8671 * or equal to the second argument and, if the third argument is specified,
8672 * less than the sum of the second and third arguments; the comparisons
8673 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8674 * - substring("12345", 1.5, 2.6) returns "234"
8675 * - substring("12345", 0, 3) returns "12"
8676 * - substring("12345", 0 div 0, 3) returns ""
8677 * - substring("12345", 1, 0 div 0) returns ""
8678 * - substring("12345", -42, 1 div 0) returns "12345"
8679 * - substring("12345", -1 div 0, 1 div 0) returns ""
8680 */
8681void
8682xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008684 double le=0, in;
8685 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00008686 xmlChar *ret;
8687
Owen Taylor3473f882001-02-23 17:55:21 +00008688 if (nargs < 2) {
8689 CHECK_ARITY(2);
8690 }
8691 if (nargs > 3) {
8692 CHECK_ARITY(3);
8693 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008694 /*
8695 * take care of possible last (position) argument
8696 */
Owen Taylor3473f882001-02-23 17:55:21 +00008697 if (nargs == 3) {
8698 CAST_TO_NUMBER;
8699 CHECK_TYPE(XPATH_NUMBER);
8700 len = valuePop(ctxt);
8701 le = len->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008702 xmlXPathReleaseObject(ctxt->context, len);
Owen Taylor3473f882001-02-23 17:55:21 +00008703 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008704
Owen Taylor3473f882001-02-23 17:55:21 +00008705 CAST_TO_NUMBER;
8706 CHECK_TYPE(XPATH_NUMBER);
8707 start = valuePop(ctxt);
8708 in = start->floatval;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008709 xmlXPathReleaseObject(ctxt->context, start);
Owen Taylor3473f882001-02-23 17:55:21 +00008710 CAST_TO_STRING;
8711 CHECK_TYPE(XPATH_STRING);
8712 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00008713 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00008714
Daniel Veillard97ac1312001-05-30 19:14:17 +00008715 /*
8716 * If last pos not present, calculate last position
8717 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008718 if (nargs != 3) {
8719 le = (double)m;
8720 if (in < 1.0)
8721 in = 1.0;
8722 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00008723
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008724 /* Need to check for the special cases where either
8725 * the index is NaN, the length is NaN, or both
8726 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00008727 */
Daniel Veillard9e412302002-06-10 15:59:44 +00008728 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008729 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00008730 * To meet the requirements of the spec, the arguments
8731 * must be converted to integer format before
8732 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008733 *
Daniel Veillard9e412302002-06-10 15:59:44 +00008734 * First we go to integer form, rounding up
8735 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008736 */
8737 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00008738 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00008739
Daniel Veillard9e412302002-06-10 15:59:44 +00008740 if (xmlXPathIsInf(le) == 1) {
8741 l = m;
8742 if (i < 1)
8743 i = 1;
8744 }
8745 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
8746 l = 0;
8747 else {
8748 l = (int) le;
8749 if (((double)l)+0.5 <= le) l++;
8750 }
8751
8752 /* Now we normalize inidices */
8753 i -= 1;
8754 l += i;
8755 if (i < 0)
8756 i = 0;
8757 if (l > m)
8758 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00008759
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008760 /* number of chars to copy */
8761 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00008762
Daniel Veillard0eafdef2002-04-10 16:14:34 +00008763 ret = xmlUTF8Strsub(str->stringval, i, l);
8764 }
8765 else {
8766 ret = NULL;
8767 }
Owen Taylor3473f882001-02-23 17:55:21 +00008768 if (ret == NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008769 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
Owen Taylor3473f882001-02-23 17:55:21 +00008770 else {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008771 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00008772 xmlFree(ret);
8773 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008774 xmlXPathReleaseObject(ctxt->context, str);
Owen Taylor3473f882001-02-23 17:55:21 +00008775}
8776
8777/**
8778 * xmlXPathSubstringBeforeFunction:
8779 * @ctxt: the XPath Parser context
8780 * @nargs: the number of arguments
8781 *
8782 * Implement the substring-before() XPath function
8783 * string substring-before(string, string)
8784 * The substring-before function returns the substring of the first
8785 * argument string that precedes the first occurrence of the second
8786 * argument string in the first argument string, or the empty string
8787 * if the first argument string does not contain the second argument
8788 * string. For example, substring-before("1999/04/01","/") returns 1999.
8789 */
8790void
8791xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8792 xmlXPathObjectPtr str;
8793 xmlXPathObjectPtr find;
8794 xmlBufferPtr target;
8795 const xmlChar *point;
8796 int offset;
8797
8798 CHECK_ARITY(2);
8799 CAST_TO_STRING;
8800 find = valuePop(ctxt);
8801 CAST_TO_STRING;
8802 str = valuePop(ctxt);
8803
8804 target = xmlBufferCreate();
8805 if (target) {
8806 point = xmlStrstr(str->stringval, find->stringval);
8807 if (point) {
8808 offset = (int)(point - str->stringval);
8809 xmlBufferAdd(target, str->stringval, offset);
8810 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008811 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8812 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008813 xmlBufferFree(target);
8814 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008815 xmlXPathReleaseObject(ctxt->context, str);
8816 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008817}
8818
8819/**
8820 * xmlXPathSubstringAfterFunction:
8821 * @ctxt: the XPath Parser context
8822 * @nargs: the number of arguments
8823 *
8824 * Implement the substring-after() XPath function
8825 * string substring-after(string, string)
8826 * The substring-after function returns the substring of the first
8827 * argument string that follows the first occurrence of the second
8828 * argument string in the first argument string, or the empty stringi
8829 * if the first argument string does not contain the second argument
8830 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8831 * and substring-after("1999/04/01","19") returns 99/04/01.
8832 */
8833void
8834xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8835 xmlXPathObjectPtr str;
8836 xmlXPathObjectPtr find;
8837 xmlBufferPtr target;
8838 const xmlChar *point;
8839 int offset;
8840
8841 CHECK_ARITY(2);
8842 CAST_TO_STRING;
8843 find = valuePop(ctxt);
8844 CAST_TO_STRING;
8845 str = valuePop(ctxt);
8846
8847 target = xmlBufferCreate();
8848 if (target) {
8849 point = xmlStrstr(str->stringval, find->stringval);
8850 if (point) {
8851 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
8852 xmlBufferAdd(target, &str->stringval[offset],
8853 xmlStrlen(str->stringval) - offset);
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, str);
8860 xmlXPathReleaseObject(ctxt->context, find);
Owen Taylor3473f882001-02-23 17:55:21 +00008861}
8862
8863/**
8864 * xmlXPathNormalizeFunction:
8865 * @ctxt: the XPath Parser context
8866 * @nargs: the number of arguments
8867 *
8868 * Implement the normalize-space() XPath function
8869 * string normalize-space(string?)
8870 * The normalize-space function returns the argument string with white
8871 * space normalized by stripping leading and trailing whitespace
8872 * and replacing sequences of whitespace characters by a single
8873 * space. Whitespace characters are the same allowed by the S production
8874 * in XML. If the argument is omitted, it defaults to the context
8875 * node converted to a string, in other words the value of the context node.
8876 */
8877void
8878xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8879 xmlXPathObjectPtr obj = NULL;
8880 xmlChar *source = NULL;
8881 xmlBufferPtr target;
8882 xmlChar blank;
8883
Daniel Veillarda82b1822004-11-08 16:24:57 +00008884 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00008885 if (nargs == 0) {
8886 /* Use current context node */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008887 valuePush(ctxt,
8888 xmlXPathCacheWrapString(ctxt->context,
8889 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00008890 nargs = 1;
8891 }
8892
8893 CHECK_ARITY(1);
8894 CAST_TO_STRING;
8895 CHECK_TYPE(XPATH_STRING);
8896 obj = valuePop(ctxt);
8897 source = obj->stringval;
8898
8899 target = xmlBufferCreate();
8900 if (target && source) {
8901
8902 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00008903 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00008904 source++;
8905
8906 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8907 blank = 0;
8908 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00008909 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008910 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00008911 } else {
8912 if (blank) {
8913 xmlBufferAdd(target, &blank, 1);
8914 blank = 0;
8915 }
8916 xmlBufferAdd(target, source, 1);
8917 }
8918 source++;
8919 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008920 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8921 xmlBufferContent(target)));
Owen Taylor3473f882001-02-23 17:55:21 +00008922 xmlBufferFree(target);
8923 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00008924 xmlXPathReleaseObject(ctxt->context, obj);
Owen Taylor3473f882001-02-23 17:55:21 +00008925}
8926
8927/**
8928 * xmlXPathTranslateFunction:
8929 * @ctxt: the XPath Parser context
8930 * @nargs: the number of arguments
8931 *
8932 * Implement the translate() XPath function
8933 * string translate(string, string, string)
8934 * The translate function returns the first argument string with
8935 * occurrences of characters in the second argument string replaced
8936 * by the character at the corresponding position in the third argument
8937 * string. For example, translate("bar","abc","ABC") returns the string
8938 * BAr. If there is a character in the second argument string with no
8939 * character at a corresponding position in the third argument string
8940 * (because the second argument string is longer than the third argument
8941 * string), then occurrences of that character in the first argument
8942 * string are removed. For example, translate("--aaa--","abc-","ABC")
8943 * returns "AAA". If a character occurs more than once in second
8944 * argument string, then the first occurrence determines the replacement
8945 * character. If the third argument string is longer than the second
8946 * argument string, then excess characters are ignored.
8947 */
8948void
8949xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00008950 xmlXPathObjectPtr str;
8951 xmlXPathObjectPtr from;
8952 xmlXPathObjectPtr to;
8953 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008954 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00008955 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00008956 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00008957 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00008958
Daniel Veillarde043ee12001-04-16 14:08:07 +00008959 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00008960
Daniel Veillarde043ee12001-04-16 14:08:07 +00008961 CAST_TO_STRING;
8962 to = valuePop(ctxt);
8963 CAST_TO_STRING;
8964 from = valuePop(ctxt);
8965 CAST_TO_STRING;
8966 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008967
Daniel Veillarde043ee12001-04-16 14:08:07 +00008968 target = xmlBufferCreate();
8969 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00008970 max = xmlUTF8Strlen(to->stringval);
8971 for (cptr = str->stringval; (ch=*cptr); ) {
8972 offset = xmlUTF8Strloc(from->stringval, cptr);
8973 if (offset >= 0) {
8974 if (offset < max) {
8975 point = xmlUTF8Strpos(to->stringval, offset);
8976 if (point)
8977 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
8978 }
8979 } else
8980 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8981
8982 /* Step to next character in input */
8983 cptr++;
8984 if ( ch & 0x80 ) {
8985 /* if not simple ascii, verify proper format */
8986 if ( (ch & 0xc0) != 0xc0 ) {
8987 xmlGenericError(xmlGenericErrorContext,
8988 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8989 break;
8990 }
8991 /* then skip over remaining bytes for this char */
8992 while ( (ch <<= 1) & 0x80 )
8993 if ( (*cptr++ & 0xc0) != 0x80 ) {
8994 xmlGenericError(xmlGenericErrorContext,
8995 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8996 break;
8997 }
8998 if (ch & 0x80) /* must have had error encountered */
8999 break;
9000 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009001 }
Owen Taylor3473f882001-02-23 17:55:21 +00009002 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009003 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9004 xmlBufferContent(target)));
Daniel Veillarde043ee12001-04-16 14:08:07 +00009005 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009006 xmlXPathReleaseObject(ctxt->context, str);
9007 xmlXPathReleaseObject(ctxt->context, from);
9008 xmlXPathReleaseObject(ctxt->context, to);
Owen Taylor3473f882001-02-23 17:55:21 +00009009}
9010
9011/**
9012 * xmlXPathBooleanFunction:
9013 * @ctxt: the XPath Parser context
9014 * @nargs: the number of arguments
9015 *
9016 * Implement the boolean() XPath function
9017 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00009018 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00009019 * - a number is true if and only if it is neither positive or
9020 * negative zero nor NaN
9021 * - a node-set is true if and only if it is non-empty
9022 * - a string is true if and only if its length is non-zero
9023 */
9024void
9025xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9026 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00009027
9028 CHECK_ARITY(1);
9029 cur = valuePop(ctxt);
9030 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009031 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009032 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009033}
9034
9035/**
9036 * xmlXPathNotFunction:
9037 * @ctxt: the XPath Parser context
9038 * @nargs: the number of arguments
9039 *
9040 * Implement the not() XPath function
9041 * boolean not(boolean)
9042 * The not function returns true if its argument is false,
9043 * and false otherwise.
9044 */
9045void
9046xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9047 CHECK_ARITY(1);
9048 CAST_TO_BOOLEAN;
9049 CHECK_TYPE(XPATH_BOOLEAN);
9050 ctxt->value->boolval = ! ctxt->value->boolval;
9051}
9052
9053/**
9054 * xmlXPathTrueFunction:
9055 * @ctxt: the XPath Parser context
9056 * @nargs: the number of arguments
9057 *
9058 * Implement the true() XPath function
9059 * boolean true()
9060 */
9061void
9062xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9063 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009064 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009065}
9066
9067/**
9068 * xmlXPathFalseFunction:
9069 * @ctxt: the XPath Parser context
9070 * @nargs: the number of arguments
9071 *
9072 * Implement the false() XPath function
9073 * boolean false()
9074 */
9075void
9076xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9077 CHECK_ARITY(0);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009078 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009079}
9080
9081/**
9082 * xmlXPathLangFunction:
9083 * @ctxt: the XPath Parser context
9084 * @nargs: the number of arguments
9085 *
9086 * Implement the lang() XPath function
9087 * boolean lang(string)
9088 * The lang function returns true or false depending on whether the
9089 * language of the context node as specified by xml:lang attributes
9090 * is the same as or is a sublanguage of the language specified by
9091 * the argument string. The language of the context node is determined
9092 * by the value of the xml:lang attribute on the context node, or, if
9093 * the context node has no xml:lang attribute, by the value of the
9094 * xml:lang attribute on the nearest ancestor of the context node that
9095 * has an xml:lang attribute. If there is no such attribute, then lang
9096 * returns false. If there is such an attribute, then lang returns
9097 * true if the attribute value is equal to the argument ignoring case,
9098 * or if there is some suffix starting with - such that the attribute
9099 * value is equal to the argument ignoring that suffix of the attribute
9100 * value and ignoring case.
9101 */
9102void
9103xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009104 xmlXPathObjectPtr val = NULL;
9105 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00009106 const xmlChar *lang;
9107 int ret = 0;
9108 int i;
9109
9110 CHECK_ARITY(1);
9111 CAST_TO_STRING;
9112 CHECK_TYPE(XPATH_STRING);
9113 val = valuePop(ctxt);
9114 lang = val->stringval;
9115 theLang = xmlNodeGetLang(ctxt->context->node);
9116 if ((theLang != NULL) && (lang != NULL)) {
9117 for (i = 0;lang[i] != 0;i++)
9118 if (toupper(lang[i]) != toupper(theLang[i]))
9119 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009120 if ((theLang[i] == 0) || (theLang[i] == '-'))
9121 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009122 }
9123not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00009124 if (theLang != NULL)
9125 xmlFree((void *)theLang);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009126
9127 xmlXPathReleaseObject(ctxt->context, val);
9128 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Owen Taylor3473f882001-02-23 17:55:21 +00009129}
9130
9131/**
9132 * xmlXPathNumberFunction:
9133 * @ctxt: the XPath Parser context
9134 * @nargs: the number of arguments
9135 *
9136 * Implement the number() XPath function
9137 * number number(object?)
9138 */
9139void
9140xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9141 xmlXPathObjectPtr cur;
9142 double res;
9143
Daniel Veillarda82b1822004-11-08 16:24:57 +00009144 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00009145 if (nargs == 0) {
9146 if (ctxt->context->node == NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009147 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
Owen Taylor3473f882001-02-23 17:55:21 +00009148 } else {
9149 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9150
9151 res = xmlXPathStringEvalNumber(content);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009152 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
Owen Taylor3473f882001-02-23 17:55:21 +00009153 xmlFree(content);
9154 }
9155 return;
9156 }
9157
9158 CHECK_ARITY(1);
9159 cur = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009160 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
Owen Taylor3473f882001-02-23 17:55:21 +00009161}
9162
9163/**
9164 * xmlXPathSumFunction:
9165 * @ctxt: the XPath Parser context
9166 * @nargs: the number of arguments
9167 *
9168 * Implement the sum() XPath function
9169 * number sum(node-set)
9170 * The sum function returns the sum of the values of the nodes in
9171 * the argument node-set.
9172 */
9173void
9174xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175 xmlXPathObjectPtr cur;
9176 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009177 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00009178
9179 CHECK_ARITY(1);
9180 if ((ctxt->value == NULL) ||
9181 ((ctxt->value->type != XPATH_NODESET) &&
9182 (ctxt->value->type != XPATH_XSLT_TREE)))
9183 XP_ERROR(XPATH_INVALID_TYPE);
9184 cur = valuePop(ctxt);
9185
William M. Brack08171912003-12-29 02:52:11 +00009186 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00009187 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9188 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00009189 }
9190 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009191 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9192 xmlXPathReleaseObject(ctxt->context, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00009193}
9194
William M. Brack3d426662005-04-19 14:40:28 +00009195/*
9196 * To assure working code on multiple platforms, we want to only depend
9197 * upon the characteristic truncation of converting a floating point value
9198 * to an integer. Unfortunately, because of the different storage sizes
9199 * of our internal floating point value (double) and integer (int), we
9200 * can't directly convert (see bug 301162). This macro is a messy
9201 * 'workaround'
9202 */
9203#define XTRUNC(f, v) \
9204 f = fmod((v), INT_MAX); \
9205 f = (v) - (f) + (double)((int)(f));
9206
Owen Taylor3473f882001-02-23 17:55:21 +00009207/**
9208 * xmlXPathFloorFunction:
9209 * @ctxt: the XPath Parser context
9210 * @nargs: the number of arguments
9211 *
9212 * Implement the floor() XPath function
9213 * number floor(number)
9214 * The floor function returns the largest (closest to positive infinity)
9215 * number that is not greater than the argument and that is an integer.
9216 */
9217void
9218xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009219 double f;
9220
Owen Taylor3473f882001-02-23 17:55:21 +00009221 CHECK_ARITY(1);
9222 CAST_TO_NUMBER;
9223 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009224
William M. Brack3d426662005-04-19 14:40:28 +00009225 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009226 if (f != ctxt->value->floatval) {
9227 if (ctxt->value->floatval > 0)
9228 ctxt->value->floatval = f;
9229 else
9230 ctxt->value->floatval = f - 1;
9231 }
Owen Taylor3473f882001-02-23 17:55:21 +00009232}
9233
9234/**
9235 * xmlXPathCeilingFunction:
9236 * @ctxt: the XPath Parser context
9237 * @nargs: the number of arguments
9238 *
9239 * Implement the ceiling() XPath function
9240 * number ceiling(number)
9241 * The ceiling function returns the smallest (closest to negative infinity)
9242 * number that is not less than the argument and that is an integer.
9243 */
9244void
9245xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9246 double f;
9247
9248 CHECK_ARITY(1);
9249 CAST_TO_NUMBER;
9250 CHECK_TYPE(XPATH_NUMBER);
9251
9252#if 0
9253 ctxt->value->floatval = ceil(ctxt->value->floatval);
9254#else
William M. Brack3d426662005-04-19 14:40:28 +00009255 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009256 if (f != ctxt->value->floatval) {
9257 if (ctxt->value->floatval > 0)
9258 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009259 else {
9260 if (ctxt->value->floatval < 0 && f == 0)
9261 ctxt->value->floatval = xmlXPathNZERO;
9262 else
9263 ctxt->value->floatval = f;
9264 }
9265
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009266 }
Owen Taylor3473f882001-02-23 17:55:21 +00009267#endif
9268}
9269
9270/**
9271 * xmlXPathRoundFunction:
9272 * @ctxt: the XPath Parser context
9273 * @nargs: the number of arguments
9274 *
9275 * Implement the round() XPath function
9276 * number round(number)
9277 * The round function returns the number that is closest to the
9278 * argument and that is an integer. If there are two such numbers,
9279 * then the one that is even is returned.
9280 */
9281void
9282xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9283 double f;
9284
9285 CHECK_ARITY(1);
9286 CAST_TO_NUMBER;
9287 CHECK_TYPE(XPATH_NUMBER);
9288
Daniel Veillardcda96922001-08-21 10:56:31 +00009289 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9290 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9291 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00009292 (ctxt->value->floatval == 0.0))
9293 return;
9294
William M. Brack3d426662005-04-19 14:40:28 +00009295 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009296 if (ctxt->value->floatval < 0) {
9297 if (ctxt->value->floatval < f - 0.5)
9298 ctxt->value->floatval = f - 1;
9299 else
9300 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00009301 if (ctxt->value->floatval == 0)
9302 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00009303 } else {
9304 if (ctxt->value->floatval < f + 0.5)
9305 ctxt->value->floatval = f;
9306 else
9307 ctxt->value->floatval = f + 1;
9308 }
Owen Taylor3473f882001-02-23 17:55:21 +00009309}
9310
9311/************************************************************************
9312 * *
9313 * The Parser *
9314 * *
9315 ************************************************************************/
9316
9317/*
William M. Brack08171912003-12-29 02:52:11 +00009318 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00009319 * implementation.
9320 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009321static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009322static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009323static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009324static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00009325static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9326 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00009327
9328/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00009329 * xmlXPathCurrentChar:
9330 * @ctxt: the XPath parser context
9331 * @cur: pointer to the beginning of the char
9332 * @len: pointer to the length of the char read
9333 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009334 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00009335 * bytes in the input buffer.
9336 *
Daniel Veillard60087f32001-10-10 09:45:09 +00009337 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00009338 */
9339
9340static int
9341xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9342 unsigned char c;
9343 unsigned int val;
9344 const xmlChar *cur;
9345
9346 if (ctxt == NULL)
9347 return(0);
9348 cur = ctxt->cur;
9349
9350 /*
9351 * We are supposed to handle UTF8, check it's valid
9352 * From rfc2044: encoding of the Unicode values on UTF-8:
9353 *
9354 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9355 * 0000 0000-0000 007F 0xxxxxxx
9356 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9357 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9358 *
9359 * Check for the 0x110000 limit too
9360 */
9361 c = *cur;
9362 if (c & 0x80) {
9363 if ((cur[1] & 0xc0) != 0x80)
9364 goto encoding_error;
9365 if ((c & 0xe0) == 0xe0) {
9366
9367 if ((cur[2] & 0xc0) != 0x80)
9368 goto encoding_error;
9369 if ((c & 0xf0) == 0xf0) {
9370 if (((c & 0xf8) != 0xf0) ||
9371 ((cur[3] & 0xc0) != 0x80))
9372 goto encoding_error;
9373 /* 4-byte code */
9374 *len = 4;
9375 val = (cur[0] & 0x7) << 18;
9376 val |= (cur[1] & 0x3f) << 12;
9377 val |= (cur[2] & 0x3f) << 6;
9378 val |= cur[3] & 0x3f;
9379 } else {
9380 /* 3-byte code */
9381 *len = 3;
9382 val = (cur[0] & 0xf) << 12;
9383 val |= (cur[1] & 0x3f) << 6;
9384 val |= cur[2] & 0x3f;
9385 }
9386 } else {
9387 /* 2-byte code */
9388 *len = 2;
9389 val = (cur[0] & 0x1f) << 6;
9390 val |= cur[1] & 0x3f;
9391 }
9392 if (!IS_CHAR(val)) {
9393 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9394 }
9395 return(val);
9396 } else {
9397 /* 1-byte code */
9398 *len = 1;
9399 return((int) *cur);
9400 }
9401encoding_error:
9402 /*
William M. Brack08171912003-12-29 02:52:11 +00009403 * If we detect an UTF8 error that probably means that the
9404 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00009405 * declaration header. Report the error and switch the encoding
9406 * to ISO-Latin-1 (if you don't like this policy, just declare the
9407 * encoding !)
9408 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00009409 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00009410 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009411}
9412
9413/**
Owen Taylor3473f882001-02-23 17:55:21 +00009414 * xmlXPathParseNCName:
9415 * @ctxt: the XPath Parser context
9416 *
9417 * parse an XML namespace non qualified name.
9418 *
9419 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9420 *
9421 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9422 * CombiningChar | Extender
9423 *
9424 * Returns the namespace name or NULL
9425 */
9426
9427xmlChar *
9428xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00009429 const xmlChar *in;
9430 xmlChar *ret;
9431 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009432
Daniel Veillarda82b1822004-11-08 16:24:57 +00009433 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00009434 /*
9435 * Accelerator for simple ASCII names
9436 */
9437 in = ctxt->cur;
9438 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9439 ((*in >= 0x41) && (*in <= 0x5A)) ||
9440 (*in == '_')) {
9441 in++;
9442 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9443 ((*in >= 0x41) && (*in <= 0x5A)) ||
9444 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00009445 (*in == '_') || (*in == '.') ||
9446 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00009447 in++;
9448 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9449 (*in == '[') || (*in == ']') || (*in == ':') ||
9450 (*in == '@') || (*in == '*')) {
9451 count = in - ctxt->cur;
9452 if (count == 0)
9453 return(NULL);
9454 ret = xmlStrndup(ctxt->cur, count);
9455 ctxt->cur = in;
9456 return(ret);
9457 }
9458 }
9459 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00009460}
9461
Daniel Veillard2156a562001-04-28 12:24:34 +00009462
Owen Taylor3473f882001-02-23 17:55:21 +00009463/**
9464 * xmlXPathParseQName:
9465 * @ctxt: the XPath Parser context
9466 * @prefix: a xmlChar **
9467 *
9468 * parse an XML qualified name
9469 *
9470 * [NS 5] QName ::= (Prefix ':')? LocalPart
9471 *
9472 * [NS 6] Prefix ::= NCName
9473 *
9474 * [NS 7] LocalPart ::= NCName
9475 *
9476 * Returns the function returns the local part, and prefix is updated
9477 * to get the Prefix if any.
9478 */
9479
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009480static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00009481xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9482 xmlChar *ret = NULL;
9483
9484 *prefix = NULL;
9485 ret = xmlXPathParseNCName(ctxt);
9486 if (CUR == ':') {
9487 *prefix = ret;
9488 NEXT;
9489 ret = xmlXPathParseNCName(ctxt);
9490 }
9491 return(ret);
9492}
9493
9494/**
9495 * xmlXPathParseName:
9496 * @ctxt: the XPath Parser context
9497 *
9498 * parse an XML name
9499 *
9500 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9501 * CombiningChar | Extender
9502 *
9503 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9504 *
9505 * Returns the namespace name or NULL
9506 */
9507
9508xmlChar *
9509xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009510 const xmlChar *in;
9511 xmlChar *ret;
9512 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009513
Daniel Veillarda82b1822004-11-08 16:24:57 +00009514 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009515 /*
9516 * Accelerator for simple ASCII names
9517 */
9518 in = ctxt->cur;
9519 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9520 ((*in >= 0x41) && (*in <= 0x5A)) ||
9521 (*in == '_') || (*in == ':')) {
9522 in++;
9523 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9524 ((*in >= 0x41) && (*in <= 0x5A)) ||
9525 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00009526 (*in == '_') || (*in == '-') ||
9527 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00009528 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00009529 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009530 count = in - ctxt->cur;
9531 ret = xmlStrndup(ctxt->cur, count);
9532 ctxt->cur = in;
9533 return(ret);
9534 }
9535 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009536 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00009537}
9538
Daniel Veillard61d80a22001-04-27 17:13:01 +00009539static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00009540xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009541 xmlChar buf[XML_MAX_NAMELEN + 5];
9542 int len = 0, l;
9543 int c;
9544
9545 /*
9546 * Handler for more complex cases
9547 */
9548 c = CUR_CHAR(l);
9549 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00009550 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9551 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00009552 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00009553 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00009554 return(NULL);
9555 }
9556
9557 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9558 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9559 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009560 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009561 (IS_COMBINING(c)) ||
9562 (IS_EXTENDER(c)))) {
9563 COPY_BUF(l,buf,len,c);
9564 NEXTL(l);
9565 c = CUR_CHAR(l);
9566 if (len >= XML_MAX_NAMELEN) {
9567 /*
9568 * Okay someone managed to make a huge name, so he's ready to pay
9569 * for the processing speed.
9570 */
9571 xmlChar *buffer;
9572 int max = len * 2;
9573
Daniel Veillard3c908dc2003-04-19 00:07:51 +00009574 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009575 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009576 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009577 }
9578 memcpy(buffer, buf, len);
9579 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9580 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00009581 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00009582 (IS_COMBINING(c)) ||
9583 (IS_EXTENDER(c))) {
9584 if (len + 10 > max) {
9585 max *= 2;
9586 buffer = (xmlChar *) xmlRealloc(buffer,
9587 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00009588 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009589 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009590 }
9591 }
9592 COPY_BUF(l,buffer,len,c);
9593 NEXTL(l);
9594 c = CUR_CHAR(l);
9595 }
9596 buffer[len] = 0;
9597 return(buffer);
9598 }
9599 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009600 if (len == 0)
9601 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00009602 return(xmlStrndup(buf, len));
9603}
Daniel Veillard3cd72402002-05-13 10:33:30 +00009604
9605#define MAX_FRAC 20
9606
William M. Brack372a4452004-02-17 13:09:23 +00009607/*
9608 * These are used as divisors for the fractional part of a number.
9609 * Since the table includes 1.0 (representing '0' fractional digits),
9610 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9611 */
9612static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009613 1.0, 10.0, 100.0, 1000.0, 10000.0,
9614 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9615 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9616 100000000000000.0,
9617 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00009618 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00009619};
9620
Owen Taylor3473f882001-02-23 17:55:21 +00009621/**
9622 * xmlXPathStringEvalNumber:
9623 * @str: A string to scan
9624 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00009625 * [30a] Float ::= Number ('e' Digits?)?
9626 *
Owen Taylor3473f882001-02-23 17:55:21 +00009627 * [30] Number ::= Digits ('.' Digits?)?
9628 * | '.' Digits
9629 * [31] Digits ::= [0-9]+
9630 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009631 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00009632 * In complement of the Number expression, this function also handles
9633 * negative values : '-' Number.
9634 *
9635 * Returns the double value.
9636 */
9637double
9638xmlXPathStringEvalNumber(const xmlChar *str) {
9639 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00009640 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009641 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009642 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009643 int exponent = 0;
9644 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009645#ifdef __GNUC__
9646 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009647 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009648#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00009649 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00009650 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009651 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9652 return(xmlXPathNAN);
9653 }
9654 if (*cur == '-') {
9655 isneg = 1;
9656 cur++;
9657 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009658
9659#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009660 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009661 * tmp/temp is a workaround against a gcc compiler bug
9662 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009663 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009664 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009665 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009666 ret = ret * 10;
9667 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00009668 ok = 1;
9669 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00009670 temp = (double) tmp;
9671 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009672 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00009673#else
Daniel Veillard7b416132002-03-07 08:36:03 +00009674 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00009675 while ((*cur >= '0') && (*cur <= '9')) {
9676 ret = ret * 10 + (*cur - '0');
9677 ok = 1;
9678 cur++;
9679 }
9680#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009681
Owen Taylor3473f882001-02-23 17:55:21 +00009682 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00009683 int v, frac = 0;
9684 double fraction = 0;
9685
Owen Taylor3473f882001-02-23 17:55:21 +00009686 cur++;
9687 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9688 return(xmlXPathNAN);
9689 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009690 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9691 v = (*cur - '0');
9692 fraction = fraction * 10 + v;
9693 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009694 cur++;
9695 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00009696 fraction /= my_pow10[frac];
9697 ret = ret + fraction;
9698 while ((*cur >= '0') && (*cur <= '9'))
9699 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009700 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009701 if ((*cur == 'e') || (*cur == 'E')) {
9702 cur++;
9703 if (*cur == '-') {
9704 is_exponent_negative = 1;
9705 cur++;
William M. Brack99127052004-05-24 02:52:28 +00009706 } else if (*cur == '+') {
9707 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009708 }
9709 while ((*cur >= '0') && (*cur <= '9')) {
9710 exponent = exponent * 10 + (*cur - '0');
9711 cur++;
9712 }
9713 }
William M. Brack76e95df2003-10-18 16:20:14 +00009714 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00009715 if (*cur != 0) return(xmlXPathNAN);
9716 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009717 if (is_exponent_negative) exponent = -exponent;
9718 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00009719 return(ret);
9720}
9721
9722/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009723 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00009724 * @ctxt: the XPath Parser context
9725 *
9726 * [30] Number ::= Digits ('.' Digits?)?
9727 * | '.' Digits
9728 * [31] Digits ::= [0-9]+
9729 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009730 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00009731 *
9732 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009733static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009734xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9735{
Owen Taylor3473f882001-02-23 17:55:21 +00009736 double ret = 0.0;
9737 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00009738 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00009739 int exponent = 0;
9740 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00009741#ifdef __GNUC__
9742 unsigned long tmp = 0;
9743 double temp;
9744#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009745
9746 CHECK_ERROR;
9747 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9748 XP_ERROR(XPATH_NUMBER_ERROR);
9749 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009750#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009751 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00009752 * tmp/temp is a workaround against a gcc compiler bug
9753 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009754 */
Daniel Veillard7b416132002-03-07 08:36:03 +00009755 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009756 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00009757 ret = ret * 10;
9758 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009759 ok = 1;
9760 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00009761 temp = (double) tmp;
9762 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00009763 }
Daniel Veillard7b416132002-03-07 08:36:03 +00009764#else
9765 ret = 0;
9766 while ((CUR >= '0') && (CUR <= '9')) {
9767 ret = ret * 10 + (CUR - '0');
9768 ok = 1;
9769 NEXT;
9770 }
9771#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009772 if (CUR == '.') {
9773 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009774 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9775 XP_ERROR(XPATH_NUMBER_ERROR);
9776 }
9777 while ((CUR >= '0') && (CUR <= '9')) {
9778 mult /= 10;
9779 ret = ret + (CUR - '0') * mult;
9780 NEXT;
9781 }
Owen Taylor3473f882001-02-23 17:55:21 +00009782 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00009783 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009784 NEXT;
9785 if (CUR == '-') {
9786 is_exponent_negative = 1;
9787 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00009788 } else if (CUR == '+') {
9789 NEXT;
9790 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00009791 while ((CUR >= '0') && (CUR <= '9')) {
9792 exponent = exponent * 10 + (CUR - '0');
9793 NEXT;
9794 }
9795 if (is_exponent_negative)
9796 exponent = -exponent;
9797 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00009798 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009799 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009800 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009801}
9802
9803/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009804 * xmlXPathParseLiteral:
9805 * @ctxt: the XPath Parser context
9806 *
9807 * Parse a Literal
9808 *
9809 * [29] Literal ::= '"' [^"]* '"'
9810 * | "'" [^']* "'"
9811 *
9812 * Returns the value found or NULL in case of error
9813 */
9814static xmlChar *
9815xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9816 const xmlChar *q;
9817 xmlChar *ret = NULL;
9818
9819 if (CUR == '"') {
9820 NEXT;
9821 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009822 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009823 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009824 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009825 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009826 } else {
9827 ret = xmlStrndup(q, CUR_PTR - q);
9828 NEXT;
9829 }
9830 } else if (CUR == '\'') {
9831 NEXT;
9832 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009833 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009834 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009835 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009836 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009837 } else {
9838 ret = xmlStrndup(q, CUR_PTR - q);
9839 NEXT;
9840 }
9841 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00009842 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009843 }
9844 return(ret);
9845}
9846
9847/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009848 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00009849 * @ctxt: the XPath Parser context
9850 *
9851 * Parse a Literal and push it on the stack.
9852 *
9853 * [29] Literal ::= '"' [^"]* '"'
9854 * | "'" [^']* "'"
9855 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009856 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00009857 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009858static void
9859xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009860 const xmlChar *q;
9861 xmlChar *ret = NULL;
9862
9863 if (CUR == '"') {
9864 NEXT;
9865 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009866 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00009867 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009868 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009869 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9870 } else {
9871 ret = xmlStrndup(q, CUR_PTR - q);
9872 NEXT;
9873 }
9874 } else if (CUR == '\'') {
9875 NEXT;
9876 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00009877 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00009878 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00009879 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00009880 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9881 } else {
9882 ret = xmlStrndup(q, CUR_PTR - q);
9883 NEXT;
9884 }
9885 } else {
9886 XP_ERROR(XPATH_START_LITERAL_ERROR);
9887 }
9888 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009889 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +00009890 xmlXPathCacheNewString(ctxt->context, ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009891 xmlFree(ret);
9892}
9893
9894/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009895 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00009896 * @ctxt: the XPath Parser context
9897 *
9898 * Parse a VariableReference, evaluate it and push it on the stack.
9899 *
9900 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00009901 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00009902 * of any of the types that are possible for the value of an expression,
9903 * and may also be of additional types not specified here.
9904 *
9905 * Early evaluation is possible since:
9906 * The variable bindings [...] used to evaluate a subexpression are
9907 * always the same as those used to evaluate the containing expression.
9908 *
9909 * [36] VariableReference ::= '$' QName
9910 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009911static void
9912xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009913 xmlChar *name;
9914 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009915
9916 SKIP_BLANKS;
9917 if (CUR != '$') {
9918 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9919 }
9920 NEXT;
9921 name = xmlXPathParseQName(ctxt, &prefix);
9922 if (name == NULL) {
9923 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9924 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009925 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009926 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
9927 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00009928 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00009929 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9930 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
9931 }
Owen Taylor3473f882001-02-23 17:55:21 +00009932}
9933
9934/**
9935 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00009936 * @name: a name string
9937 *
9938 * Is the name given a NodeType one.
9939 *
9940 * [38] NodeType ::= 'comment'
9941 * | 'text'
9942 * | 'processing-instruction'
9943 * | 'node'
9944 *
9945 * Returns 1 if true 0 otherwise
9946 */
9947int
9948xmlXPathIsNodeType(const xmlChar *name) {
9949 if (name == NULL)
9950 return(0);
9951
Daniel Veillard1971ee22002-01-31 20:29:19 +00009952 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00009953 return(1);
9954 if (xmlStrEqual(name, BAD_CAST "text"))
9955 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009956 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00009957 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00009958 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00009959 return(1);
9960 return(0);
9961}
9962
9963/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009964 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00009965 * @ctxt: the XPath Parser context
9966 *
9967 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9968 * [17] Argument ::= Expr
9969 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009970 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00009971 * pushed on the stack
9972 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009973static void
9974xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009975 xmlChar *name;
9976 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00009977 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009978 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009979
9980 name = xmlXPathParseQName(ctxt, &prefix);
9981 if (name == NULL) {
9982 XP_ERROR(XPATH_EXPR_ERROR);
9983 }
9984 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00009985#ifdef DEBUG_EXPR
9986 if (prefix == NULL)
9987 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
9988 name);
9989 else
9990 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
9991 prefix, name);
9992#endif
9993
Owen Taylor3473f882001-02-23 17:55:21 +00009994 if (CUR != '(') {
9995 XP_ERROR(XPATH_EXPR_ERROR);
9996 }
9997 NEXT;
9998 SKIP_BLANKS;
9999
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010000 /*
10001 * Optimization for count(): we don't need the node-set to be sorted.
10002 */
10003 if ((prefix == NULL) && (name[0] == 'c') &&
10004 xmlStrEqual(name, BAD_CAST "count"))
10005 {
10006 sort = 0;
10007 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010008 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +000010009 if (CUR != ')') {
10010 while (CUR != 0) {
10011 int op1 = ctxt->comp->last;
10012 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010013 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +000010014 CHECK_ERROR;
10015 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10016 nbargs++;
10017 if (CUR == ')') break;
10018 if (CUR != ',') {
10019 XP_ERROR(XPATH_EXPR_ERROR);
10020 }
10021 NEXT;
10022 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010023 }
Owen Taylor3473f882001-02-23 17:55:21 +000010024 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010025 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10026 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +000010027 NEXT;
10028 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +000010029}
10030
10031/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010032 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010033 * @ctxt: the XPath Parser context
10034 *
10035 * [15] PrimaryExpr ::= VariableReference
10036 * | '(' Expr ')'
10037 * | Literal
10038 * | Number
10039 * | FunctionCall
10040 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010041 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010042 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010043static void
10044xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010045 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010046 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010047 else if (CUR == '(') {
10048 NEXT;
10049 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010050 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000010051 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +000010052 if (CUR != ')') {
10053 XP_ERROR(XPATH_EXPR_ERROR);
10054 }
10055 NEXT;
10056 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010057 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010058 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010059 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010060 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010061 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010062 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010063 }
10064 SKIP_BLANKS;
10065}
10066
10067/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010068 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010069 * @ctxt: the XPath Parser context
10070 *
10071 * [20] FilterExpr ::= PrimaryExpr
10072 * | FilterExpr Predicate
10073 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010074 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010075 * Square brackets are used to filter expressions in the same way that
10076 * they are used in location paths. It is an error if the expression to
10077 * be filtered does not evaluate to a node-set. The context node list
10078 * used for evaluating the expression in square brackets is the node-set
10079 * to be filtered listed in document order.
10080 */
10081
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010082static void
10083xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10084 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010085 CHECK_ERROR;
10086 SKIP_BLANKS;
10087
10088 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010089 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +000010090 SKIP_BLANKS;
10091 }
10092
10093
10094}
10095
10096/**
10097 * xmlXPathScanName:
10098 * @ctxt: the XPath Parser context
10099 *
10100 * Trickery: parse an XML name but without consuming the input flow
10101 * Needed to avoid insanity in the parser state.
10102 *
10103 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10104 * CombiningChar | Extender
10105 *
10106 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10107 *
10108 * [6] Names ::= Name (S Name)*
10109 *
10110 * Returns the Name parsed or NULL
10111 */
10112
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010113static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +000010114xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +000010115 int len = 0, l;
10116 int c;
Daniel Veillard03226812004-11-01 14:55:21 +000010117 const xmlChar *cur;
10118 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +000010119
Daniel Veillard03226812004-11-01 14:55:21 +000010120 cur = ctxt->cur;
10121
10122 c = CUR_CHAR(l);
10123 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10124 (!IS_LETTER(c) && (c != '_') &&
10125 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010126 return(NULL);
10127 }
10128
Daniel Veillard03226812004-11-01 14:55:21 +000010129 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10130 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10131 (c == '.') || (c == '-') ||
10132 (c == '_') || (c == ':') ||
10133 (IS_COMBINING(c)) ||
10134 (IS_EXTENDER(c)))) {
10135 len += l;
10136 NEXTL(l);
10137 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +000010138 }
Daniel Veillard03226812004-11-01 14:55:21 +000010139 ret = xmlStrndup(cur, ctxt->cur - cur);
10140 ctxt->cur = cur;
10141 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +000010142}
10143
10144/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010145 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010146 * @ctxt: the XPath Parser context
10147 *
10148 * [19] PathExpr ::= LocationPath
10149 * | FilterExpr
10150 * | FilterExpr '/' RelativeLocationPath
10151 * | FilterExpr '//' RelativeLocationPath
10152 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010153 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010154 * The / operator and // operators combine an arbitrary expression
10155 * and a relative location path. It is an error if the expression
10156 * does not evaluate to a node-set.
10157 * The / operator does composition in the same way as when / is
10158 * used in a location path. As in location paths, // is short for
10159 * /descendant-or-self::node()/.
10160 */
10161
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010162static void
10163xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010164 int lc = 1; /* Should we branch to LocationPath ? */
10165 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10166
10167 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +000010168 if ((CUR == '$') || (CUR == '(') ||
10169 (IS_ASCII_DIGIT(CUR)) ||
10170 (CUR == '\'') || (CUR == '"') ||
10171 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +000010172 lc = 0;
10173 } else if (CUR == '*') {
10174 /* relative or absolute location path */
10175 lc = 1;
10176 } else if (CUR == '/') {
10177 /* relative or absolute location path */
10178 lc = 1;
10179 } else if (CUR == '@') {
10180 /* relative abbreviated attribute location path */
10181 lc = 1;
10182 } else if (CUR == '.') {
10183 /* relative abbreviated attribute location path */
10184 lc = 1;
10185 } else {
10186 /*
10187 * Problem is finding if we have a name here whether it's:
10188 * - a nodetype
10189 * - a function call in which case it's followed by '('
10190 * - an axis in which case it's followed by ':'
10191 * - a element name
10192 * We do an a priori analysis here rather than having to
10193 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +000010194 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +000010195 * read/write/debug.
10196 */
10197 SKIP_BLANKS;
10198 name = xmlXPathScanName(ctxt);
10199 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10200#ifdef DEBUG_STEP
10201 xmlGenericError(xmlGenericErrorContext,
10202 "PathExpr: Axis\n");
10203#endif
10204 lc = 1;
10205 xmlFree(name);
10206 } else if (name != NULL) {
10207 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +000010208
10209
10210 while (NXT(len) != 0) {
10211 if (NXT(len) == '/') {
10212 /* element name */
10213#ifdef DEBUG_STEP
10214 xmlGenericError(xmlGenericErrorContext,
10215 "PathExpr: AbbrRelLocation\n");
10216#endif
10217 lc = 1;
10218 break;
William M. Brack76e95df2003-10-18 16:20:14 +000010219 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +000010220 /* ignore blanks */
10221 ;
Owen Taylor3473f882001-02-23 17:55:21 +000010222 } else if (NXT(len) == ':') {
10223#ifdef DEBUG_STEP
10224 xmlGenericError(xmlGenericErrorContext,
10225 "PathExpr: AbbrRelLocation\n");
10226#endif
10227 lc = 1;
10228 break;
10229 } else if ((NXT(len) == '(')) {
10230 /* Note Type or Function */
10231 if (xmlXPathIsNodeType(name)) {
10232#ifdef DEBUG_STEP
10233 xmlGenericError(xmlGenericErrorContext,
10234 "PathExpr: Type search\n");
10235#endif
10236 lc = 1;
10237 } else {
10238#ifdef DEBUG_STEP
10239 xmlGenericError(xmlGenericErrorContext,
10240 "PathExpr: function call\n");
10241#endif
10242 lc = 0;
10243 }
10244 break;
10245 } else if ((NXT(len) == '[')) {
10246 /* element name */
10247#ifdef DEBUG_STEP
10248 xmlGenericError(xmlGenericErrorContext,
10249 "PathExpr: AbbrRelLocation\n");
10250#endif
10251 lc = 1;
10252 break;
10253 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10254 (NXT(len) == '=')) {
10255 lc = 1;
10256 break;
10257 } else {
10258 lc = 1;
10259 break;
10260 }
10261 len++;
10262 }
10263 if (NXT(len) == 0) {
10264#ifdef DEBUG_STEP
10265 xmlGenericError(xmlGenericErrorContext,
10266 "PathExpr: AbbrRelLocation\n");
10267#endif
10268 /* element name */
10269 lc = 1;
10270 }
10271 xmlFree(name);
10272 } else {
William M. Brack08171912003-12-29 02:52:11 +000010273 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +000010274 XP_ERROR(XPATH_EXPR_ERROR);
10275 }
10276 }
10277
10278 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010279 if (CUR == '/') {
10280 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10281 } else {
10282 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010283 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010284 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010285 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010286 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010287 CHECK_ERROR;
10288 if ((CUR == '/') && (NXT(1) == '/')) {
10289 SKIP(2);
10290 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010291
10292 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10293 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10294 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10295
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010296 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010297 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010298 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010299 }
10300 }
10301 SKIP_BLANKS;
10302}
10303
10304/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010305 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010306 * @ctxt: the XPath Parser context
10307 *
10308 * [18] UnionExpr ::= PathExpr
10309 * | UnionExpr '|' PathExpr
10310 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010311 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010312 */
10313
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010314static void
10315xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10316 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010317 CHECK_ERROR;
10318 SKIP_BLANKS;
10319 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010320 int op1 = ctxt->comp->last;
10321 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010322
10323 NEXT;
10324 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010325 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010326
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010327 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10328
Owen Taylor3473f882001-02-23 17:55:21 +000010329 SKIP_BLANKS;
10330 }
Owen Taylor3473f882001-02-23 17:55:21 +000010331}
10332
10333/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010334 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010335 * @ctxt: the XPath Parser context
10336 *
10337 * [27] UnaryExpr ::= UnionExpr
10338 * | '-' UnaryExpr
10339 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010340 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010341 */
10342
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010343static void
10344xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000010345 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010346 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010347
10348 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +000010349 while (CUR == '-') {
10350 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010351 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010352 NEXT;
10353 SKIP_BLANKS;
10354 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010355
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010356 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010357 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010358 if (found) {
10359 if (minus)
10360 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10361 else
10362 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010363 }
10364}
10365
10366/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010367 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010368 * @ctxt: the XPath Parser context
10369 *
10370 * [26] MultiplicativeExpr ::= UnaryExpr
10371 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10372 * | MultiplicativeExpr 'div' UnaryExpr
10373 * | MultiplicativeExpr 'mod' UnaryExpr
10374 * [34] MultiplyOperator ::= '*'
10375 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010376 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010377 */
10378
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010379static void
10380xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10381 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010382 CHECK_ERROR;
10383 SKIP_BLANKS;
10384 while ((CUR == '*') ||
10385 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10386 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10387 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010388 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010389
10390 if (CUR == '*') {
10391 op = 0;
10392 NEXT;
10393 } else if (CUR == 'd') {
10394 op = 1;
10395 SKIP(3);
10396 } else if (CUR == 'm') {
10397 op = 2;
10398 SKIP(3);
10399 }
10400 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010401 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010402 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010403 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010404 SKIP_BLANKS;
10405 }
10406}
10407
10408/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010409 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010410 * @ctxt: the XPath Parser context
10411 *
10412 * [25] AdditiveExpr ::= MultiplicativeExpr
10413 * | AdditiveExpr '+' MultiplicativeExpr
10414 * | AdditiveExpr '-' MultiplicativeExpr
10415 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010416 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010417 */
10418
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010419static void
10420xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010421
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010422 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010423 CHECK_ERROR;
10424 SKIP_BLANKS;
10425 while ((CUR == '+') || (CUR == '-')) {
10426 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010427 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010428
10429 if (CUR == '+') plus = 1;
10430 else plus = 0;
10431 NEXT;
10432 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010433 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010434 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010435 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010436 SKIP_BLANKS;
10437 }
10438}
10439
10440/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010441 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010442 * @ctxt: the XPath Parser context
10443 *
10444 * [24] RelationalExpr ::= AdditiveExpr
10445 * | RelationalExpr '<' AdditiveExpr
10446 * | RelationalExpr '>' AdditiveExpr
10447 * | RelationalExpr '<=' AdditiveExpr
10448 * | RelationalExpr '>=' AdditiveExpr
10449 *
10450 * A <= B > C is allowed ? Answer from James, yes with
10451 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10452 * which is basically what got implemented.
10453 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010454 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +000010455 * on the stack
10456 */
10457
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010458static void
10459xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10460 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010461 CHECK_ERROR;
10462 SKIP_BLANKS;
10463 while ((CUR == '<') ||
10464 (CUR == '>') ||
10465 ((CUR == '<') && (NXT(1) == '=')) ||
10466 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010467 int inf, strict;
10468 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010469
10470 if (CUR == '<') inf = 1;
10471 else inf = 0;
10472 if (NXT(1) == '=') strict = 0;
10473 else strict = 1;
10474 NEXT;
10475 if (!strict) NEXT;
10476 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010477 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010478 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010479 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +000010480 SKIP_BLANKS;
10481 }
10482}
10483
10484/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010485 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010486 * @ctxt: the XPath Parser context
10487 *
10488 * [23] EqualityExpr ::= RelationalExpr
10489 * | EqualityExpr '=' RelationalExpr
10490 * | EqualityExpr '!=' RelationalExpr
10491 *
10492 * A != B != C is allowed ? Answer from James, yes with
10493 * (RelationalExpr = RelationalExpr) = RelationalExpr
10494 * (RelationalExpr != RelationalExpr) != RelationalExpr
10495 * which is basically what got implemented.
10496 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010497 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010498 *
10499 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010500static void
10501xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10502 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010503 CHECK_ERROR;
10504 SKIP_BLANKS;
10505 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010506 int eq;
10507 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010508
10509 if (CUR == '=') eq = 1;
10510 else eq = 0;
10511 NEXT;
10512 if (!eq) NEXT;
10513 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010514 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010515 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010516 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010517 SKIP_BLANKS;
10518 }
10519}
10520
10521/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010522 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010523 * @ctxt: the XPath Parser context
10524 *
10525 * [22] AndExpr ::= EqualityExpr
10526 * | AndExpr 'and' EqualityExpr
10527 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010528 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +000010529 *
10530 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010531static void
10532xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10533 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010534 CHECK_ERROR;
10535 SKIP_BLANKS;
10536 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010537 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010538 SKIP(3);
10539 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010540 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010541 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010542 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010543 SKIP_BLANKS;
10544 }
10545}
10546
10547/**
Daniel Veillard591b4be2003-02-09 23:33:36 +000010548 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +000010549 * @ctxt: the XPath Parser context
10550 *
10551 * [14] Expr ::= OrExpr
10552 * [21] OrExpr ::= AndExpr
10553 * | OrExpr 'or' AndExpr
10554 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010555 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +000010556 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010557static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010558xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010559 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010560 CHECK_ERROR;
10561 SKIP_BLANKS;
10562 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010563 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010564 SKIP(2);
10565 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010566 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000010567 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010568 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10569 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +000010570 SKIP_BLANKS;
10571 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010572 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010573 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010574 /*
10575 * This is the main place to eliminate sorting for
10576 * operations which don't require a sorted node-set.
10577 * E.g. count().
10578 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010579 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10580 }
Owen Taylor3473f882001-02-23 17:55:21 +000010581}
10582
10583/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010584 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +000010585 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010586 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +000010587 *
10588 * [8] Predicate ::= '[' PredicateExpr ']'
10589 * [9] PredicateExpr ::= Expr
10590 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010591 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +000010592 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010593static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010594xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010595 int op1 = ctxt->comp->last;
10596
10597 SKIP_BLANKS;
10598 if (CUR != '[') {
10599 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10600 }
10601 NEXT;
10602 SKIP_BLANKS;
10603
10604 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010605 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010606 CHECK_ERROR;
10607
10608 if (CUR != ']') {
10609 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10610 }
10611
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010612 if (filter)
10613 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10614 else
10615 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010616
10617 NEXT;
10618 SKIP_BLANKS;
10619}
10620
10621/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010622 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +000010623 * @ctxt: the XPath Parser context
10624 * @test: pointer to a xmlXPathTestVal
10625 * @type: pointer to a xmlXPathTypeVal
10626 * @prefix: placeholder for a possible name prefix
10627 *
10628 * [7] NodeTest ::= NameTest
10629 * | NodeType '(' ')'
10630 * | 'processing-instruction' '(' Literal ')'
10631 *
10632 * [37] NameTest ::= '*'
10633 * | NCName ':' '*'
10634 * | QName
10635 * [38] NodeType ::= 'comment'
10636 * | 'text'
10637 * | 'processing-instruction'
10638 * | 'node'
10639 *
William M. Brack08171912003-12-29 02:52:11 +000010640 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +000010641 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010642static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010643xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10644 xmlXPathTypeVal *type, const xmlChar **prefix,
10645 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +000010646 int blanks;
10647
10648 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10649 STRANGE;
10650 return(NULL);
10651 }
William M. Brack78637da2003-07-31 14:47:38 +000010652 *type = (xmlXPathTypeVal) 0;
10653 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010654 *prefix = NULL;
10655 SKIP_BLANKS;
10656
10657 if ((name == NULL) && (CUR == '*')) {
10658 /*
10659 * All elements
10660 */
10661 NEXT;
10662 *test = NODE_TEST_ALL;
10663 return(NULL);
10664 }
10665
10666 if (name == NULL)
10667 name = xmlXPathParseNCName(ctxt);
10668 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010669 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010670 }
10671
William M. Brack76e95df2003-10-18 16:20:14 +000010672 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +000010673 SKIP_BLANKS;
10674 if (CUR == '(') {
10675 NEXT;
10676 /*
10677 * NodeType or PI search
10678 */
10679 if (xmlStrEqual(name, BAD_CAST "comment"))
10680 *type = NODE_TYPE_COMMENT;
10681 else if (xmlStrEqual(name, BAD_CAST "node"))
10682 *type = NODE_TYPE_NODE;
10683 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10684 *type = NODE_TYPE_PI;
10685 else if (xmlStrEqual(name, BAD_CAST "text"))
10686 *type = NODE_TYPE_TEXT;
10687 else {
10688 if (name != NULL)
10689 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010690 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010691 }
10692
10693 *test = NODE_TEST_TYPE;
10694
10695 SKIP_BLANKS;
10696 if (*type == NODE_TYPE_PI) {
10697 /*
10698 * Specific case: search a PI by name.
10699 */
Owen Taylor3473f882001-02-23 17:55:21 +000010700 if (name != NULL)
10701 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +000010702 name = NULL;
10703 if (CUR != ')') {
10704 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000010705 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +000010706 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +000010707 SKIP_BLANKS;
10708 }
Owen Taylor3473f882001-02-23 17:55:21 +000010709 }
10710 if (CUR != ')') {
10711 if (name != NULL)
10712 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +000010713 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010714 }
10715 NEXT;
10716 return(name);
10717 }
10718 *test = NODE_TEST_NAME;
10719 if ((!blanks) && (CUR == ':')) {
10720 NEXT;
10721
10722 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010723 * Since currently the parser context don't have a
10724 * namespace list associated:
10725 * The namespace name for this prefix can be computed
10726 * only at evaluation time. The compilation is done
10727 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +000010728 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010729#if 0
Owen Taylor3473f882001-02-23 17:55:21 +000010730 *prefix = xmlXPathNsLookup(ctxt->context, name);
10731 if (name != NULL)
10732 xmlFree(name);
10733 if (*prefix == NULL) {
10734 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10735 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010736#else
10737 *prefix = name;
10738#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010739
10740 if (CUR == '*') {
10741 /*
10742 * All elements
10743 */
10744 NEXT;
10745 *test = NODE_TEST_ALL;
10746 return(NULL);
10747 }
10748
10749 name = xmlXPathParseNCName(ctxt);
10750 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +000010751 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +000010752 }
10753 }
10754 return(name);
10755}
10756
10757/**
10758 * xmlXPathIsAxisName:
10759 * @name: a preparsed name token
10760 *
10761 * [6] AxisName ::= 'ancestor'
10762 * | 'ancestor-or-self'
10763 * | 'attribute'
10764 * | 'child'
10765 * | 'descendant'
10766 * | 'descendant-or-self'
10767 * | 'following'
10768 * | 'following-sibling'
10769 * | 'namespace'
10770 * | 'parent'
10771 * | 'preceding'
10772 * | 'preceding-sibling'
10773 * | 'self'
10774 *
10775 * Returns the axis or 0
10776 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +000010777static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +000010778xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +000010779 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +000010780 switch (name[0]) {
10781 case 'a':
10782 if (xmlStrEqual(name, BAD_CAST "ancestor"))
10783 ret = AXIS_ANCESTOR;
10784 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10785 ret = AXIS_ANCESTOR_OR_SELF;
10786 if (xmlStrEqual(name, BAD_CAST "attribute"))
10787 ret = AXIS_ATTRIBUTE;
10788 break;
10789 case 'c':
10790 if (xmlStrEqual(name, BAD_CAST "child"))
10791 ret = AXIS_CHILD;
10792 break;
10793 case 'd':
10794 if (xmlStrEqual(name, BAD_CAST "descendant"))
10795 ret = AXIS_DESCENDANT;
10796 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10797 ret = AXIS_DESCENDANT_OR_SELF;
10798 break;
10799 case 'f':
10800 if (xmlStrEqual(name, BAD_CAST "following"))
10801 ret = AXIS_FOLLOWING;
10802 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10803 ret = AXIS_FOLLOWING_SIBLING;
10804 break;
10805 case 'n':
10806 if (xmlStrEqual(name, BAD_CAST "namespace"))
10807 ret = AXIS_NAMESPACE;
10808 break;
10809 case 'p':
10810 if (xmlStrEqual(name, BAD_CAST "parent"))
10811 ret = AXIS_PARENT;
10812 if (xmlStrEqual(name, BAD_CAST "preceding"))
10813 ret = AXIS_PRECEDING;
10814 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10815 ret = AXIS_PRECEDING_SIBLING;
10816 break;
10817 case 's':
10818 if (xmlStrEqual(name, BAD_CAST "self"))
10819 ret = AXIS_SELF;
10820 break;
10821 }
10822 return(ret);
10823}
10824
10825/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010826 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +000010827 * @ctxt: the XPath Parser context
10828 *
10829 * [4] Step ::= AxisSpecifier NodeTest Predicate*
10830 * | AbbreviatedStep
10831 *
10832 * [12] AbbreviatedStep ::= '.' | '..'
10833 *
10834 * [5] AxisSpecifier ::= AxisName '::'
10835 * | AbbreviatedAxisSpecifier
10836 *
10837 * [13] AbbreviatedAxisSpecifier ::= '@'?
10838 *
10839 * Modified for XPtr range support as:
10840 *
10841 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10842 * | AbbreviatedStep
10843 * | 'range-to' '(' Expr ')' Predicate*
10844 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010845 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +000010846 * A location step of . is short for self::node(). This is
10847 * particularly useful in conjunction with //. For example, the
10848 * location path .//para is short for
10849 * self::node()/descendant-or-self::node()/child::para
10850 * and so will select all para descendant elements of the context
10851 * node.
10852 * Similarly, a location step of .. is short for parent::node().
10853 * For example, ../title is short for parent::node()/child::title
10854 * and so will select the title children of the parent of the context
10855 * node.
10856 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010857static void
10858xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010859#ifdef LIBXML_XPTR_ENABLED
10860 int rangeto = 0;
10861 int op2 = -1;
10862#endif
10863
Owen Taylor3473f882001-02-23 17:55:21 +000010864 SKIP_BLANKS;
10865 if ((CUR == '.') && (NXT(1) == '.')) {
10866 SKIP(2);
10867 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010868 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10869 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000010870 } else if (CUR == '.') {
10871 NEXT;
10872 SKIP_BLANKS;
10873 } else {
10874 xmlChar *name = NULL;
10875 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010876 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +000010877 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +000010878 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010879 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +000010880
10881 /*
10882 * The modification needed for XPointer change to the production
10883 */
10884#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010885 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +000010886 name = xmlXPathParseNCName(ctxt);
10887 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010888 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +000010889 xmlFree(name);
10890 SKIP_BLANKS;
10891 if (CUR != '(') {
10892 XP_ERROR(XPATH_EXPR_ERROR);
10893 }
10894 NEXT;
10895 SKIP_BLANKS;
10896
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010897 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010898 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +000010899 CHECK_ERROR;
10900
10901 SKIP_BLANKS;
10902 if (CUR != ')') {
10903 XP_ERROR(XPATH_EXPR_ERROR);
10904 }
10905 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010906 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000010907 goto eval_predicates;
10908 }
10909 }
10910#endif
Daniel Veillard2156a562001-04-28 12:24:34 +000010911 if (CUR == '*') {
10912 axis = AXIS_CHILD;
10913 } else {
10914 if (name == NULL)
10915 name = xmlXPathParseNCName(ctxt);
10916 if (name != NULL) {
10917 axis = xmlXPathIsAxisName(name);
10918 if (axis != 0) {
10919 SKIP_BLANKS;
10920 if ((CUR == ':') && (NXT(1) == ':')) {
10921 SKIP(2);
10922 xmlFree(name);
10923 name = NULL;
10924 } else {
10925 /* an element name can conflict with an axis one :-\ */
10926 axis = AXIS_CHILD;
10927 }
Owen Taylor3473f882001-02-23 17:55:21 +000010928 } else {
Owen Taylor3473f882001-02-23 17:55:21 +000010929 axis = AXIS_CHILD;
10930 }
Daniel Veillard2156a562001-04-28 12:24:34 +000010931 } else if (CUR == '@') {
10932 NEXT;
10933 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +000010934 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +000010935 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +000010936 }
Owen Taylor3473f882001-02-23 17:55:21 +000010937 }
10938
10939 CHECK_ERROR;
10940
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010941 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +000010942 if (test == 0)
10943 return;
10944
Daniel Veillarded6c5492005-07-23 15:00:22 +000010945 if ((prefix != NULL) && (ctxt->context != NULL) &&
10946 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10947 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10948 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10949 }
10950 }
Owen Taylor3473f882001-02-23 17:55:21 +000010951#ifdef DEBUG_STEP
10952 xmlGenericError(xmlGenericErrorContext,
10953 "Basis : computing new set\n");
10954#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010955
Owen Taylor3473f882001-02-23 17:55:21 +000010956#ifdef DEBUG_STEP
10957 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010958 if (ctxt->value == NULL)
10959 xmlGenericError(xmlGenericErrorContext, "no value\n");
10960 else if (ctxt->value->nodesetval == NULL)
10961 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10962 else
10963 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010964#endif
Owen Taylor3473f882001-02-23 17:55:21 +000010965
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010966#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000010967eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +000010968#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010969 op1 = ctxt->comp->last;
10970 ctxt->comp->last = -1;
10971
Owen Taylor3473f882001-02-23 17:55:21 +000010972 SKIP_BLANKS;
10973 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010974 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +000010975 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010976
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010977#ifdef LIBXML_XPTR_ENABLED
10978 if (rangeto) {
10979 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10980 } else
10981#endif
10982 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10983 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010984
Owen Taylor3473f882001-02-23 17:55:21 +000010985 }
10986#ifdef DEBUG_STEP
10987 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +000010988 if (ctxt->value == NULL)
10989 xmlGenericError(xmlGenericErrorContext, "no value\n");
10990 else if (ctxt->value->nodesetval == NULL)
10991 xmlGenericError(xmlGenericErrorContext, "Empty\n");
10992 else
10993 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
10994 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +000010995#endif
10996}
10997
10998/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010999 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011000 * @ctxt: the XPath Parser context
11001 *
11002 * [3] RelativeLocationPath ::= Step
11003 * | RelativeLocationPath '/' Step
11004 * | AbbreviatedRelativeLocationPath
11005 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11006 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011007 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +000011008 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011009static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011010xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +000011011(xmlXPathParserContextPtr ctxt) {
11012 SKIP_BLANKS;
11013 if ((CUR == '/') && (NXT(1) == '/')) {
11014 SKIP(2);
11015 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011016 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11017 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011018 } else if (CUR == '/') {
11019 NEXT;
11020 SKIP_BLANKS;
11021 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011022 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011023 SKIP_BLANKS;
11024 while (CUR == '/') {
11025 if ((CUR == '/') && (NXT(1) == '/')) {
11026 SKIP(2);
11027 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011028 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +000011029 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011030 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011031 } else if (CUR == '/') {
11032 NEXT;
11033 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011034 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011035 }
11036 SKIP_BLANKS;
11037 }
11038}
11039
11040/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011041 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +000011042 * @ctxt: the XPath Parser context
11043 *
11044 * [1] LocationPath ::= RelativeLocationPath
11045 * | AbsoluteLocationPath
11046 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11047 * | AbbreviatedAbsoluteLocationPath
11048 * [10] AbbreviatedAbsoluteLocationPath ::=
11049 * '//' RelativeLocationPath
11050 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011051 * Compile a location path
11052 *
Owen Taylor3473f882001-02-23 17:55:21 +000011053 * // is short for /descendant-or-self::node()/. For example,
11054 * //para is short for /descendant-or-self::node()/child::para and
11055 * so will select any para element in the document (even a para element
11056 * that is a document element will be selected by //para since the
11057 * document element node is a child of the root node); div//para is
11058 * short for div/descendant-or-self::node()/child::para and so will
11059 * select all para descendants of div children.
11060 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011061static void
11062xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +000011063 SKIP_BLANKS;
11064 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011065 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011066 } else {
11067 while (CUR == '/') {
11068 if ((CUR == '/') && (NXT(1) == '/')) {
11069 SKIP(2);
11070 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011071 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11072 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011073 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011074 } else if (CUR == '/') {
11075 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +000011076 SKIP_BLANKS;
11077 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +000011078 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +000011079 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011080 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011081 }
11082 }
11083 }
11084}
11085
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011086/************************************************************************
11087 * *
11088 * XPath precompiled expression evaluation *
11089 * *
11090 ************************************************************************/
11091
Daniel Veillardf06307e2001-07-03 10:35:50 +000011092static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011093xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11094
11095/**
11096 * xmlXPathNodeCollectAndTest:
11097 * @ctxt: the XPath Parser context
11098 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +000011099 * @first: pointer to the first element in document order
11100 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011101 *
11102 * This is the function implementing a step: based on the current list
11103 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000011104 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011105 *
11106 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +000011107 *
William M. Brack08171912003-12-29 02:52:11 +000011108 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011109 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011110static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011111xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011112 xmlXPathStepOpPtr op,
11113 xmlNodePtr * first, xmlNodePtr * last)
11114{
William M. Brack78637da2003-07-31 14:47:38 +000011115 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11116 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11117 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011118 const xmlChar *prefix = op->value4;
11119 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +000011120 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011121
11122#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011123 int nbMatches = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011124#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011125 int inputIdx, total = 0, specialNodeInSet = 0;
11126 xmlNodeSetPtr inputList, resultList, list;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011127 xmlXPathTraversalFunction next = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011128 xmlXPathTraversalFunctionExt compoundNext = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011129 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +000011130 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011131 xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011132 xmlXPathObjectPtr obj;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011133 xmlXPathContextPtr xpctxt = ctxt->context;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011134
Daniel Veillardf06307e2001-07-03 10:35:50 +000011135 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011136 obj = valuePop(ctxt);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011137
11138 /*
11139 * Setup wrt namespaces.
11140 */
Daniel Veillarde043ee12001-04-16 14:08:07 +000011141 if (prefix != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011142 URI = xmlXPathNsLookup(xpctxt, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011143 if (URI == NULL) {
11144 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011145 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011146 }
Daniel Veillarde043ee12001-04-16 14:08:07 +000011147 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011148
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011149#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011150 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011151#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011152
11153 /*
11154 * Setup wrt the axis.
11155 */
11156 addNode = xmlXPathNodeSetAdd;
11157 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011158 switch (axis) {
11159 case AXIS_ANCESTOR:
11160#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011161 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011162#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011163 first = NULL;
11164 next = xmlXPathNextAncestor;
11165 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011166 case AXIS_ANCESTOR_OR_SELF:
11167#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011168 xmlGenericError(xmlGenericErrorContext,
11169 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011170#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011171 first = NULL;
11172 next = xmlXPathNextAncestorOrSelf;
11173 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011174 case AXIS_ATTRIBUTE:
11175#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011176 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011177#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011178 first = NULL;
11179 last = NULL;
11180 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +000011181 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011182 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011183 case AXIS_CHILD:
11184#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011185 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011186#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011187 last = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011188 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11189 /*
11190 * This iterator will give us only nodes which can
11191 * hold element nodes.
11192 */
11193 compoundNext = xmlXPathNextDescendantOrSelfElemParent;
11194 }
11195 if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011196 /*
11197 * Optimization if an element node type is 'element'.
11198 */
11199 next = xmlXPathNextChildElement;
11200 } else
11201 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +000011202 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011203 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011204 case AXIS_DESCENDANT:
11205#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011206 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011207#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011208 last = NULL;
11209 next = xmlXPathNextDescendant;
11210 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011211 case AXIS_DESCENDANT_OR_SELF:
11212#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011213 xmlGenericError(xmlGenericErrorContext,
11214 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011215#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011216 last = NULL;
11217 next = xmlXPathNextDescendantOrSelf;
11218 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011219 case AXIS_FOLLOWING:
11220#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011221 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011222#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011223 last = NULL;
11224 next = xmlXPathNextFollowing;
11225 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011226 case AXIS_FOLLOWING_SIBLING:
11227#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011228 xmlGenericError(xmlGenericErrorContext,
11229 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011230#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011231 last = NULL;
11232 next = xmlXPathNextFollowingSibling;
11233 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011234 case AXIS_NAMESPACE:
11235#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011236 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011237#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011238 first = NULL;
11239 last = NULL;
11240 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +000011241 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011242 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011243 case AXIS_PARENT:
11244#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011245 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011246#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011247 first = NULL;
11248 next = xmlXPathNextParent;
11249 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011250 case AXIS_PRECEDING:
11251#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011252 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011253#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011254 first = NULL;
11255 next = xmlXPathNextPrecedingInternal;
11256 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011257 case AXIS_PRECEDING_SIBLING:
11258#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011259 xmlGenericError(xmlGenericErrorContext,
11260 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011261#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011262 first = NULL;
11263 next = xmlXPathNextPrecedingSibling;
11264 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011265 case AXIS_SELF:
11266#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +000011267 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011268#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011269 first = NULL;
11270 last = NULL;
11271 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +000011272 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011273 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011274 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011275 if (next == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011276 xmlXPathReleaseObject(xpctxt, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011277 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011278 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011279
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011280 inputList = obj->nodesetval;
11281 if ((inputList == NULL) || (inputList->nodeNr <= 0)) {
11282 xmlXPathReleaseObject(xpctxt, obj);
11283 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011284 return(0);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011285 }
11286
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011287#ifdef DEBUG_STEP
11288 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011289 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011290 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011291 case NODE_TEST_NONE:
11292 xmlGenericError(xmlGenericErrorContext,
11293 " searching for none !!!\n");
11294 break;
11295 case NODE_TEST_TYPE:
11296 xmlGenericError(xmlGenericErrorContext,
11297 " searching for type %d\n", type);
11298 break;
11299 case NODE_TEST_PI:
11300 xmlGenericError(xmlGenericErrorContext,
11301 " searching for PI !!!\n");
11302 break;
11303 case NODE_TEST_ALL:
11304 xmlGenericError(xmlGenericErrorContext,
11305 " searching for *\n");
11306 break;
11307 case NODE_TEST_NS:
11308 xmlGenericError(xmlGenericErrorContext,
11309 " searching for namespace %s\n",
11310 prefix);
11311 break;
11312 case NODE_TEST_NAME:
11313 xmlGenericError(xmlGenericErrorContext,
11314 " searching for name %s\n", name);
11315 if (prefix != NULL)
11316 xmlGenericError(xmlGenericErrorContext,
11317 " with namespace %s\n", prefix);
11318 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011319 }
11320 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11321#endif
11322 /*
11323 * 2.3 Node Tests
11324 * - For the attribute axis, the principal node type is attribute.
11325 * - For the namespace axis, the principal node type is namespace.
11326 * - For other axes, the principal node type is element.
11327 *
11328 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011329 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011330 * select all element children of the context node
11331 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011332 oldContextNode = xpctxt->node;
11333 addNode = xmlXPathNodeSetAddUnique;
11334 resultList = NULL;
11335 list = NULL;
11336 compoundContextNode = NULL;
11337 contextNode = NULL;
11338 inputIdx = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011339
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011340 while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) {
11341 if (compoundNext != NULL) {
11342 /*
11343 * This is a compound traversal.
11344 */
11345 if (contextNode == NULL) {
11346 /*
11347 * Set the context for the initial traversal.
11348 */
11349 compoundContextNode = inputList->nodeTab[inputIdx++];
11350 contextNode = compoundNext(NULL, compoundContextNode);
11351 } else
11352 contextNode = compoundNext(contextNode, compoundContextNode);
11353 if (contextNode == NULL)
11354 continue;
11355 /*
11356 * Set the context for the main traversal.
11357 */
11358 xpctxt->node = contextNode;
11359 } else
11360 xpctxt->node = inputList->nodeTab[inputIdx++];
11361
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011362 if (list == NULL) {
11363 list = xmlXPathNodeSetCreate(NULL);
11364 if (list == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011365 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011366 goto error;
11367 }
11368 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011369 cur = NULL;
11370 specialNodeInSet = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011371 do {
11372 cur = next(ctxt, cur);
11373 if (cur == NULL)
11374 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011375
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011376 if (first != NULL) {
11377 if (*first == cur)
11378 break;
11379 if ((*first != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011380 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011381#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011382 (xmlXPathCmpNodesExt(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011383#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011384 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011385#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011386 {
11387 break;
11388 }
11389 }
11390 if (last != NULL) {
11391 if (*last == cur)
11392 break;
11393 if ((*last != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011394 ((total % 256) == 0) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011395#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011396 (xmlXPathCmpNodesExt(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011397#else
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011398 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011399#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011400 {
11401 break;
11402 }
11403 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011404
11405 total++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011406#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011407 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
11408#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011409 switch (test) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011410 case NODE_TEST_NONE:
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011411 STRANGE
11412 goto error;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011413 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011414 if ((cur->type == type) ||
11415 ((type == NODE_TYPE_NODE) &&
11416 ((cur->type == XML_DOCUMENT_NODE) ||
11417 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11418 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +000011419 (cur->type == XML_NAMESPACE_DECL) ||
11420 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +000011421 (cur->type == XML_PI_NODE) ||
11422 (cur->type == XML_COMMENT_NODE) ||
11423 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +000011424 (cur->type == XML_TEXT_NODE))) ||
11425 ((type == NODE_TYPE_TEXT) &&
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011426 (cur->type == XML_CDATA_SECTION_NODE)))
11427 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011428#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011429 nbMatches++;
11430#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011431 if (cur->type == XML_NAMESPACE_DECL)
11432 specialNodeInSet = 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011433 /*
11434 * TODO: Don't we need to use xmlXPathNodeSetAddNs()
11435 * for namespace nodes here ?
11436 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011437 addNode(list, cur);
11438 }
11439 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011440 case NODE_TEST_PI:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011441 if ((cur->type == XML_PI_NODE) &&
11442 ((name == NULL) || xmlStrEqual(name, cur->name)))
11443 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011444#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011445 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011446#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011447 addNode(list, cur);
11448 }
11449 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011450 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011451 if (axis == AXIS_ATTRIBUTE) {
11452 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011453#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011454 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011455#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011456 addNode(list, cur);
11457 }
11458 } else if (axis == AXIS_NAMESPACE) {
11459 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011460#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011461 nbMatches++;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011462#endif
11463 specialNodeInSet = 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011464 xmlXPathNodeSetAddNs(list, xpctxt->node,
11465 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011466 }
11467 } else {
11468 if (cur->type == XML_ELEMENT_NODE) {
11469 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011470#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011471 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011472#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011473 addNode(list, cur);
11474 } else if ((cur->ns != NULL) &&
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011475 (xmlStrEqual(URI, cur->ns->href)))
11476 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011477#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011478 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011479#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011480 addNode(list, cur);
11481 }
11482 }
11483 }
11484 break;
11485 case NODE_TEST_NS:{
11486 TODO;
11487 break;
11488 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011489 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +000011490 switch (cur->type) {
11491 case XML_ELEMENT_NODE:
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011492 if (xmlStrEqual(name, cur->name)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011493 if (prefix == NULL) {
11494 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011495#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011496 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011497#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011498 addNode(list, cur);
11499 }
11500 } else {
11501 if ((cur->ns != NULL) &&
11502 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011503 cur->ns->href)))
11504 {
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011505#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011506 nbMatches++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011507#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000011508 addNode(list, cur);
11509 }
11510 }
11511 }
11512 break;
11513 case XML_ATTRIBUTE_NODE:{
11514 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011515
Daniel Veillardf06307e2001-07-03 10:35:50 +000011516 if (xmlStrEqual(name, attr->name)) {
11517 if (prefix == NULL) {
11518 if ((attr->ns == NULL) ||
11519 (attr->ns->prefix == NULL)) {
11520#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011521 nbMatches++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011522#endif
11523 addNode(list,
11524 (xmlNodePtr) attr);
11525 }
11526 } else {
11527 if ((attr->ns != NULL) &&
11528 (xmlStrEqual(URI,
11529 attr->ns->
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011530 href)))
11531 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011532#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011533 nbMatches++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011534#endif
11535 addNode(list,
11536 (xmlNodePtr) attr);
11537 }
11538 }
11539 }
11540 break;
11541 }
11542 case XML_NAMESPACE_DECL:
11543 if (cur->type == XML_NAMESPACE_DECL) {
11544 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011545
Daniel Veillardf06307e2001-07-03 10:35:50 +000011546 if ((ns->prefix != NULL) && (name != NULL)
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011547 && (xmlStrEqual(ns->prefix, name)))
11548 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011549#ifdef DEBUG_STEP
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011550 nbMatches++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011551#endif
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011552 specialNodeInSet = 1;
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011553 xmlXPathNodeSetAddNs(list,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011554 xpctxt->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011555 }
11556 }
11557 break;
11558 default:
11559 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011560 } /* switch (cur->type) */
11561 break; /* case NODE_TEST_NAME: */
11562 } /* switch (test) */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011563 } while (cur != NULL);
11564
11565 /*
11566 * If there is some predicate filtering do it now
11567 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011568 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011569 xmlXPathObjectPtr obj2;
11570
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011571 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011572 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
11573 CHECK_TYPE0(XPATH_NODESET);
11574 obj2 = valuePop(ctxt);
11575 list = obj2->nodesetval;
11576 obj2->nodesetval = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011577 xmlXPathReleaseObject(xpctxt, obj2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011578
William M. Brack2c19a7b2005-04-10 01:03:23 +000011579 if (ctxt->error != XPATH_EXPRESSION_OK) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011580 total = 0;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011581 goto error;
William M. Brack2c19a7b2005-04-10 01:03:23 +000011582 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011583 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011584 if (resultList == NULL) {
11585 resultList = list;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011586 list = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011587 } else if ((list != NULL) && (list->nodeNr > 0)) {
11588 resultList = mergeNodeSet(resultList, list);
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011589 /*
11590 * This is the list containing the current matching nodes.
11591 * Avoid massive creation/freeing and preserve it for the
11592 * next iterations.
11593 */
11594 /* If a namespace node was put it, then we need a more
11595 * time consuming cleanup.
11596 */
11597 if (specialNodeInSet)
11598 xmlXPathNodeSetClear(list);
11599 else
11600 list->nodeNr = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011601 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011602 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011603
11604 xpctxt->node = oldContextNode;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011605 /*
11606 * Cleanup the temporary list of current node-test matches.
11607 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011608 if ((list != NULL) && (list != resultList)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011609 xmlXPathFreeNodeSet(list);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011610 list = NULL;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011611 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011612
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011613#ifdef DEBUG_STEP
11614 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011615 "\nExamined %d nodes, found %d nodes at that step\n",
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011616 total, nbMatches);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011617#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011618
11619 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, resultList));
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000011620
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011621 if ((obj->boolval) && (obj->user != NULL)) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011622 /*
11623 * QUESTION TODO: What does this do and why?
11624 */
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000011625 ctxt->value->boolval = 1;
11626 ctxt->value->user = obj->user;
11627 obj->user = NULL;
11628 obj->boolval = 0;
11629 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011630 xmlXPathReleaseObject(xpctxt, obj);
11631 return(total);
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011632
11633error:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011634 xpctxt->node = oldContextNode;
11635 xmlXPathReleaseObject(xpctxt, obj);
11636 if ((list != NULL) && (list != resultList)) {
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000011637 xmlXPathFreeNodeSet(list);
11638 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011639 if (resultList != NULL)
11640 xmlXPathFreeNodeSet(resultList);
11641 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011642}
11643
11644/**
11645 * xmlXPathNodeCollectAndTestNth:
11646 * @ctxt: the XPath Parser context
11647 * @op: the XPath precompiled step operation
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011648 * @reqpos: the requested position wrt to the axis
Daniel Veillardf06307e2001-07-03 10:35:50 +000011649 * @first: pointer to the first element in document order
11650 * @last: pointer to the last element in document order
11651 *
11652 * This is the function implementing a step: based on the current list
11653 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +000011654 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +000011655 *
11656 * Pushes the new NodeSet resulting from the search.
11657 * Returns the number of node traversed
11658 */
11659static int
11660xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011661 xmlXPathStepOpPtr op, int reqpos,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011662 xmlNodePtr * first, xmlNodePtr * last)
11663{
William M. Brack78637da2003-07-31 14:47:38 +000011664 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11665 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11666 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011667 const xmlChar *prefix = op->value4;
11668 const xmlChar *name = op->value5;
11669 const xmlChar *URI = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011670 int pos; /* The current context position */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011671
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011672 int inputIdx, total = 0;
11673 xmlNodeSetPtr inputList, list;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011674 xmlXPathTraversalFunction next = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011675 xmlXPathTraversalFunctionExt compoundNext = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011676 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011677 xmlNodePtr oldContextNode, contextNode, cur, compoundContextNode;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011678 xmlXPathObjectPtr obj;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011679 xmlXPathContextPtr xpctxt = ctxt->context;
11680
Daniel Veillardf06307e2001-07-03 10:35:50 +000011681
11682 CHECK_TYPE0(XPATH_NODESET);
11683 obj = valuePop(ctxt);
11684 addNode = xmlXPathNodeSetAdd;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011685
Daniel Veillardf06307e2001-07-03 10:35:50 +000011686 if (prefix != NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011687 URI = xmlXPathNsLookup(xpctxt, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011688 if (URI == NULL) {
11689 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011690 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011691 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011692 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011693
Daniel Veillardf06307e2001-07-03 10:35:50 +000011694#ifdef DEBUG_STEP_NTH
11695 xmlGenericError(xmlGenericErrorContext, "new step : ");
11696 if (first != NULL) {
11697 if (*first != NULL)
11698 xmlGenericError(xmlGenericErrorContext, "first = %s ",
11699 (*first)->name);
11700 else
11701 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
11702 }
11703 if (last != NULL) {
11704 if (*last != NULL)
11705 xmlGenericError(xmlGenericErrorContext, "last = %s ",
11706 (*last)->name);
11707 else
11708 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
11709 }
11710#endif
11711 switch (axis) {
11712 case AXIS_ANCESTOR:
11713#ifdef DEBUG_STEP_NTH
11714 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11715#endif
11716 first = NULL;
11717 next = xmlXPathNextAncestor;
11718 break;
11719 case AXIS_ANCESTOR_OR_SELF:
11720#ifdef DEBUG_STEP_NTH
11721 xmlGenericError(xmlGenericErrorContext,
11722 "axis 'ancestors-or-self' ");
11723#endif
11724 first = NULL;
11725 next = xmlXPathNextAncestorOrSelf;
11726 break;
11727 case AXIS_ATTRIBUTE:
11728#ifdef DEBUG_STEP_NTH
11729 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11730#endif
11731 first = NULL;
11732 last = NULL;
11733 next = xmlXPathNextAttribute;
11734 break;
11735 case AXIS_CHILD:
11736#ifdef DEBUG_STEP_NTH
11737 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11738#endif
11739 last = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011740 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11741 /*
11742 * This iterator will give us only nodes which can
11743 * hold element nodes.
11744 */
11745 compoundNext = xmlXPathNextDescendantOrSelfElemParent;
11746 }
11747 if ((test == NODE_TEST_NAME) && (type == NODE_TYPE_NODE)) {
11748 /*
11749 * Optimization if an element node type is 'element'.
11750 */
11751 next = xmlXPathNextChildElement;
11752 } else
11753 next = xmlXPathNextChild;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011754 break;
11755 case AXIS_DESCENDANT:
11756#ifdef DEBUG_STEP_NTH
11757 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11758#endif
11759 last = NULL;
11760 next = xmlXPathNextDescendant;
11761 break;
11762 case AXIS_DESCENDANT_OR_SELF:
11763#ifdef DEBUG_STEP_NTH
11764 xmlGenericError(xmlGenericErrorContext,
11765 "axis 'descendant-or-self' ");
11766#endif
11767 last = NULL;
11768 next = xmlXPathNextDescendantOrSelf;
11769 break;
11770 case AXIS_FOLLOWING:
11771#ifdef DEBUG_STEP_NTH
11772 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11773#endif
11774 last = NULL;
11775 next = xmlXPathNextFollowing;
11776 break;
11777 case AXIS_FOLLOWING_SIBLING:
11778#ifdef DEBUG_STEP_NTH
11779 xmlGenericError(xmlGenericErrorContext,
11780 "axis 'following-siblings' ");
11781#endif
11782 last = NULL;
11783 next = xmlXPathNextFollowingSibling;
11784 break;
11785 case AXIS_NAMESPACE:
11786#ifdef DEBUG_STEP_NTH
11787 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11788#endif
11789 last = NULL;
11790 first = NULL;
11791 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11792 break;
11793 case AXIS_PARENT:
11794#ifdef DEBUG_STEP_NTH
11795 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11796#endif
11797 first = NULL;
11798 next = xmlXPathNextParent;
11799 break;
11800 case AXIS_PRECEDING:
11801#ifdef DEBUG_STEP_NTH
11802 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11803#endif
11804 first = NULL;
11805 next = xmlXPathNextPrecedingInternal;
11806 break;
11807 case AXIS_PRECEDING_SIBLING:
11808#ifdef DEBUG_STEP_NTH
11809 xmlGenericError(xmlGenericErrorContext,
11810 "axis 'preceding-sibling' ");
11811#endif
11812 first = NULL;
11813 next = xmlXPathNextPrecedingSibling;
11814 break;
11815 case AXIS_SELF:
11816#ifdef DEBUG_STEP_NTH
11817 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11818#endif
11819 first = NULL;
11820 last = NULL;
11821 next = xmlXPathNextSelf;
11822 break;
11823 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000011824 if (next == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011825 xmlXPathReleaseObject(xpctxt, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011826 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011827 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011828
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011829 inputList = obj->nodesetval;
11830 if ((inputList == NULL) || (inputList->nodeNr <= 0)) {
11831 xmlXPathReleaseObject(xpctxt, obj);
11832 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011833 return(0);
11834 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011835
Daniel Veillardf06307e2001-07-03 10:35:50 +000011836#ifdef DEBUG_STEP_NTH
11837 xmlGenericError(xmlGenericErrorContext,
11838 " context contains %d nodes\n", nodelist->nodeNr);
11839 switch (test) {
11840 case NODE_TEST_NONE:
11841 xmlGenericError(xmlGenericErrorContext,
11842 " searching for none !!!\n");
11843 break;
11844 case NODE_TEST_TYPE:
11845 xmlGenericError(xmlGenericErrorContext,
11846 " searching for type %d\n", type);
11847 break;
11848 case NODE_TEST_PI:
11849 xmlGenericError(xmlGenericErrorContext,
11850 " searching for PI !!!\n");
11851 break;
11852 case NODE_TEST_ALL:
11853 xmlGenericError(xmlGenericErrorContext,
11854 " searching for *\n");
11855 break;
11856 case NODE_TEST_NS:
11857 xmlGenericError(xmlGenericErrorContext,
11858 " searching for namespace %s\n",
11859 prefix);
11860 break;
11861 case NODE_TEST_NAME:
11862 xmlGenericError(xmlGenericErrorContext,
11863 " searching for name %s\n", name);
11864 if (prefix != NULL)
11865 xmlGenericError(xmlGenericErrorContext,
11866 " with namespace %s\n", prefix);
11867 break;
11868 }
11869 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11870#endif
11871 /*
11872 * 2.3 Node Tests
11873 * - For the attribute axis, the principal node type is attribute.
11874 * - For the namespace axis, the principal node type is namespace.
11875 * - For other axes, the principal node type is element.
11876 *
11877 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011878 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +000011879 * select all element children of the context node
11880 */
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011881 oldContextNode = xpctxt->node;
11882 addNode = xmlXPathNodeSetAddUnique;
11883 list = NULL;
11884 compoundContextNode = NULL;
11885 contextNode = NULL;
11886 inputIdx = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011887 list = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011888
11889 while ((inputIdx < inputList->nodeNr) || (contextNode != NULL)) {
11890 if (compoundNext != NULL) {
11891 /*
11892 * This is a compound traversal.
11893 */
11894 if (contextNode == NULL) {
11895 /*
11896 * Set the context for the initial traversal.
11897 */
11898 compoundContextNode = inputList->nodeTab[inputIdx++];
11899 contextNode = compoundNext(NULL, compoundContextNode);
11900 } else
11901 contextNode = compoundNext(contextNode, compoundContextNode);
11902 if (contextNode == NULL)
11903 continue;
11904 /*
11905 * Set the context for the main traversal.
11906 */
11907 xpctxt->node = contextNode;
11908 } else
11909 xpctxt->node = inputList->nodeTab[inputIdx++];
Daniel Veillardf06307e2001-07-03 10:35:50 +000011910
11911 cur = NULL;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011912 pos = 0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011913 do {
11914 cur = next(ctxt, cur);
11915 if (cur == NULL)
11916 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011917
11918 if (first != NULL) {
11919 if (*first == cur)
11920 break;
11921 if ((*first != NULL) &&
11922 ((total % 256) == 0) &&
11923#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11924 (xmlXPathCmpNodesExt(*first, cur) >= 0))
11925#else
11926 (xmlXPathCmpNodes(*first, cur) >= 0))
11927#endif
11928 {
11929 break;
11930 }
11931 }
11932 if (last != NULL) {
11933 if (*last == cur)
11934 break;
11935 if ((*last != NULL) &&
11936 ((total % 256) == 0) &&
11937#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11938 (xmlXPathCmpNodesExt(cur, *last) >= 0))
11939#else
11940 (xmlXPathCmpNodes(cur, *last) >= 0))
11941#endif
11942 {
11943 break;
11944 }
11945 }
11946
11947 total++;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011948 switch (test) {
11949 case NODE_TEST_NONE:
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011950 total = 0;
11951 STRANGE
11952 goto error;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011953 case NODE_TEST_TYPE:
11954 if ((cur->type == type) ||
11955 ((type == NODE_TYPE_NODE) &&
11956 ((cur->type == XML_DOCUMENT_NODE) ||
11957 (cur->type == XML_HTML_DOCUMENT_NODE) ||
11958 (cur->type == XML_ELEMENT_NODE) ||
11959 (cur->type == XML_PI_NODE) ||
11960 (cur->type == XML_COMMENT_NODE) ||
11961 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +000011962 (cur->type == XML_TEXT_NODE))) ||
11963 ((type == NODE_TYPE_TEXT) &&
11964 (cur->type == XML_CDATA_SECTION_NODE))) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011965 pos++;
11966 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011967 addNode(list, cur);
11968 }
11969 break;
11970 case NODE_TEST_PI:
11971 if (cur->type == XML_PI_NODE) {
11972 if ((name != NULL) &&
11973 (!xmlStrEqual(name, cur->name)))
11974 break;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011975 pos++;
11976 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011977 addNode(list, cur);
11978 }
11979 break;
11980 case NODE_TEST_ALL:
11981 if (axis == AXIS_ATTRIBUTE) {
11982 if (cur->type == XML_ATTRIBUTE_NODE) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011983 pos++;
11984 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011985 addNode(list, cur);
11986 }
11987 } else if (axis == AXIS_NAMESPACE) {
11988 if (cur->type == XML_NAMESPACE_DECL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011989 pos++;
11990 if (pos == reqpos)
11991 xmlXPathNodeSetAddNs(list, xpctxt->node,
Daniel Veillard044fc6b2002-03-04 17:09:44 +000011992 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011993 }
11994 } else {
11995 if (cur->type == XML_ELEMENT_NODE) {
11996 if (prefix == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000011997 pos++;
11998 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000011999 addNode(list, cur);
12000 } else if ((cur->ns != NULL) &&
12001 (xmlStrEqual(URI, cur->ns->href))) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012002 pos++;
12003 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012004 addNode(list, cur);
12005 }
12006 }
12007 }
12008 break;
12009 case NODE_TEST_NS:{
12010 TODO;
12011 break;
12012 }
12013 case NODE_TEST_NAME:
12014 switch (cur->type) {
12015 case XML_ELEMENT_NODE:
12016 if (xmlStrEqual(name, cur->name)) {
12017 if (prefix == NULL) {
12018 if (cur->ns == NULL) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012019 pos++;
12020 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012021 addNode(list, cur);
12022 }
12023 } else {
12024 if ((cur->ns != NULL) &&
12025 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012026 cur->ns->href)))
12027 {
12028 pos++;
12029 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012030 addNode(list, cur);
12031 }
12032 }
12033 }
12034 break;
12035 case XML_ATTRIBUTE_NODE:{
12036 xmlAttrPtr attr = (xmlAttrPtr) cur;
12037
12038 if (xmlStrEqual(name, attr->name)) {
12039 if (prefix == NULL) {
12040 if ((attr->ns == NULL) ||
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012041 (attr->ns->prefix == NULL))
12042 {
12043 pos++;
12044 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012045 addNode(list, cur);
12046 }
12047 } else {
12048 if ((attr->ns != NULL) &&
12049 (xmlStrEqual(URI,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012050 attr->ns->href)))
12051 {
12052 pos++;
12053 if (pos == reqpos)
Daniel Veillardf06307e2001-07-03 10:35:50 +000012054 addNode(list, cur);
12055 }
12056 }
12057 }
12058 break;
12059 }
12060 case XML_NAMESPACE_DECL:
12061 if (cur->type == XML_NAMESPACE_DECL) {
12062 xmlNsPtr ns = (xmlNsPtr) cur;
12063
12064 if ((ns->prefix != NULL) && (name != NULL)
12065 && (xmlStrEqual(ns->prefix, name))) {
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012066 pos++;
12067 if (pos == reqpos)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000012068 xmlXPathNodeSetAddNs(list,
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012069 xpctxt->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012070 }
12071 }
12072 break;
12073 default:
12074 break;
12075 }
12076 break;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012077 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012078 } while (pos < reqpos);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012079 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012080 xpctxt->node = oldContextNode;
12081
Daniel Veillardf06307e2001-07-03 10:35:50 +000012082#ifdef DEBUG_STEP_NTH
12083 xmlGenericError(xmlGenericErrorContext,
12084 "\nExamined %d nodes, found %d nodes at that step\n",
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012085 total, list->nodeNr);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012086#endif
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012087
12088 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, list));
12089
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000012090 if ((obj->boolval) && (obj->user != NULL)) {
12091 ctxt->value->boolval = 1;
12092 ctxt->value->user = obj->user;
12093 obj->user = NULL;
12094 obj->boolval = 0;
12095 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012096 xmlXPathReleaseObject(xpctxt, obj);
12097 return(total);
12098
12099error:
12100 xpctxt->node = oldContextNode;
12101 xmlXPathReleaseObject(xpctxt, obj);
12102 if (list != NULL)
12103 xmlXPathFreeNodeSet(list);
12104 return(total);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012105}
12106
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012107static int
12108xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12109 xmlXPathStepOpPtr op, xmlNodePtr * first);
12110
Daniel Veillardf06307e2001-07-03 10:35:50 +000012111/**
12112 * xmlXPathCompOpEvalFirst:
12113 * @ctxt: the XPath parser context with the compiled expression
12114 * @op: an XPath compiled operation
12115 * @first: the first elem found so far
12116 *
12117 * Evaluate the Precompiled XPath operation searching only the first
12118 * element in document order
12119 *
12120 * Returns the number of examined objects.
12121 */
12122static int
12123xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12124 xmlXPathStepOpPtr op, xmlNodePtr * first)
12125{
12126 int total = 0, cur;
12127 xmlXPathCompExprPtr comp;
12128 xmlXPathObjectPtr arg1, arg2;
12129
Daniel Veillard556c6682001-10-06 09:59:51 +000012130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012131 comp = ctxt->comp;
12132 switch (op->op) {
12133 case XPATH_OP_END:
12134 return (0);
12135 case XPATH_OP_UNION:
12136 total =
12137 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12138 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012140 if ((ctxt->value != NULL)
12141 && (ctxt->value->type == XPATH_NODESET)
12142 && (ctxt->value->nodesetval != NULL)
12143 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12144 /*
12145 * limit tree traversing to first node in the result
12146 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012147 /*
12148 * OPTIMIZE TODO: This implicitely sorts
12149 * the result, even if not needed. E.g. if the argument
12150 * of the count() function, no sorting is needed.
12151 * OPTIMIZE TODO: How do we know if the node-list wasn't
12152 * aready sorted?
12153 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012154 if (ctxt->value->nodesetval->nodeNr > 1)
12155 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012156 *first = ctxt->value->nodesetval->nodeTab[0];
12157 }
12158 cur =
12159 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12160 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012161 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012162 CHECK_TYPE0(XPATH_NODESET);
12163 arg2 = valuePop(ctxt);
12164
12165 CHECK_TYPE0(XPATH_NODESET);
12166 arg1 = valuePop(ctxt);
12167
12168 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12169 arg2->nodesetval);
12170 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012171 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012172 /* optimizer */
12173 if (total > cur)
12174 xmlXPathCompSwap(op);
12175 return (total + cur);
12176 case XPATH_OP_ROOT:
12177 xmlXPathRoot(ctxt);
12178 return (0);
12179 case XPATH_OP_NODE:
12180 if (op->ch1 != -1)
12181 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012182 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012183 if (op->ch2 != -1)
12184 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012185 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012186 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12187 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012188 return (total);
12189 case XPATH_OP_RESET:
12190 if (op->ch1 != -1)
12191 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012192 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012193 if (op->ch2 != -1)
12194 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012195 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012196 ctxt->context->node = NULL;
12197 return (total);
12198 case XPATH_OP_COLLECT:{
12199 if (op->ch1 == -1)
12200 return (total);
12201
12202 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012203 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012204
12205 /*
12206 * Optimization for [n] selection where n is a number
12207 */
12208 if ((op->ch2 != -1) &&
12209 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12210 (comp->steps[op->ch2].ch1 == -1) &&
12211 (comp->steps[op->ch2].ch2 != -1) &&
12212 (comp->steps[comp->steps[op->ch2].ch2].op ==
12213 XPATH_OP_VALUE)) {
12214 xmlXPathObjectPtr val;
12215
12216 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12217 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12218 int indx = (int) val->floatval;
12219
12220 if (val->floatval == (float) indx) {
12221 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
12222 first, NULL);
12223 return (total);
12224 }
12225 }
12226 }
12227 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
12228 return (total);
12229 }
12230 case XPATH_OP_VALUE:
12231 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012232 xmlXPathCacheObjectCopy(ctxt->context,
12233 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012234 return (0);
12235 case XPATH_OP_SORT:
12236 if (op->ch1 != -1)
12237 total +=
12238 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12239 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000012240 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012241 if ((ctxt->value != NULL)
12242 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012243 && (ctxt->value->nodesetval != NULL)
12244 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012245 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12246 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012247#ifdef XP_OPTIMIZED_FILTER_FIRST
12248 case XPATH_OP_FILTER:
12249 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12250 return (total);
12251#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000012252 default:
12253 return (xmlXPathCompOpEval(ctxt, op));
12254 }
12255}
12256
12257/**
12258 * xmlXPathCompOpEvalLast:
12259 * @ctxt: the XPath parser context with the compiled expression
12260 * @op: an XPath compiled operation
12261 * @last: the last elem found so far
12262 *
12263 * Evaluate the Precompiled XPath operation searching only the last
12264 * element in document order
12265 *
William M. Brack08171912003-12-29 02:52:11 +000012266 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000012267 */
12268static int
12269xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12270 xmlNodePtr * last)
12271{
12272 int total = 0, cur;
12273 xmlXPathCompExprPtr comp;
12274 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000012275 xmlNodePtr bak;
12276 xmlDocPtr bakd;
12277 int pp;
12278 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012279
Daniel Veillard556c6682001-10-06 09:59:51 +000012280 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012281 comp = ctxt->comp;
12282 switch (op->op) {
12283 case XPATH_OP_END:
12284 return (0);
12285 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000012286 bakd = ctxt->context->doc;
12287 bak = ctxt->context->node;
12288 pp = ctxt->context->proximityPosition;
12289 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012290 total =
12291 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012292 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012293 if ((ctxt->value != NULL)
12294 && (ctxt->value->type == XPATH_NODESET)
12295 && (ctxt->value->nodesetval != NULL)
12296 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12297 /*
12298 * limit tree traversing to first node in the result
12299 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012300 if (ctxt->value->nodesetval->nodeNr > 1)
12301 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012302 *last =
12303 ctxt->value->nodesetval->nodeTab[ctxt->value->
12304 nodesetval->nodeNr -
12305 1];
12306 }
William M. Brackce4fc562004-01-22 02:47:18 +000012307 ctxt->context->doc = bakd;
12308 ctxt->context->node = bak;
12309 ctxt->context->proximityPosition = pp;
12310 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012311 cur =
12312 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012314 if ((ctxt->value != NULL)
12315 && (ctxt->value->type == XPATH_NODESET)
12316 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012317 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012318 }
12319 CHECK_TYPE0(XPATH_NODESET);
12320 arg2 = valuePop(ctxt);
12321
12322 CHECK_TYPE0(XPATH_NODESET);
12323 arg1 = valuePop(ctxt);
12324
12325 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12326 arg2->nodesetval);
12327 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012328 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012329 /* optimizer */
12330 if (total > cur)
12331 xmlXPathCompSwap(op);
12332 return (total + cur);
12333 case XPATH_OP_ROOT:
12334 xmlXPathRoot(ctxt);
12335 return (0);
12336 case XPATH_OP_NODE:
12337 if (op->ch1 != -1)
12338 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012339 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012340 if (op->ch2 != -1)
12341 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012342 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012343 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12344 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012345 return (total);
12346 case XPATH_OP_RESET:
12347 if (op->ch1 != -1)
12348 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012349 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012350 if (op->ch2 != -1)
12351 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012352 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012353 ctxt->context->node = NULL;
12354 return (total);
12355 case XPATH_OP_COLLECT:{
12356 if (op->ch1 == -1)
12357 return (0);
12358
12359 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012360 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012361
12362 /*
12363 * Optimization for [n] selection where n is a number
12364 */
12365 if ((op->ch2 != -1) &&
12366 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12367 (comp->steps[op->ch2].ch1 == -1) &&
12368 (comp->steps[op->ch2].ch2 != -1) &&
12369 (comp->steps[comp->steps[op->ch2].ch2].op ==
12370 XPATH_OP_VALUE)) {
12371 xmlXPathObjectPtr val;
12372
12373 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12374 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12375 int indx = (int) val->floatval;
12376
12377 if (val->floatval == (float) indx) {
12378 total +=
12379 xmlXPathNodeCollectAndTestNth(ctxt, op,
12380 indx, NULL,
12381 last);
12382 return (total);
12383 }
12384 }
12385 }
12386 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
12387 return (total);
12388 }
12389 case XPATH_OP_VALUE:
12390 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012391 xmlXPathCacheObjectCopy(ctxt->context,
12392 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012393 return (0);
12394 case XPATH_OP_SORT:
12395 if (op->ch1 != -1)
12396 total +=
12397 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12398 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000012399 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012400 if ((ctxt->value != NULL)
12401 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012402 && (ctxt->value->nodesetval != NULL)
12403 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000012404 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12405 return (total);
12406 default:
12407 return (xmlXPathCompOpEval(ctxt, op));
12408 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012409}
12410
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012411#ifdef XP_OPTIMIZED_FILTER_FIRST
12412static int
12413xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12414 xmlXPathStepOpPtr op, xmlNodePtr * first)
12415{
12416 int total = 0;
12417 xmlXPathCompExprPtr comp;
12418 xmlXPathObjectPtr res;
12419 xmlXPathObjectPtr obj;
12420 xmlNodeSetPtr oldset;
12421 xmlNodePtr oldnode;
12422 xmlDocPtr oldDoc;
12423 int i;
12424
12425 CHECK_ERROR0;
12426 comp = ctxt->comp;
12427 /*
12428 * Optimization for ()[last()] selection i.e. the last elem
12429 */
12430 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12431 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12432 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12433 int f = comp->steps[op->ch2].ch1;
12434
12435 if ((f != -1) &&
12436 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12437 (comp->steps[f].value5 == NULL) &&
12438 (comp->steps[f].value == 0) &&
12439 (comp->steps[f].value4 != NULL) &&
12440 (xmlStrEqual
12441 (comp->steps[f].value4, BAD_CAST "last"))) {
12442 xmlNodePtr last = NULL;
12443
12444 total +=
12445 xmlXPathCompOpEvalLast(ctxt,
12446 &comp->steps[op->ch1],
12447 &last);
12448 CHECK_ERROR0;
12449 /*
12450 * The nodeset should be in document order,
12451 * Keep only the last value
12452 */
12453 if ((ctxt->value != NULL) &&
12454 (ctxt->value->type == XPATH_NODESET) &&
12455 (ctxt->value->nodesetval != NULL) &&
12456 (ctxt->value->nodesetval->nodeTab != NULL) &&
12457 (ctxt->value->nodesetval->nodeNr > 1)) {
12458 ctxt->value->nodesetval->nodeTab[0] =
12459 ctxt->value->nodesetval->nodeTab[ctxt->
12460 value->
12461 nodesetval->
12462 nodeNr -
12463 1];
12464 ctxt->value->nodesetval->nodeNr = 1;
12465 *first = *(ctxt->value->nodesetval->nodeTab);
12466 }
12467 return (total);
12468 }
12469 }
12470
12471 if (op->ch1 != -1)
12472 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12473 CHECK_ERROR0;
12474 if (op->ch2 == -1)
12475 return (total);
12476 if (ctxt->value == NULL)
12477 return (total);
12478
12479#ifdef LIBXML_XPTR_ENABLED
12480 oldnode = ctxt->context->node;
12481 /*
12482 * Hum are we filtering the result of an XPointer expression
12483 */
12484 if (ctxt->value->type == XPATH_LOCATIONSET) {
12485 xmlXPathObjectPtr tmp = NULL;
12486 xmlLocationSetPtr newlocset = NULL;
12487 xmlLocationSetPtr oldlocset;
12488
12489 /*
12490 * Extract the old locset, and then evaluate the result of the
12491 * expression for all the element in the locset. use it to grow
12492 * up a new locset.
12493 */
12494 CHECK_TYPE0(XPATH_LOCATIONSET);
12495 obj = valuePop(ctxt);
12496 oldlocset = obj->user;
12497 ctxt->context->node = NULL;
12498
12499 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12500 ctxt->context->contextSize = 0;
12501 ctxt->context->proximityPosition = 0;
12502 if (op->ch2 != -1)
12503 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12504 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012505 if (res != NULL) {
12506 xmlXPathReleaseObject(ctxt->context, res);
12507 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012508 valuePush(ctxt, obj);
12509 CHECK_ERROR0;
12510 return (total);
12511 }
12512 newlocset = xmlXPtrLocationSetCreate(NULL);
12513
12514 for (i = 0; i < oldlocset->locNr; i++) {
12515 /*
12516 * Run the evaluation with a node list made of a
12517 * single item in the nodelocset.
12518 */
12519 ctxt->context->node = oldlocset->locTab[i]->user;
12520 ctxt->context->contextSize = oldlocset->locNr;
12521 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012522 if (tmp == NULL) {
12523 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12524 ctxt->context->node);
12525 } else {
12526 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12527 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012528 }
12529 valuePush(ctxt, tmp);
12530 if (op->ch2 != -1)
12531 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12532 if (ctxt->error != XPATH_EXPRESSION_OK) {
12533 xmlXPathFreeObject(obj);
12534 return(0);
12535 }
12536 /*
12537 * The result of the evaluation need to be tested to
12538 * decided whether the filter succeeded or not
12539 */
12540 res = valuePop(ctxt);
12541 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12542 xmlXPtrLocationSetAdd(newlocset,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012543 xmlXPathCacheObjectCopy(ctxt->context,
12544 oldlocset->locTab[i]));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012545 }
12546 /*
12547 * Cleanup
12548 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012549 if (res != NULL) {
12550 xmlXPathReleaseObject(ctxt->context, res);
12551 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012552 if (ctxt->value == tmp) {
12553 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012554 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012555 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012556 * REVISIT TODO: Don't create a temporary nodeset
12557 * for everly iteration.
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012558 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012559 /* OLD: xmlXPathFreeObject(res); */
12560 } else
12561 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012562 ctxt->context->node = NULL;
12563 /*
12564 * Only put the first node in the result, then leave.
12565 */
12566 if (newlocset->locNr > 0) {
12567 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12568 break;
12569 }
12570 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012571 if (tmp != NULL) {
12572 xmlXPathReleaseObject(ctxt->context, tmp);
12573 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012574 /*
12575 * The result is used as the new evaluation locset.
12576 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012577 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012578 ctxt->context->node = NULL;
12579 ctxt->context->contextSize = -1;
12580 ctxt->context->proximityPosition = -1;
12581 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12582 ctxt->context->node = oldnode;
12583 return (total);
12584 }
12585#endif /* LIBXML_XPTR_ENABLED */
12586
12587 /*
12588 * Extract the old set, and then evaluate the result of the
12589 * expression for all the element in the set. use it to grow
12590 * up a new set.
12591 */
12592 CHECK_TYPE0(XPATH_NODESET);
12593 obj = valuePop(ctxt);
12594 oldset = obj->nodesetval;
12595
12596 oldnode = ctxt->context->node;
12597 oldDoc = ctxt->context->doc;
12598 ctxt->context->node = NULL;
12599
12600 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12601 ctxt->context->contextSize = 0;
12602 ctxt->context->proximityPosition = 0;
12603 /* QUESTION TODO: Why was this code commented out?
12604 if (op->ch2 != -1)
12605 total +=
12606 xmlXPathCompOpEval(ctxt,
12607 &comp->steps[op->ch2]);
12608 CHECK_ERROR0;
12609 res = valuePop(ctxt);
12610 if (res != NULL)
12611 xmlXPathFreeObject(res);
12612 */
12613 valuePush(ctxt, obj);
12614 ctxt->context->node = oldnode;
12615 CHECK_ERROR0;
12616 } else {
12617 xmlNodeSetPtr newset;
12618 xmlXPathObjectPtr tmp = NULL;
12619 /*
12620 * Initialize the new set.
12621 * Also set the xpath document in case things like
12622 * key() evaluation are attempted on the predicate
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012623 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012624 newset = xmlXPathNodeSetCreate(NULL);
12625
12626 for (i = 0; i < oldset->nodeNr; i++) {
12627 /*
12628 * Run the evaluation with a node list made of
12629 * a single item in the nodeset.
12630 */
12631 ctxt->context->node = oldset->nodeTab[i];
12632 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12633 (oldset->nodeTab[i]->doc != NULL))
12634 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012635 if (tmp == NULL) {
12636 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12637 ctxt->context->node);
12638 } else {
12639 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12640 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012641 }
12642 valuePush(ctxt, tmp);
12643 ctxt->context->contextSize = oldset->nodeNr;
12644 ctxt->context->proximityPosition = i + 1;
12645 if (op->ch2 != -1)
12646 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12647 if (ctxt->error != XPATH_EXPRESSION_OK) {
12648 xmlXPathFreeNodeSet(newset);
12649 xmlXPathFreeObject(obj);
12650 return(0);
12651 }
12652 /*
12653 * The result of the evaluation needs to be tested to
12654 * decide whether the filter succeeded or not
12655 */
12656 res = valuePop(ctxt);
12657 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12658 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12659 }
12660 /*
12661 * Cleanup
12662 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012663 if (res != NULL) {
12664 xmlXPathReleaseObject(ctxt->context, res);
12665 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012666 if (ctxt->value == tmp) {
12667 valuePop(ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012668 /*
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012669 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012670 * in order to avoid massive recreation inside this
12671 * loop.
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012672 */
12673 xmlXPathNodeSetClear(tmp->nodesetval);
12674 } else
12675 tmp = NULL;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012676 ctxt->context->node = NULL;
12677 /*
12678 * Only put the first node in the result, then leave.
12679 */
12680 if (newset->nodeNr > 0) {
12681 *first = *(newset->nodeTab);
12682 break;
12683 }
12684 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012685 if (tmp != NULL) {
12686 xmlXPathReleaseObject(ctxt->context, tmp);
12687 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012688 /*
12689 * The result is used as the new evaluation set.
12690 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012691 xmlXPathReleaseObject(ctxt->context, obj);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012692 ctxt->context->node = NULL;
12693 ctxt->context->contextSize = -1;
12694 ctxt->context->proximityPosition = -1;
12695 /* may want to move this past the '}' later */
12696 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012697 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012698 }
12699 ctxt->context->node = oldnode;
12700 return(total);
12701}
12702#endif /* XP_OPTIMIZED_FILTER_FIRST */
12703
Owen Taylor3473f882001-02-23 17:55:21 +000012704/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012705 * xmlXPathCompOpEval:
12706 * @ctxt: the XPath parser context with the compiled expression
12707 * @op: an XPath compiled operation
12708 *
12709 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000012710 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012711 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012712static int
12713xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12714{
12715 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012716 int equal, ret;
12717 xmlXPathCompExprPtr comp;
12718 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012719 xmlNodePtr bak;
12720 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000012721 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000012722 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012723
Daniel Veillard556c6682001-10-06 09:59:51 +000012724 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012725 comp = ctxt->comp;
12726 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012727 case XPATH_OP_END:
12728 return (0);
12729 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012730 bakd = ctxt->context->doc;
12731 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012732 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012733 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012734 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012735 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012736 xmlXPathBooleanFunction(ctxt, 1);
12737 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12738 return (total);
12739 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012740 ctxt->context->doc = bakd;
12741 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012742 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012743 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012744 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012745 if (ctxt->error) {
12746 xmlXPathFreeObject(arg2);
12747 return(0);
12748 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012749 xmlXPathBooleanFunction(ctxt, 1);
12750 arg1 = valuePop(ctxt);
12751 arg1->boolval &= arg2->boolval;
12752 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012753 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012754 return (total);
12755 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012756 bakd = ctxt->context->doc;
12757 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012758 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012759 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012760 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012761 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012762 xmlXPathBooleanFunction(ctxt, 1);
12763 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12764 return (total);
12765 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012766 ctxt->context->doc = bakd;
12767 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012768 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012769 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012770 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012771 if (ctxt->error) {
12772 xmlXPathFreeObject(arg2);
12773 return(0);
12774 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000012775 xmlXPathBooleanFunction(ctxt, 1);
12776 arg1 = valuePop(ctxt);
12777 arg1->boolval |= arg2->boolval;
12778 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012779 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012780 return (total);
12781 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012782 bakd = ctxt->context->doc;
12783 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012784 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012785 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012786 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012787 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012788 ctxt->context->doc = bakd;
12789 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012790 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012791 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012793 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000012794 if (op->value)
12795 equal = xmlXPathEqualValues(ctxt);
12796 else
12797 equal = xmlXPathNotEqualValues(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012798 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012799 return (total);
12800 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012801 bakd = ctxt->context->doc;
12802 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012803 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012804 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012805 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012806 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012807 ctxt->context->doc = bakd;
12808 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012809 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012810 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012811 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012812 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012813 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012814 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012815 return (total);
12816 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012817 bakd = ctxt->context->doc;
12818 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012819 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012820 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012821 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012822 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012823 if (op->ch2 != -1) {
12824 ctxt->context->doc = bakd;
12825 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012826 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012827 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012828 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012829 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012831 if (op->value == 0)
12832 xmlXPathSubValues(ctxt);
12833 else if (op->value == 1)
12834 xmlXPathAddValues(ctxt);
12835 else if (op->value == 2)
12836 xmlXPathValueFlipSign(ctxt);
12837 else if (op->value == 3) {
12838 CAST_TO_NUMBER;
12839 CHECK_TYPE0(XPATH_NUMBER);
12840 }
12841 return (total);
12842 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012843 bakd = ctxt->context->doc;
12844 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012845 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012846 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012847 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012848 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012849 ctxt->context->doc = bakd;
12850 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012851 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012852 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012853 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012854 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012855 if (op->value == 0)
12856 xmlXPathMultValues(ctxt);
12857 else if (op->value == 1)
12858 xmlXPathDivValues(ctxt);
12859 else if (op->value == 2)
12860 xmlXPathModValues(ctxt);
12861 return (total);
12862 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012863 bakd = ctxt->context->doc;
12864 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000012865 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000012866 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012868 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000012869 ctxt->context->doc = bakd;
12870 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000012871 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000012872 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012873 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012874 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012875 CHECK_TYPE0(XPATH_NODESET);
12876 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012877
Daniel Veillardf06307e2001-07-03 10:35:50 +000012878 CHECK_TYPE0(XPATH_NODESET);
12879 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012880
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000012881 if ((arg1->nodesetval == NULL) ||
12882 ((arg2->nodesetval != NULL) &&
12883 (arg2->nodesetval->nodeNr != 0)))
12884 {
12885 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12886 arg2->nodesetval);
12887 }
12888
Daniel Veillardf06307e2001-07-03 10:35:50 +000012889 valuePush(ctxt, arg1);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012890 xmlXPathReleaseObject(ctxt->context, arg2);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012891 return (total);
12892 case XPATH_OP_ROOT:
12893 xmlXPathRoot(ctxt);
12894 return (total);
12895 case XPATH_OP_NODE:
12896 if (op->ch1 != -1)
12897 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012898 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012899 if (op->ch2 != -1)
12900 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012901 CHECK_ERROR0;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012902 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12903 ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012904 return (total);
12905 case XPATH_OP_RESET:
12906 if (op->ch1 != -1)
12907 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012908 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012909 if (op->ch2 != -1)
12910 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012911 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012912 ctxt->context->node = NULL;
12913 return (total);
12914 case XPATH_OP_COLLECT:{
12915 if (op->ch1 == -1)
12916 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012917
Daniel Veillardf06307e2001-07-03 10:35:50 +000012918 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012919 CHECK_ERROR0;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012920
12921 if ((op->ch2 != -1) &&
Daniel Veillardf06307e2001-07-03 10:35:50 +000012922 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
12923 (comp->steps[op->ch2].ch1 == -1) &&
12924 (comp->steps[op->ch2].ch2 != -1) &&
12925 (comp->steps[comp->steps[op->ch2].ch2].op ==
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012926 XPATH_OP_VALUE))
12927 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012928 xmlXPathObjectPtr val;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000012929 /*
12930 * Optimization for [n] selection where n is a number
12931 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000012932 val = comp->steps[comp->steps[op->ch2].ch2].value4;
12933 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
12934 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012935
Daniel Veillardf06307e2001-07-03 10:35:50 +000012936 if (val->floatval == (float) indx) {
12937 total +=
12938 xmlXPathNodeCollectAndTestNth(ctxt, op,
12939 indx, NULL,
12940 NULL);
12941 return (total);
12942 }
12943 }
12944 }
12945 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
12946 return (total);
12947 }
12948 case XPATH_OP_VALUE:
12949 valuePush(ctxt,
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000012950 xmlXPathCacheObjectCopy(ctxt->context,
12951 (xmlXPathObjectPtr) op->value4));
Daniel Veillardf06307e2001-07-03 10:35:50 +000012952 return (total);
12953 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000012954 xmlXPathObjectPtr val;
12955
Daniel Veillardf06307e2001-07-03 10:35:50 +000012956 if (op->ch1 != -1)
12957 total +=
12958 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012959 if (op->value5 == NULL) {
12960 val = xmlXPathVariableLookup(ctxt->context, op->value4);
12961 if (val == NULL) {
12962 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12963 return(0);
12964 }
12965 valuePush(ctxt, val);
12966 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000012967 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012968
Daniel Veillardf06307e2001-07-03 10:35:50 +000012969 URI = xmlXPathNsLookup(ctxt->context, op->value5);
12970 if (URI == NULL) {
12971 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012972 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000012973 op->value4, op->value5);
12974 return (total);
12975 }
Daniel Veillard556c6682001-10-06 09:59:51 +000012976 val = xmlXPathVariableLookupNS(ctxt->context,
12977 op->value4, URI);
12978 if (val == NULL) {
12979 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
12980 return(0);
12981 }
12982 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000012983 }
12984 return (total);
12985 }
12986 case XPATH_OP_FUNCTION:{
12987 xmlXPathFunction func;
12988 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000012989 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000012990
12991 if (op->ch1 != -1)
12992 total +=
12993 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000012994 if (ctxt->valueNr < op->value) {
12995 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012996 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000012997 ctxt->error = XPATH_INVALID_OPERAND;
12998 return (total);
12999 }
13000 for (i = 0; i < op->value; i++)
13001 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13002 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013003 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000013004 ctxt->error = XPATH_INVALID_OPERAND;
13005 return (total);
13006 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013007 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000013008 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013009 else {
13010 const xmlChar *URI = NULL;
13011
13012 if (op->value5 == NULL)
13013 func =
13014 xmlXPathFunctionLookup(ctxt->context,
13015 op->value4);
13016 else {
13017 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13018 if (URI == NULL) {
13019 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013020 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013021 op->value4, op->value5);
13022 return (total);
13023 }
13024 func = xmlXPathFunctionLookupNS(ctxt->context,
13025 op->value4, URI);
13026 }
13027 if (func == NULL) {
13028 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013029 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000013030 op->value4);
13031 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013032 }
William M. Brackad0e67c2004-12-01 14:35:10 +000013033 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013034 op->cacheURI = (void *) URI;
13035 }
13036 oldFunc = ctxt->context->function;
13037 oldFuncURI = ctxt->context->functionURI;
13038 ctxt->context->function = op->value4;
13039 ctxt->context->functionURI = op->cacheURI;
13040 func(ctxt, op->value);
13041 ctxt->context->function = oldFunc;
13042 ctxt->context->functionURI = oldFuncURI;
13043 return (total);
13044 }
13045 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000013046 bakd = ctxt->context->doc;
13047 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000013048 pp = ctxt->context->proximityPosition;
13049 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013050 if (op->ch1 != -1)
13051 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000013052 ctxt->context->contextSize = cs;
13053 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000013054 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000013055 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000013056 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000013057 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000013059 ctxt->context->doc = bakd;
13060 ctxt->context->node = bak;
13061 CHECK_ERROR0;
13062 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013063 return (total);
13064 case XPATH_OP_PREDICATE:
13065 case XPATH_OP_FILTER:{
13066 xmlXPathObjectPtr res;
13067 xmlXPathObjectPtr obj, tmp;
13068 xmlNodeSetPtr newset = NULL;
13069 xmlNodeSetPtr oldset;
13070 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000013071 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013072 int i;
13073
13074 /*
13075 * Optimization for ()[1] selection i.e. the first elem
13076 */
13077 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013078#ifdef XP_OPTIMIZED_FILTER_FIRST
13079 /*
13080 * FILTER TODO: Can we assume that the inner processing
13081 * will result in an ordered list if we have an
13082 * XPATH_OP_FILTER?
13083 * What about an additional field or flag on
13084 * xmlXPathObject like @sorted ? This way we wouln'd need
13085 * to assume anything, so it would be more robust and
13086 * easier to optimize.
13087 */
13088 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13089 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13090#else
13091 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13092#endif
13093 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013094 xmlXPathObjectPtr val;
13095
13096 val = comp->steps[op->ch2].value4;
13097 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13098 (val->floatval == 1.0)) {
13099 xmlNodePtr first = NULL;
13100
13101 total +=
13102 xmlXPathCompOpEvalFirst(ctxt,
13103 &comp->steps[op->ch1],
13104 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000013105 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013106 /*
13107 * The nodeset should be in document order,
13108 * Keep only the first value
13109 */
13110 if ((ctxt->value != NULL) &&
13111 (ctxt->value->type == XPATH_NODESET) &&
13112 (ctxt->value->nodesetval != NULL) &&
13113 (ctxt->value->nodesetval->nodeNr > 1))
13114 ctxt->value->nodesetval->nodeNr = 1;
13115 return (total);
13116 }
13117 }
13118 /*
13119 * Optimization for ()[last()] selection i.e. the last elem
13120 */
13121 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13122 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13123 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13124 int f = comp->steps[op->ch2].ch1;
13125
13126 if ((f != -1) &&
13127 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13128 (comp->steps[f].value5 == NULL) &&
13129 (comp->steps[f].value == 0) &&
13130 (comp->steps[f].value4 != NULL) &&
13131 (xmlStrEqual
13132 (comp->steps[f].value4, BAD_CAST "last"))) {
13133 xmlNodePtr last = NULL;
13134
13135 total +=
13136 xmlXPathCompOpEvalLast(ctxt,
13137 &comp->steps[op->ch1],
13138 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000013139 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013140 /*
13141 * The nodeset should be in document order,
13142 * Keep only the last value
13143 */
13144 if ((ctxt->value != NULL) &&
13145 (ctxt->value->type == XPATH_NODESET) &&
13146 (ctxt->value->nodesetval != NULL) &&
13147 (ctxt->value->nodesetval->nodeTab != NULL) &&
13148 (ctxt->value->nodesetval->nodeNr > 1)) {
13149 ctxt->value->nodesetval->nodeTab[0] =
13150 ctxt->value->nodesetval->nodeTab[ctxt->
13151 value->
13152 nodesetval->
13153 nodeNr -
13154 1];
13155 ctxt->value->nodesetval->nodeNr = 1;
13156 }
13157 return (total);
13158 }
13159 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013160 /*
13161 * Process inner predicates first.
13162 * Example "index[parent::book][1]":
13163 * ...
13164 * PREDICATE <-- we are here "[1]"
13165 * PREDICATE <-- process "[parent::book]" first
13166 * SORT
13167 * COLLECT 'parent' 'name' 'node' book
13168 * NODE
13169 * ELEM Object is a number : 1
13170 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013171 if (op->ch1 != -1)
13172 total +=
13173 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013174 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013175 if (op->ch2 == -1)
13176 return (total);
13177 if (ctxt->value == NULL)
13178 return (total);
13179
13180 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013181
13182#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013183 /*
13184 * Hum are we filtering the result of an XPointer expression
13185 */
13186 if (ctxt->value->type == XPATH_LOCATIONSET) {
13187 xmlLocationSetPtr newlocset = NULL;
13188 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013189
Daniel Veillardf06307e2001-07-03 10:35:50 +000013190 /*
13191 * Extract the old locset, and then evaluate the result of the
13192 * expression for all the element in the locset. use it to grow
13193 * up a new locset.
13194 */
13195 CHECK_TYPE0(XPATH_LOCATIONSET);
13196 obj = valuePop(ctxt);
13197 oldlocset = obj->user;
13198 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013199
Daniel Veillardf06307e2001-07-03 10:35:50 +000013200 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13201 ctxt->context->contextSize = 0;
13202 ctxt->context->proximityPosition = 0;
13203 if (op->ch2 != -1)
13204 total +=
13205 xmlXPathCompOpEval(ctxt,
13206 &comp->steps[op->ch2]);
13207 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013208 if (res != NULL) {
13209 xmlXPathReleaseObject(ctxt->context, res);
13210 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013211 valuePush(ctxt, obj);
13212 CHECK_ERROR0;
13213 return (total);
13214 }
13215 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013216
Daniel Veillardf06307e2001-07-03 10:35:50 +000013217 for (i = 0; i < oldlocset->locNr; i++) {
13218 /*
13219 * Run the evaluation with a node list made of a
13220 * single item in the nodelocset.
13221 */
13222 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013223 ctxt->context->contextSize = oldlocset->locNr;
13224 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013225 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13226 ctxt->context->node);
William M. Brackf7eb7942003-12-31 07:59:17 +000013227 valuePush(ctxt, tmp);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013228
Daniel Veillardf06307e2001-07-03 10:35:50 +000013229 if (op->ch2 != -1)
13230 total +=
13231 xmlXPathCompOpEval(ctxt,
13232 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013233 if (ctxt->error != XPATH_EXPRESSION_OK) {
13234 xmlXPathFreeObject(obj);
13235 return(0);
13236 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013237
Daniel Veillardf06307e2001-07-03 10:35:50 +000013238 /*
13239 * The result of the evaluation need to be tested to
13240 * decided whether the filter succeeded or not
13241 */
13242 res = valuePop(ctxt);
13243 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13244 xmlXPtrLocationSetAdd(newlocset,
13245 xmlXPathObjectCopy
13246 (oldlocset->locTab[i]));
13247 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013248
Daniel Veillardf06307e2001-07-03 10:35:50 +000013249 /*
13250 * Cleanup
13251 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013252 if (res != NULL) {
13253 xmlXPathReleaseObject(ctxt->context, res);
13254 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013255 if (ctxt->value == tmp) {
13256 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013257 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013258 }
13259
13260 ctxt->context->node = NULL;
13261 }
13262
13263 /*
13264 * The result is used as the new evaluation locset.
13265 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013266 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013267 ctxt->context->node = NULL;
13268 ctxt->context->contextSize = -1;
13269 ctxt->context->proximityPosition = -1;
13270 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13271 ctxt->context->node = oldnode;
13272 return (total);
13273 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013274#endif /* LIBXML_XPTR_ENABLED */
13275
Daniel Veillardf06307e2001-07-03 10:35:50 +000013276 /*
13277 * Extract the old set, and then evaluate the result of the
13278 * expression for all the element in the set. use it to grow
13279 * up a new set.
13280 */
13281 CHECK_TYPE0(XPATH_NODESET);
13282 obj = valuePop(ctxt);
13283 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000013284
Daniel Veillardf06307e2001-07-03 10:35:50 +000013285 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000013286 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013287 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013288
Daniel Veillardf06307e2001-07-03 10:35:50 +000013289 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13290 ctxt->context->contextSize = 0;
13291 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000013292/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000013293 if (op->ch2 != -1)
13294 total +=
13295 xmlXPathCompOpEval(ctxt,
13296 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013297 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013298 res = valuePop(ctxt);
13299 if (res != NULL)
13300 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000013301*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000013302 valuePush(ctxt, obj);
13303 ctxt->context->node = oldnode;
13304 CHECK_ERROR0;
13305 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013306 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013307 /*
13308 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000013309 * Also set the xpath document in case things like
13310 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000013311 */
13312 newset = xmlXPathNodeSetCreate(NULL);
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013313 /*
13314 * SPEC XPath 1.0:
13315 * "For each node in the node-set to be filtered, the
13316 * PredicateExpr is evaluated with that node as the
13317 * context node, with the number of nodes in the
13318 * node-set as the context size, and with the proximity
13319 * position of the node in the node-set with respect to
13320 * the axis as the context position;"
13321 * @oldset is the node-set" to be filtered.
13322 *
13323 * SPEC XPath 1.0:
13324 * "only predicates change the context position and
13325 * context size (see [2.4 Predicates])."
13326 * Example:
13327 * node-set context pos
13328 * nA 1
13329 * nB 2
13330 * nC 3
13331 * After applying predicate [position() > 1] :
13332 * node-set context pos
13333 * nB 1
13334 * nC 2
13335 *
13336 * removed the first node in the node-set, then
13337 * the context position of the
13338 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013339 for (i = 0; i < oldset->nodeNr; i++) {
13340 /*
13341 * Run the evaluation with a node list made of
13342 * a single item in the nodeset.
13343 */
13344 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000013345 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13346 (oldset->nodeTab[i]->doc != NULL))
13347 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013348 if (tmp == NULL) {
13349 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13350 ctxt->context->node);
13351 } else {
13352 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13353 ctxt->context->node);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013354 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013355 valuePush(ctxt, tmp);
13356 ctxt->context->contextSize = oldset->nodeNr;
13357 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013358 /*
13359 * Evaluate the predicate against the context node.
13360 * Can/should we optimize position() predicates
13361 * here (e.g. "[1]")?
13362 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013363 if (op->ch2 != -1)
13364 total +=
13365 xmlXPathCompOpEval(ctxt,
13366 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013367 if (ctxt->error != XPATH_EXPRESSION_OK) {
13368 xmlXPathFreeNodeSet(newset);
13369 xmlXPathFreeObject(obj);
13370 return(0);
13371 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013372
Daniel Veillardf06307e2001-07-03 10:35:50 +000013373 /*
William M. Brack08171912003-12-29 02:52:11 +000013374 * The result of the evaluation needs to be tested to
13375 * decide whether the filter succeeded or not
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013376 */
13377 /*
13378 * OPTIMIZE TODO: Can we use
13379 * xmlXPathNodeSetAdd*Unique()* instead?
13380 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000013381 res = valuePop(ctxt);
13382 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13383 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13384 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013385
Daniel Veillardf06307e2001-07-03 10:35:50 +000013386 /*
13387 * Cleanup
13388 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013389 if (res != NULL) {
13390 xmlXPathReleaseObject(ctxt->context, res);
13391 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013392 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013393 valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013394 xmlXPathNodeSetClear(tmp->nodesetval);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013395 /*
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013396 * Don't free the temporary nodeset
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013397 * in order to avoid massive recreation inside this
13398 * loop.
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000013399 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013400 } else
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013401 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013402 ctxt->context->node = NULL;
13403 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000013404 if (tmp != NULL)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013405 xmlXPathReleaseObject(ctxt->context, tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013406 /*
13407 * The result is used as the new evaluation set.
13408 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013409 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013410 ctxt->context->node = NULL;
13411 ctxt->context->contextSize = -1;
13412 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000013413 /* may want to move this past the '}' later */
13414 ctxt->context->doc = oldDoc;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013415 valuePush(ctxt,
13416 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013417 }
13418 ctxt->context->node = oldnode;
13419 return (total);
13420 }
13421 case XPATH_OP_SORT:
13422 if (op->ch1 != -1)
13423 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000013424 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013425 if ((ctxt->value != NULL) &&
13426 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000013427 (ctxt->value->nodesetval != NULL) &&
13428 (ctxt->value->nodesetval->nodeNr > 1))
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013429 {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013430 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013431 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013432 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013433#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000013434 case XPATH_OP_RANGETO:{
13435 xmlXPathObjectPtr range;
13436 xmlXPathObjectPtr res, obj;
13437 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000013438 xmlLocationSetPtr newlocset = NULL;
13439 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000013440 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000013441 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013442
Daniel Veillardf06307e2001-07-03 10:35:50 +000013443 if (op->ch1 != -1)
13444 total +=
13445 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13446 if (op->ch2 == -1)
13447 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013448
William M. Brack08171912003-12-29 02:52:11 +000013449 if (ctxt->value->type == XPATH_LOCATIONSET) {
13450 /*
13451 * Extract the old locset, and then evaluate the result of the
13452 * expression for all the element in the locset. use it to grow
13453 * up a new locset.
13454 */
13455 CHECK_TYPE0(XPATH_LOCATIONSET);
13456 obj = valuePop(ctxt);
13457 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013458
William M. Brack08171912003-12-29 02:52:11 +000013459 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000013460 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000013461 ctxt->context->contextSize = 0;
13462 ctxt->context->proximityPosition = 0;
13463 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13464 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013465 if (res != NULL) {
13466 xmlXPathReleaseObject(ctxt->context, res);
13467 }
William M. Brack08171912003-12-29 02:52:11 +000013468 valuePush(ctxt, obj);
13469 CHECK_ERROR0;
13470 return (total);
13471 }
13472 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013473
William M. Brack08171912003-12-29 02:52:11 +000013474 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000013475 /*
William M. Brack08171912003-12-29 02:52:11 +000013476 * Run the evaluation with a node list made of a
13477 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000013478 */
William M. Brackf7eb7942003-12-31 07:59:17 +000013479 ctxt->context->node = oldlocset->locTab[i]->user;
13480 ctxt->context->contextSize = oldlocset->locNr;
13481 ctxt->context->proximityPosition = i + 1;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013482 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13483 ctxt->context->node);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013484 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013485
Daniel Veillardf06307e2001-07-03 10:35:50 +000013486 if (op->ch2 != -1)
13487 total +=
13488 xmlXPathCompOpEval(ctxt,
13489 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013490 if (ctxt->error != XPATH_EXPRESSION_OK) {
13491 xmlXPathFreeObject(obj);
13492 return(0);
13493 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013494
Daniel Veillardf06307e2001-07-03 10:35:50 +000013495 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000013496 if (res->type == XPATH_LOCATIONSET) {
13497 xmlLocationSetPtr rloc =
13498 (xmlLocationSetPtr)res->user;
13499 for (j=0; j<rloc->locNr; j++) {
13500 range = xmlXPtrNewRange(
13501 oldlocset->locTab[i]->user,
13502 oldlocset->locTab[i]->index,
13503 rloc->locTab[j]->user2,
13504 rloc->locTab[j]->index2);
13505 if (range != NULL) {
13506 xmlXPtrLocationSetAdd(newlocset, range);
13507 }
13508 }
13509 } else {
13510 range = xmlXPtrNewRangeNodeObject(
13511 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13512 if (range != NULL) {
13513 xmlXPtrLocationSetAdd(newlocset,range);
13514 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013515 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013516
Daniel Veillardf06307e2001-07-03 10:35:50 +000013517 /*
13518 * Cleanup
13519 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013520 if (res != NULL) {
13521 xmlXPathReleaseObject(ctxt->context, res);
13522 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013523 if (ctxt->value == tmp) {
13524 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013525 xmlXPathReleaseObject(ctxt->context, res);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013526 }
13527
13528 ctxt->context->node = NULL;
13529 }
William M. Brack72ee48d2003-12-30 08:30:19 +000013530 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000013531 CHECK_TYPE0(XPATH_NODESET);
13532 obj = valuePop(ctxt);
13533 oldset = obj->nodesetval;
13534 ctxt->context->node = NULL;
13535
13536 newlocset = xmlXPtrLocationSetCreate(NULL);
13537
13538 if (oldset != NULL) {
13539 for (i = 0; i < oldset->nodeNr; i++) {
13540 /*
13541 * Run the evaluation with a node list made of a single item
13542 * in the nodeset.
13543 */
13544 ctxt->context->node = oldset->nodeTab[i];
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013545 /*
13546 * OPTIMIZE TODO: Avoid recreation for every iteration.
13547 */
13548 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13549 ctxt->context->node);
William M. Brack08171912003-12-29 02:52:11 +000013550 valuePush(ctxt, tmp);
13551
13552 if (op->ch2 != -1)
13553 total +=
13554 xmlXPathCompOpEval(ctxt,
13555 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000013556 if (ctxt->error != XPATH_EXPRESSION_OK) {
13557 xmlXPathFreeObject(obj);
13558 return(0);
13559 }
William M. Brack08171912003-12-29 02:52:11 +000013560
William M. Brack08171912003-12-29 02:52:11 +000013561 res = valuePop(ctxt);
13562 range =
13563 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13564 res);
13565 if (range != NULL) {
13566 xmlXPtrLocationSetAdd(newlocset, range);
13567 }
13568
13569 /*
13570 * Cleanup
13571 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013572 if (res != NULL) {
13573 xmlXPathReleaseObject(ctxt->context, res);
13574 }
William M. Brack08171912003-12-29 02:52:11 +000013575 if (ctxt->value == tmp) {
13576 res = valuePop(ctxt);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013577 xmlXPathReleaseObject(ctxt->context, res);
William M. Brack08171912003-12-29 02:52:11 +000013578 }
13579
13580 ctxt->context->node = NULL;
13581 }
13582 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000013583 }
13584
13585 /*
13586 * The result is used as the new evaluation set.
13587 */
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013588 xmlXPathReleaseObject(ctxt->context, obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000013589 ctxt->context->node = NULL;
13590 ctxt->context->contextSize = -1;
13591 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000013592 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000013593 return (total);
13594 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013595#endif /* LIBXML_XPTR_ENABLED */
13596 }
13597 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000013598 "XPath: unknown precompiled operation %d\n", op->op);
13599 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013600}
13601
Daniel Veillard56de87e2005-02-16 00:22:29 +000013602#ifdef XPATH_STREAMING
13603/**
13604 * xmlXPathRunStreamEval:
13605 * @ctxt: the XPath parser context with the compiled expression
13606 *
13607 * Evaluate the Precompiled Streamable XPath expression in the given context.
13608 */
13609static xmlXPathObjectPtr
13610xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013611 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013612 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013613 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013614#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13615 int eval_all_nodes;
13616#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000013617 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013618 xmlXPathObjectPtr retval;
13619 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013620
13621 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013622
13623 if ((ctxt == NULL) || (comp == NULL))
13624 return(NULL);
13625 max_depth = xmlPatternMaxDepth(comp);
13626 if (max_depth == -1)
13627 return(NULL);
13628 if (max_depth == -2)
13629 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013630 min_depth = xmlPatternMinDepth(comp);
13631 if (min_depth == -1)
13632 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013633 from_root = xmlPatternFromRoot(comp);
13634 if (from_root < 0)
13635 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013636#if 0
13637 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13638#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013639
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000013640 retval = xmlXPathCacheNewNodeSet(ctxt, NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000013641 if (retval == NULL)
13642 return(NULL);
13643
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013644 /*
13645 * handle the special cases of / amd . being matched
13646 */
13647 if (min_depth == 0) {
13648 if (from_root) {
13649 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
13650 } else {
13651 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
13652 }
13653 }
13654 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013655 return(retval);
13656 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000013657
Daniel Veillard56de87e2005-02-16 00:22:29 +000013658 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000013659 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013660 } else if (ctxt->node != NULL) {
13661 switch (ctxt->node->type) {
13662 case XML_ELEMENT_NODE:
13663 case XML_DOCUMENT_NODE:
13664 case XML_DOCUMENT_FRAG_NODE:
13665 case XML_HTML_DOCUMENT_NODE:
13666#ifdef LIBXML_DOCB_ENABLED
13667 case XML_DOCB_DOCUMENT_NODE:
13668#endif
13669 cur = ctxt->node;
13670 break;
13671 case XML_ATTRIBUTE_NODE:
13672 case XML_TEXT_NODE:
13673 case XML_CDATA_SECTION_NODE:
13674 case XML_ENTITY_REF_NODE:
13675 case XML_ENTITY_NODE:
13676 case XML_PI_NODE:
13677 case XML_COMMENT_NODE:
13678 case XML_NOTATION_NODE:
13679 case XML_DTD_NODE:
13680 case XML_DOCUMENT_TYPE_NODE:
13681 case XML_ELEMENT_DECL:
13682 case XML_ATTRIBUTE_DECL:
13683 case XML_ENTITY_DECL:
13684 case XML_NAMESPACE_DECL:
13685 case XML_XINCLUDE_START:
13686 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000013687 break;
13688 }
13689 limit = cur;
13690 }
13691 if (cur == NULL)
13692 return(retval);
13693
13694 patstream = xmlPatternGetStreamCtxt(comp);
13695 if (patstream == NULL) {
13696 return(retval);
13697 }
13698
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013699#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13700 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13701#endif
13702
Daniel Veillard56de87e2005-02-16 00:22:29 +000013703 if (from_root) {
13704 ret = xmlStreamPush(patstream, NULL, NULL);
13705 if (ret < 0) {
13706 } else if (ret == 1) {
13707 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13708 }
13709 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013710 depth = 0;
13711 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000013712next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000013713 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013714 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013715
13716 switch (cur->type) {
13717 case XML_ELEMENT_NODE:
13718#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13719 case XML_TEXT_NODE:
13720 case XML_CDATA_SECTION_NODE:
13721 case XML_COMMENT_NODE:
13722 case XML_PI_NODE:
13723#endif
13724 if (cur->type == XML_ELEMENT_NODE) {
13725 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000013726 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000013727 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013728#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13729 else if (eval_all_nodes)
13730 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13731 else
13732 break;
13733#endif
13734
13735 if (ret < 0) {
13736 /* NOP. */
13737 } else if (ret == 1) {
13738 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
13739 }
13740 if ((cur->children == NULL) || (depth >= max_depth)) {
13741 ret = xmlStreamPop(patstream);
13742 while (cur->next != NULL) {
13743 cur = cur->next;
13744 if ((cur->type != XML_ENTITY_DECL) &&
13745 (cur->type != XML_DTD_NODE))
13746 goto next_node;
13747 }
13748 }
13749 default:
13750 break;
13751 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013752
13753scan_children:
13754 if ((cur->children != NULL) && (depth < max_depth)) {
13755 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013756 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000013757 */
13758 if (cur->children->type != XML_ENTITY_DECL) {
13759 cur = cur->children;
13760 depth++;
13761 /*
13762 * Skip DTDs
13763 */
13764 if (cur->type != XML_DTD_NODE)
13765 continue;
13766 }
13767 }
13768
13769 if (cur == limit)
13770 break;
13771
13772 while (cur->next != NULL) {
13773 cur = cur->next;
13774 if ((cur->type != XML_ENTITY_DECL) &&
13775 (cur->type != XML_DTD_NODE))
13776 goto next_node;
13777 }
13778
13779 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000013780 cur = cur->parent;
13781 depth--;
13782 if ((cur == NULL) || (cur == limit))
13783 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000013784 if (cur->type == XML_ELEMENT_NODE) {
13785 ret = xmlStreamPop(patstream);
13786 }
13787#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
13788 else if ((eval_all_nodes) &&
13789 ((cur->type == XML_TEXT_NODE) ||
13790 (cur->type == XML_CDATA_SECTION_NODE) ||
13791 (cur->type == XML_COMMENT_NODE) ||
13792 (cur->type == XML_PI_NODE)))
13793 {
13794 ret = xmlStreamPop(patstream);
13795 }
13796#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013797 if (cur->next != NULL) {
13798 cur = cur->next;
13799 break;
13800 }
13801 } while (cur != NULL);
13802
13803 } while ((cur != NULL) && (depth >= 0));
13804done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000013805#if 0
13806 printf("stream eval: checked %d nodes selected %d\n",
13807 nb_nodes, retval->nodesetval->nodeNr);
13808#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000013809 xmlFreeStreamCtxt(patstream);
13810 return(retval);
13811}
13812#endif /* XPATH_STREAMING */
13813
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013814/**
13815 * xmlXPathRunEval:
13816 * @ctxt: the XPath parser context with the compiled expression
13817 *
13818 * Evaluate the Precompiled XPath expression in the given context.
13819 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013820static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013821xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
13822 xmlXPathCompExprPtr comp;
13823
13824 if ((ctxt == NULL) || (ctxt->comp == NULL))
13825 return;
13826
13827 if (ctxt->valueTab == NULL) {
13828 /* Allocate the value stack */
13829 ctxt->valueTab = (xmlXPathObjectPtr *)
13830 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13831 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000013832 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013833 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013834 }
13835 ctxt->valueNr = 0;
13836 ctxt->valueMax = 10;
13837 ctxt->value = NULL;
13838 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000013839#ifdef XPATH_STREAMING
13840 if (ctxt->comp->stream) {
13841 xmlXPathObjectPtr ret;
13842 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
13843 if (ret != NULL) {
13844 valuePush(ctxt, ret);
13845 return;
13846 }
13847 }
13848#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013849 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000013850 if(comp->last < 0) {
13851 xmlGenericError(xmlGenericErrorContext,
13852 "xmlXPathRunEval: last is less than zero\n");
13853 return;
13854 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000013855 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13856}
13857
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013858/************************************************************************
13859 * *
13860 * Public interfaces *
13861 * *
13862 ************************************************************************/
13863
13864/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013865 * xmlXPathEvalPredicate:
13866 * @ctxt: the XPath context
13867 * @res: the Predicate Expression evaluation result
13868 *
13869 * Evaluate a predicate result for the current node.
13870 * A PredicateExpr is evaluated by evaluating the Expr and converting
13871 * the result to a boolean. If the result is a number, the result will
13872 * be converted to true if the number is equal to the position of the
13873 * context node in the context node list (as returned by the position
13874 * function) and will be converted to false otherwise; if the result
13875 * is not a number, then the result will be converted as if by a call
13876 * to the boolean function.
13877 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013878 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013879 */
13880int
13881xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013882 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013883 switch (res->type) {
13884 case XPATH_BOOLEAN:
13885 return(res->boolval);
13886 case XPATH_NUMBER:
13887 return(res->floatval == ctxt->proximityPosition);
13888 case XPATH_NODESET:
13889 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000013890 if (res->nodesetval == NULL)
13891 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000013892 return(res->nodesetval->nodeNr != 0);
13893 case XPATH_STRING:
13894 return((res->stringval != NULL) &&
13895 (xmlStrlen(res->stringval) != 0));
13896 default:
13897 STRANGE
13898 }
13899 return(0);
13900}
13901
13902/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013903 * xmlXPathEvaluatePredicateResult:
13904 * @ctxt: the XPath Parser context
13905 * @res: the Predicate Expression evaluation result
13906 *
13907 * Evaluate a predicate result for the current node.
13908 * A PredicateExpr is evaluated by evaluating the Expr and converting
13909 * the result to a boolean. If the result is a number, the result will
13910 * be converted to true if the number is equal to the position of the
13911 * context node in the context node list (as returned by the position
13912 * function) and will be converted to false otherwise; if the result
13913 * is not a number, then the result will be converted as if by a call
13914 * to the boolean function.
13915 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000013916 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013917 */
13918int
13919xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13920 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000013921 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013922 switch (res->type) {
13923 case XPATH_BOOLEAN:
13924 return(res->boolval);
13925 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000013926#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000013927 return((res->floatval == ctxt->context->proximityPosition) &&
13928 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000013929#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013930 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000013931#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013932 case XPATH_NODESET:
13933 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000013934 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000013935 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013936 return(res->nodesetval->nodeNr != 0);
13937 case XPATH_STRING:
13938 return((res->stringval != NULL) &&
13939 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000013940#ifdef LIBXML_XPTR_ENABLED
13941 case XPATH_LOCATIONSET:{
13942 xmlLocationSetPtr ptr = res->user;
13943 if (ptr == NULL)
13944 return(0);
13945 return (ptr->locNr != 0);
13946 }
13947#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000013948 default:
13949 STRANGE
13950 }
13951 return(0);
13952}
13953
Daniel Veillard56de87e2005-02-16 00:22:29 +000013954#ifdef XPATH_STREAMING
13955/**
13956 * xmlXPathTryStreamCompile:
13957 * @ctxt: an XPath context
13958 * @str: the XPath expression
13959 *
13960 * Try to compile the XPath expression as a streamable subset.
13961 *
13962 * Returns the compiled expression or NULL if failed to compile.
13963 */
13964static xmlXPathCompExprPtr
13965xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13966 /*
13967 * Optimization: use streaming patterns when the XPath expression can
13968 * be compiled to a stream lookup
13969 */
13970 xmlPatternPtr stream;
13971 xmlXPathCompExprPtr comp;
13972 xmlDictPtr dict = NULL;
13973 const xmlChar **namespaces = NULL;
13974 xmlNsPtr ns;
13975 int i, j;
13976
13977 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13978 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013979 const xmlChar *tmp;
13980
13981 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013982 * We don't try to handle expressions using the verbose axis
13983 * specifiers ("::"), just the simplied form at this point.
13984 * Additionally, if there is no list of namespaces available and
13985 * there's a ":" in the expression, indicating a prefixed QName,
13986 * then we won't try to compile either. xmlPatterncompile() needs
13987 * to have a list of namespaces at compilation time in order to
13988 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013989 */
13990 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000013991 if ((tmp != NULL) &&
13992 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13993 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000013994
Daniel Veillard56de87e2005-02-16 00:22:29 +000013995 if (ctxt != NULL) {
13996 dict = ctxt->dict;
13997 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000013998 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000013999 if (namespaces == NULL) {
14000 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14001 return(NULL);
14002 }
14003 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14004 ns = ctxt->namespaces[j];
14005 namespaces[i++] = ns->href;
14006 namespaces[i++] = ns->prefix;
14007 }
14008 namespaces[i++] = NULL;
14009 namespaces[i++] = NULL;
14010 }
14011 }
14012
William M. Brackea152c02005-06-09 18:12:28 +000014013 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14014 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000014015 if (namespaces != NULL) {
14016 xmlFree((xmlChar **)namespaces);
14017 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014018 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14019 comp = xmlXPathNewCompExpr();
14020 if (comp == NULL) {
14021 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14022 return(NULL);
14023 }
14024 comp->stream = stream;
14025 comp->dict = dict;
14026 if (comp->dict)
14027 xmlDictReference(comp->dict);
14028 return(comp);
14029 }
14030 xmlFreePattern(stream);
14031 }
14032 return(NULL);
14033}
14034#endif /* XPATH_STREAMING */
14035
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014036static int
14037xmlXPathCanRewriteDosExpression(xmlChar *expr)
14038{
14039 if (expr == NULL)
14040 return(0);
14041 do {
14042 if ((*expr == '/') && (*(++expr) == '/'))
14043 return(1);
14044 } while (*expr++);
14045 return(0);
14046}
14047static void
14048xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14049{
14050 /*
14051 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14052 * internal representation.
14053 */
14054 if (op->ch1 != -1) {
14055 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14056 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14057 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14058 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14059 {
14060 /*
14061 * This is an "foo"
14062 */
14063 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14064
14065 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14066 (prevop->ch1 != -1) &&
14067 ((xmlXPathAxisVal) prevop->value ==
14068 AXIS_DESCENDANT_OR_SELF) &&
14069 (prevop->ch2 == -1) &&
14070 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014071 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14072 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014073 {
14074 /*
14075 * This is a "descendant-or-self::node()" without predicates.
14076 * Eliminate it.
14077 */
14078 op->ch1 = prevop->ch1;
14079 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14080 }
14081 }
14082 if (op->ch1 != -1)
14083 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14084 }
14085 if (op->ch2 != -1)
14086 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14087}
14088
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014089/**
Daniel Veillard4773df22004-01-23 13:15:13 +000014090 * xmlXPathCtxtCompile:
14091 * @ctxt: an XPath context
14092 * @str: the XPath expression
14093 *
14094 * Compile an XPath expression
14095 *
14096 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14097 * the caller has to free the object.
14098 */
14099xmlXPathCompExprPtr
14100xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14101 xmlXPathParserContextPtr pctxt;
14102 xmlXPathCompExprPtr comp;
14103
Daniel Veillard56de87e2005-02-16 00:22:29 +000014104#ifdef XPATH_STREAMING
14105 comp = xmlXPathTryStreamCompile(ctxt, str);
14106 if (comp != NULL)
14107 return(comp);
14108#endif
14109
Daniel Veillard4773df22004-01-23 13:15:13 +000014110 xmlXPathInit();
14111
14112 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014113 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000014114
14115 if( pctxt->error != XPATH_EXPRESSION_OK )
14116 {
14117 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000014118 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000014119 }
14120
14121 if (*pctxt->cur != 0) {
14122 /*
14123 * aleksey: in some cases this line prints *second* error message
14124 * (see bug #78858) and probably this should be fixed.
14125 * However, we are not sure that all error messages are printed
14126 * out in other places. It's not critical so we leave it as-is for now
14127 */
14128 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14129 comp = NULL;
14130 } else {
14131 comp = pctxt->comp;
14132 pctxt->comp = NULL;
14133 }
14134 xmlXPathFreeParserContext(pctxt);
14135 if (comp != NULL) {
14136 comp->expr = xmlStrdup(str);
14137#ifdef DEBUG_EVAL_COUNTS
14138 comp->string = xmlStrdup(str);
14139 comp->nb = 0;
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014140#endif
14141 if ((comp->nbStep > 2) &&
14142 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14143 {
14144 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14145 }
Kasimier T. Buchcikdf0ba262006-05-30 19:45:37 +000014146 }
Daniel Veillard4773df22004-01-23 13:15:13 +000014147 return(comp);
14148}
14149
14150/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014151 * xmlXPathCompile:
14152 * @str: the XPath expression
14153 *
14154 * Compile an XPath expression
14155 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000014156 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014157 * the caller has to free the object.
14158 */
14159xmlXPathCompExprPtr
14160xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000014161 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014162}
14163
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014164/**
14165 * xmlXPathCompiledEval:
14166 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000014167 * @ctx: the XPath context
14168 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014169 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000014170 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014171 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000014172 * the caller has to free the object.
14173 */
14174xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014175xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000014176 xmlXPathParserContextPtr ctxt;
14177 xmlXPathObjectPtr res, tmp, init = NULL;
14178 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000014179#ifndef LIBXML_THREAD_ENABLED
14180 static int reentance = 0;
14181#endif
Owen Taylor3473f882001-02-23 17:55:21 +000014182
William M. Brackf13f77f2004-11-12 16:03:48 +000014183 CHECK_CTXT(ctx)
14184
14185 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014186 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000014187 xmlXPathInit();
14188
Daniel Veillard81463942001-10-16 12:34:39 +000014189#ifndef LIBXML_THREAD_ENABLED
14190 reentance++;
14191 if (reentance > 1)
14192 xmlXPathDisableOptimizer = 1;
14193#endif
14194
Daniel Veillardf06307e2001-07-03 10:35:50 +000014195#ifdef DEBUG_EVAL_COUNTS
14196 comp->nb++;
14197 if ((comp->string != NULL) && (comp->nb > 100)) {
14198 fprintf(stderr, "100 x %s\n", comp->string);
14199 comp->nb = 0;
14200 }
14201#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014202 ctxt = xmlXPathCompParserContext(comp, ctx);
14203 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014204
14205 if (ctxt->value == NULL) {
14206 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014207 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000014208 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000014209 } else {
14210 res = valuePop(ctxt);
14211 }
14212
Daniel Veillardf06307e2001-07-03 10:35:50 +000014213
Owen Taylor3473f882001-02-23 17:55:21 +000014214 do {
14215 tmp = valuePop(ctxt);
14216 if (tmp != NULL) {
14217 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014218 stack++;
14219 xmlXPathReleaseObject(ctx, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014220 }
14221 } while (tmp != NULL);
14222 if ((stack != 0) && (res != NULL)) {
14223 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014224 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000014225 stack);
14226 }
14227 if (ctxt->error != XPATH_EXPRESSION_OK) {
14228 xmlXPathFreeObject(res);
14229 res = NULL;
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014230 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014231 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014232 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000014233#ifndef LIBXML_THREAD_ENABLED
14234 reentance--;
14235#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014236 return(res);
14237}
14238
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014239/**
14240 * xmlXPathEvalExpr:
14241 * @ctxt: the XPath Parser context
14242 *
14243 * Parse and evaluate an XPath expression in the given context,
14244 * then push the result on the context stack
14245 */
14246void
14247xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000014248#ifdef XPATH_STREAMING
14249 xmlXPathCompExprPtr comp;
14250#endif
14251
Daniel Veillarda82b1822004-11-08 16:24:57 +000014252 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014253
14254#ifdef XPATH_STREAMING
14255 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14256 if (comp != NULL) {
14257 if (ctxt->comp != NULL)
14258 xmlXPathFreeCompExpr(ctxt->comp);
14259 ctxt->comp = comp;
14260 if (ctxt->cur != NULL)
14261 while (*ctxt->cur != 0) ctxt->cur++;
14262 } else
14263#endif
14264 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000014265 xmlXPathCompileExpr(ctxt, 1);
Kasimier T. Buchcik7cb3fa92006-06-06 15:27:46 +000014266 if ((ctxt->comp != NULL) &&
14267 (ctxt->comp->nbStep > 2) &&
Kasimier T. Buchcik080152c2006-06-06 09:42:15 +000014268 (xmlXPathCanRewriteDosExpression(ctxt->comp->expr) == 1))
14269 {
14270 xmlXPathRewriteDOSExpression(ctxt->comp,
14271 &ctxt->comp->steps[comp->last]);
14272 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000014273 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000014274 CHECK_ERROR;
Kasimier T. Buchcik75af2a82006-05-30 09:29:23 +000014275 xmlXPathRunEval(ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000014276}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014277
14278/**
14279 * xmlXPathEval:
14280 * @str: the XPath expression
14281 * @ctx: the XPath context
14282 *
14283 * Evaluate the XPath Location Path in the given context.
14284 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000014285 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014286 * the caller has to free the object.
14287 */
14288xmlXPathObjectPtr
14289xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14290 xmlXPathParserContextPtr ctxt;
14291 xmlXPathObjectPtr res, tmp, init = NULL;
14292 int stack = 0;
14293
William M. Brackf13f77f2004-11-12 16:03:48 +000014294 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014295
William M. Brackf13f77f2004-11-12 16:03:48 +000014296 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014297
14298 ctxt = xmlXPathNewParserContext(str, ctx);
14299 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014300
14301 if (ctxt->value == NULL) {
14302 xmlGenericError(xmlGenericErrorContext,
14303 "xmlXPathEval: evaluation failed\n");
14304 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000014305 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14306#ifdef XPATH_STREAMING
14307 && (ctxt->comp->stream == NULL)
14308#endif
14309 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014310 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14311 res = NULL;
14312 } else {
14313 res = valuePop(ctxt);
14314 }
14315
14316 do {
14317 tmp = valuePop(ctxt);
14318 if (tmp != NULL) {
14319 if (tmp != init)
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014320 stack++;
14321 xmlXPathReleaseObject(ctx, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000014322 }
14323 } while (tmp != NULL);
14324 if ((stack != 0) && (res != NULL)) {
14325 xmlGenericError(xmlGenericErrorContext,
14326 "xmlXPathEval: %d object left on the stack\n",
14327 stack);
14328 }
14329 if (ctxt->error != XPATH_EXPRESSION_OK) {
14330 xmlXPathFreeObject(res);
14331 res = NULL;
14332 }
14333
Owen Taylor3473f882001-02-23 17:55:21 +000014334 xmlXPathFreeParserContext(ctxt);
14335 return(res);
14336}
14337
14338/**
14339 * xmlXPathEvalExpression:
14340 * @str: the XPath expression
14341 * @ctxt: the XPath context
14342 *
14343 * Evaluate the XPath expression in the given context.
14344 *
14345 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14346 * the caller has to free the object.
14347 */
14348xmlXPathObjectPtr
14349xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14350 xmlXPathParserContextPtr pctxt;
14351 xmlXPathObjectPtr res, tmp;
14352 int stack = 0;
14353
William M. Brackf13f77f2004-11-12 16:03:48 +000014354 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000014355
William M. Brackf13f77f2004-11-12 16:03:48 +000014356 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000014357
14358 pctxt = xmlXPathNewParserContext(str, ctxt);
14359 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000014360
14361 if (*pctxt->cur != 0) {
14362 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14363 res = NULL;
14364 } else {
14365 res = valuePop(pctxt);
14366 }
14367 do {
14368 tmp = valuePop(pctxt);
14369 if (tmp != NULL) {
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014370 xmlXPathReleaseObject(ctxt, tmp);
Owen Taylor3473f882001-02-23 17:55:21 +000014371 stack++;
14372 }
14373 } while (tmp != NULL);
14374 if ((stack != 0) && (res != NULL)) {
14375 xmlGenericError(xmlGenericErrorContext,
14376 "xmlXPathEvalExpression: %d object left on the stack\n",
14377 stack);
14378 }
14379 xmlXPathFreeParserContext(pctxt);
14380 return(res);
14381}
14382
Daniel Veillard42766c02002-08-22 20:52:17 +000014383/************************************************************************
14384 * *
14385 * Extra functions not pertaining to the XPath spec *
14386 * *
14387 ************************************************************************/
14388/**
14389 * xmlXPathEscapeUriFunction:
14390 * @ctxt: the XPath Parser context
14391 * @nargs: the number of arguments
14392 *
14393 * Implement the escape-uri() XPath function
14394 * string escape-uri(string $str, bool $escape-reserved)
14395 *
14396 * This function applies the URI escaping rules defined in section 2 of [RFC
14397 * 2396] to the string supplied as $uri-part, which typically represents all
14398 * or part of a URI. The effect of the function is to replace any special
14399 * character in the string by an escape sequence of the form %xx%yy...,
14400 * where xxyy... is the hexadecimal representation of the octets used to
14401 * represent the character in UTF-8.
14402 *
14403 * The set of characters that are escaped depends on the setting of the
14404 * boolean argument $escape-reserved.
14405 *
14406 * If $escape-reserved is true, all characters are escaped other than lower
14407 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14408 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14409 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14410 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14411 * A-F).
14412 *
14413 * If $escape-reserved is false, the behavior differs in that characters
14414 * referred to in [RFC 2396] as reserved characters are not escaped. These
14415 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14416 *
14417 * [RFC 2396] does not define whether escaped URIs should use lower case or
14418 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14419 * compared using string comparison functions, this function must always use
14420 * the upper-case letters A-F.
14421 *
14422 * Generally, $escape-reserved should be set to true when escaping a string
14423 * that is to form a single part of a URI, and to false when escaping an
14424 * entire URI or URI reference.
14425 *
14426 * In the case of non-ascii characters, the string is encoded according to
14427 * utf-8 and then converted according to RFC 2396.
14428 *
14429 * Examples
14430 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14431 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14432 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14433 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14434 *
14435 */
Daniel Veillard118aed72002-09-24 14:13:13 +000014436static void
Daniel Veillard42766c02002-08-22 20:52:17 +000014437xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14438 xmlXPathObjectPtr str;
14439 int escape_reserved;
14440 xmlBufferPtr target;
14441 xmlChar *cptr;
14442 xmlChar escape[4];
14443
14444 CHECK_ARITY(2);
14445
14446 escape_reserved = xmlXPathPopBoolean(ctxt);
14447
14448 CAST_TO_STRING;
14449 str = valuePop(ctxt);
14450
14451 target = xmlBufferCreate();
14452
14453 escape[0] = '%';
14454 escape[3] = 0;
14455
14456 if (target) {
14457 for (cptr = str->stringval; *cptr; cptr++) {
14458 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14459 (*cptr >= 'a' && *cptr <= 'z') ||
14460 (*cptr >= '0' && *cptr <= '9') ||
14461 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14462 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14463 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14464 (*cptr == '%' &&
14465 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14466 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14467 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14468 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14469 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14470 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14471 (!escape_reserved &&
14472 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14473 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14474 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14475 *cptr == ','))) {
14476 xmlBufferAdd(target, cptr, 1);
14477 } else {
14478 if ((*cptr >> 4) < 10)
14479 escape[1] = '0' + (*cptr >> 4);
14480 else
14481 escape[1] = 'A' - 10 + (*cptr >> 4);
14482 if ((*cptr & 0xF) < 10)
14483 escape[2] = '0' + (*cptr & 0xF);
14484 else
14485 escape[2] = 'A' - 10 + (*cptr & 0xF);
14486
14487 xmlBufferAdd(target, &escape[0], 3);
14488 }
14489 }
14490 }
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014491 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14492 xmlBufferContent(target)));
Daniel Veillard42766c02002-08-22 20:52:17 +000014493 xmlBufferFree(target);
Kasimier T. Buchcika7248442006-05-29 16:15:36 +000014494 xmlXPathReleaseObject(ctxt->context, str);
Daniel Veillard42766c02002-08-22 20:52:17 +000014495}
14496
Owen Taylor3473f882001-02-23 17:55:21 +000014497/**
14498 * xmlXPathRegisterAllFunctions:
14499 * @ctxt: the XPath context
14500 *
14501 * Registers all default XPath functions in this context
14502 */
14503void
14504xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14505{
14506 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14507 xmlXPathBooleanFunction);
14508 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14509 xmlXPathCeilingFunction);
14510 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14511 xmlXPathCountFunction);
14512 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14513 xmlXPathConcatFunction);
14514 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14515 xmlXPathContainsFunction);
14516 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14517 xmlXPathIdFunction);
14518 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14519 xmlXPathFalseFunction);
14520 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14521 xmlXPathFloorFunction);
14522 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14523 xmlXPathLastFunction);
14524 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14525 xmlXPathLangFunction);
14526 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14527 xmlXPathLocalNameFunction);
14528 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14529 xmlXPathNotFunction);
14530 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14531 xmlXPathNameFunction);
14532 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14533 xmlXPathNamespaceURIFunction);
14534 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14535 xmlXPathNormalizeFunction);
14536 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14537 xmlXPathNumberFunction);
14538 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14539 xmlXPathPositionFunction);
14540 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14541 xmlXPathRoundFunction);
14542 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14543 xmlXPathStringFunction);
14544 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14545 xmlXPathStringLengthFunction);
14546 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14547 xmlXPathStartsWithFunction);
14548 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14549 xmlXPathSubstringFunction);
14550 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14551 xmlXPathSubstringBeforeFunction);
14552 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14553 xmlXPathSubstringAfterFunction);
14554 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14555 xmlXPathSumFunction);
14556 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14557 xmlXPathTrueFunction);
14558 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14559 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000014560
14561 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14562 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14563 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000014564}
14565
14566#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000014567#define bottom_xpath
14568#include "elfgcchack.h"