blob: 43a8070b93f7b8b4f98dfb83486a529c4b9678db [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
5 *
6 * 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/*
80* XP_FAST_NON_ELEM_COMPARISON:
81* 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*/
88#define XP_FAST_NON_ELEM_COMPARISON
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000089/*
William M. Brackd1757ab2004-10-02 22:07:48 +000090 * TODO:
91 * There are a few spots where some tests are done which depend upon ascii
92 * data. These should be enhanced for full UTF8 support (see particularly
93 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
94 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000095
William M. Brack21e4ef22005-01-02 09:53:13 +000096#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000097/************************************************************************
98 * *
99 * Floating point stuff *
100 * *
101 ************************************************************************/
102
Daniel Veillardc0631a62001-09-20 13:56:06 +0000103#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000104#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000105#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000106#include "trionan.c"
107
Owen Taylor3473f882001-02-23 17:55:21 +0000108/*
Owen Taylor3473f882001-02-23 17:55:21 +0000109 * The lack of portability of this section of the libc is annoying !
110 */
111double xmlXPathNAN = 0;
112double xmlXPathPINF = 1;
113double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000114static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000115static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000116
Owen Taylor3473f882001-02-23 17:55:21 +0000117/**
118 * xmlXPathInit:
119 *
120 * Initialize the XPath environment
121 */
122void
123xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000124 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Bjorn Reese45029602001-08-21 09:23:53 +0000126 xmlXPathPINF = trio_pinf();
127 xmlXPathNINF = trio_ninf();
128 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000129 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000130
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000131 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000132}
133
Daniel Veillardcda96922001-08-21 10:56:31 +0000134/**
135 * xmlXPathIsNaN:
136 * @val: a double value
137 *
138 * Provides a portable isnan() function to detect whether a double
139 * is a NotaNumber. Based on trio code
140 * http://sourceforge.net/projects/ctrio/
141 *
142 * Returns 1 if the value is a NaN, 0 otherwise
143 */
144int
145xmlXPathIsNaN(double val) {
146 return(trio_isnan(val));
147}
148
149/**
150 * xmlXPathIsInf:
151 * @val: a double value
152 *
153 * Provides a portable isinf() function to detect whether a double
154 * is a +Infinite or -Infinite. Based on trio code
155 * http://sourceforge.net/projects/ctrio/
156 *
157 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
158 */
159int
160xmlXPathIsInf(double val) {
161 return(trio_isinf(val));
162}
163
Daniel Veillard4432df22003-09-28 18:58:27 +0000164#endif /* SCHEMAS or XPATH */
165#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000166/**
167 * xmlXPathGetSign:
168 * @val: a double value
169 *
170 * Provides a portable function to detect the sign of a double
171 * Modified from trio code
172 * http://sourceforge.net/projects/ctrio/
173 *
174 * Returns 1 if the value is Negative, 0 if positive
175 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000176static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000177xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000178 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000179}
180
181
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000182/*
183 * TODO: when compatibility allows remove all "fake node libxslt" strings
184 * the test should just be name[0] = ' '
185 */
186/* #define DEBUG */
187/* #define DEBUG_STEP */
188/* #define DEBUG_STEP_NTH */
189/* #define DEBUG_EXPR */
190/* #define DEBUG_EVAL_COUNTS */
191
192static xmlNs xmlXPathXMLNamespaceStruct = {
193 NULL,
194 XML_NAMESPACE_DECL,
195 XML_XML_NAMESPACE,
196 BAD_CAST "xml",
197 NULL
198};
199static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
200#ifndef LIBXML_THREAD_ENABLED
201/*
202 * Optimizer is disabled only when threaded apps are detected while
203 * the library ain't compiled for thread safety.
204 */
205static int xmlXPathDisableOptimizer = 0;
206#endif
207
Owen Taylor3473f882001-02-23 17:55:21 +0000208/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000209 * *
210 * Error handling routines *
211 * *
212 ************************************************************************/
213
Daniel Veillard24505b02005-07-28 23:49:35 +0000214/**
215 * XP_ERRORNULL:
216 * @X: the error code
217 *
218 * Macro to raise an XPath error and return NULL.
219 */
220#define XP_ERRORNULL(X) \
221 { xmlXPathErr(ctxt, X); return(NULL); }
222
William M. Brack08171912003-12-29 02:52:11 +0000223/*
224 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
225 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000226static const char *xmlXPathErrorMessages[] = {
227 "Ok\n",
228 "Number encoding\n",
229 "Unfinished literal\n",
230 "Start of literal\n",
231 "Expected $ for variable reference\n",
232 "Undefined variable\n",
233 "Invalid predicate\n",
234 "Invalid expression\n",
235 "Missing closing curly brace\n",
236 "Unregistered function\n",
237 "Invalid operand\n",
238 "Invalid type\n",
239 "Invalid number of arguments\n",
240 "Invalid context size\n",
241 "Invalid context position\n",
242 "Memory allocation error\n",
243 "Syntax error\n",
244 "Resource error\n",
245 "Sub resource error\n",
246 "Undefined namespace prefix\n",
247 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000248 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000249 "Invalid or incomplete context\n",
250 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000251};
William M. Brackcd65bc92005-01-06 09:39:18 +0000252#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
253 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000254/**
255 * xmlXPathErrMemory:
256 * @ctxt: an XPath context
257 * @extra: extra informations
258 *
259 * Handle a redefinition of attribute error
260 */
261static void
262xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
263{
264 if (ctxt != NULL) {
265 if (extra) {
266 xmlChar buf[200];
267
268 xmlStrPrintf(buf, 200,
269 BAD_CAST "Memory allocation failed : %s\n",
270 extra);
271 ctxt->lastError.message = (char *) xmlStrdup(buf);
272 } else {
273 ctxt->lastError.message = (char *)
274 xmlStrdup(BAD_CAST "Memory allocation failed\n");
275 }
276 ctxt->lastError.domain = XML_FROM_XPATH;
277 ctxt->lastError.code = XML_ERR_NO_MEMORY;
278 if (ctxt->error != NULL)
279 ctxt->error(ctxt->userData, &ctxt->lastError);
280 } else {
281 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000282 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000283 NULL, NULL, XML_FROM_XPATH,
284 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
285 extra, NULL, NULL, 0, 0,
286 "Memory allocation failed : %s\n", extra);
287 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000288 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000289 NULL, NULL, XML_FROM_XPATH,
290 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
291 NULL, NULL, NULL, 0, 0,
292 "Memory allocation failed\n");
293 }
294}
295
296/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000297 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000298 * @ctxt: an XPath parser context
299 * @extra: extra informations
300 *
301 * Handle a redefinition of attribute error
302 */
303static void
304xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
305{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000306 if (ctxt == NULL)
307 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000308 else {
309 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000310 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000311 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000312}
313
314/**
315 * xmlXPathErr:
316 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000317 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000318 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000319 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000320 */
321void
322xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
323{
William M. Brackcd65bc92005-01-06 09:39:18 +0000324 if ((error < 0) || (error > MAXERRNO))
325 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000326 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000327 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000328 NULL, NULL, XML_FROM_XPATH,
329 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
330 XML_ERR_ERROR, NULL, 0,
331 NULL, NULL, NULL, 0, 0,
332 xmlXPathErrorMessages[error]);
333 return;
334 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000335 ctxt->error = error;
336 if (ctxt->context == NULL) {
337 __xmlRaiseError(NULL, NULL, NULL,
338 NULL, NULL, XML_FROM_XPATH,
339 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
340 XML_ERR_ERROR, NULL, 0,
341 (const char *) ctxt->base, NULL, NULL,
342 ctxt->cur - ctxt->base, 0,
343 xmlXPathErrorMessages[error]);
344 return;
345 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000346 ctxt->context->lastError.domain = XML_FROM_XPATH;
347 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
348 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000349 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000350 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
351 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
352 ctxt->context->lastError.node = ctxt->context->debugNode;
353 if (ctxt->context->error != NULL) {
354 ctxt->context->error(ctxt->context->userData,
355 &ctxt->context->lastError);
356 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000357 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000358 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
359 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
360 XML_ERR_ERROR, NULL, 0,
361 (const char *) ctxt->base, NULL, NULL,
362 ctxt->cur - ctxt->base, 0,
363 xmlXPathErrorMessages[error]);
364 }
365
366}
367
368/**
369 * xmlXPatherror:
370 * @ctxt: the XPath Parser context
371 * @file: the file name
372 * @line: the line number
373 * @no: the error number
374 *
375 * Formats an error message.
376 */
377void
378xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
379 int line ATTRIBUTE_UNUSED, int no) {
380 xmlXPathErr(ctxt, no);
381}
382
383
384/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000385 * *
386 * Parser Types *
387 * *
388 ************************************************************************/
389
390/*
391 * Types are private:
392 */
393
394typedef enum {
395 XPATH_OP_END=0,
396 XPATH_OP_AND,
397 XPATH_OP_OR,
398 XPATH_OP_EQUAL,
399 XPATH_OP_CMP,
400 XPATH_OP_PLUS,
401 XPATH_OP_MULT,
402 XPATH_OP_UNION,
403 XPATH_OP_ROOT,
404 XPATH_OP_NODE,
405 XPATH_OP_RESET,
406 XPATH_OP_COLLECT,
407 XPATH_OP_VALUE,
408 XPATH_OP_VARIABLE,
409 XPATH_OP_FUNCTION,
410 XPATH_OP_ARG,
411 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000412 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000413 XPATH_OP_SORT
414#ifdef LIBXML_XPTR_ENABLED
415 ,XPATH_OP_RANGETO
416#endif
417} xmlXPathOp;
418
419typedef enum {
420 AXIS_ANCESTOR = 1,
421 AXIS_ANCESTOR_OR_SELF,
422 AXIS_ATTRIBUTE,
423 AXIS_CHILD,
424 AXIS_DESCENDANT,
425 AXIS_DESCENDANT_OR_SELF,
426 AXIS_FOLLOWING,
427 AXIS_FOLLOWING_SIBLING,
428 AXIS_NAMESPACE,
429 AXIS_PARENT,
430 AXIS_PRECEDING,
431 AXIS_PRECEDING_SIBLING,
432 AXIS_SELF
433} xmlXPathAxisVal;
434
435typedef enum {
436 NODE_TEST_NONE = 0,
437 NODE_TEST_TYPE = 1,
438 NODE_TEST_PI = 2,
439 NODE_TEST_ALL = 3,
440 NODE_TEST_NS = 4,
441 NODE_TEST_NAME = 5
442} xmlXPathTestVal;
443
444typedef enum {
445 NODE_TYPE_NODE = 0,
446 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
447 NODE_TYPE_TEXT = XML_TEXT_NODE,
448 NODE_TYPE_PI = XML_PI_NODE
449} xmlXPathTypeVal;
450
451
452typedef struct _xmlXPathStepOp xmlXPathStepOp;
453typedef xmlXPathStepOp *xmlXPathStepOpPtr;
454struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000455 xmlXPathOp op; /* The identifier of the operation */
456 int ch1; /* First child */
457 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000458 int value;
459 int value2;
460 int value3;
461 void *value4;
462 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000463 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000464 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000465};
466
467struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000468 int nbStep; /* Number of steps in this expression */
469 int maxStep; /* Maximum number of steps allocated */
470 xmlXPathStepOp *steps; /* ops for computation of this expression */
471 int last; /* index of last step in expression */
472 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000473 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000474#ifdef DEBUG_EVAL_COUNTS
475 int nb;
476 xmlChar *string;
477#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000478#ifdef XPATH_STREAMING
479 xmlPatternPtr stream;
480#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000481};
482
483/************************************************************************
484 * *
485 * Parser Type functions *
486 * *
487 ************************************************************************/
488
489/**
490 * xmlXPathNewCompExpr:
491 *
492 * Create a new Xpath component
493 *
494 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
495 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000496static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000497xmlXPathNewCompExpr(void) {
498 xmlXPathCompExprPtr cur;
499
500 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
501 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000502 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000503 return(NULL);
504 }
505 memset(cur, 0, sizeof(xmlXPathCompExpr));
506 cur->maxStep = 10;
507 cur->nbStep = 0;
508 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
509 sizeof(xmlXPathStepOp));
510 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000511 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000512 xmlFree(cur);
513 return(NULL);
514 }
515 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
516 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000517#ifdef DEBUG_EVAL_COUNTS
518 cur->nb = 0;
519#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000520 return(cur);
521}
522
523/**
524 * xmlXPathFreeCompExpr:
525 * @comp: an XPATH comp
526 *
527 * Free up the memory allocated by @comp
528 */
529void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000530xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
531{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000532 xmlXPathStepOpPtr op;
533 int i;
534
535 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000536 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000537 if (comp->dict == NULL) {
538 for (i = 0; i < comp->nbStep; i++) {
539 op = &comp->steps[i];
540 if (op->value4 != NULL) {
541 if (op->op == XPATH_OP_VALUE)
542 xmlXPathFreeObject(op->value4);
543 else
544 xmlFree(op->value4);
545 }
546 if (op->value5 != NULL)
547 xmlFree(op->value5);
548 }
549 } else {
550 for (i = 0; i < comp->nbStep; i++) {
551 op = &comp->steps[i];
552 if (op->value4 != NULL) {
553 if (op->op == XPATH_OP_VALUE)
554 xmlXPathFreeObject(op->value4);
555 }
556 }
557 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000558 }
559 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000560 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000561 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000562#ifdef DEBUG_EVAL_COUNTS
563 if (comp->string != NULL) {
564 xmlFree(comp->string);
565 }
566#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000567#ifdef XPATH_STREAMING
568 if (comp->stream != NULL) {
569 xmlFreePatternList(comp->stream);
570 }
571#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000572 if (comp->expr != NULL) {
573 xmlFree(comp->expr);
574 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000575
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000576 xmlFree(comp);
577}
578
579/**
580 * xmlXPathCompExprAdd:
581 * @comp: the compiled expression
582 * @ch1: first child index
583 * @ch2: second child index
584 * @op: an op
585 * @value: the first int value
586 * @value2: the second int value
587 * @value3: the third int value
588 * @value4: the first string value
589 * @value5: the second string value
590 *
William M. Brack08171912003-12-29 02:52:11 +0000591 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000592 *
593 * Returns -1 in case of failure, the index otherwise
594 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000595static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000596xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
597 xmlXPathOp op, int value,
598 int value2, int value3, void *value4, void *value5) {
599 if (comp->nbStep >= comp->maxStep) {
600 xmlXPathStepOp *real;
601
602 comp->maxStep *= 2;
603 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
604 comp->maxStep * sizeof(xmlXPathStepOp));
605 if (real == NULL) {
606 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000607 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000608 return(-1);
609 }
610 comp->steps = real;
611 }
612 comp->last = comp->nbStep;
613 comp->steps[comp->nbStep].ch1 = ch1;
614 comp->steps[comp->nbStep].ch2 = ch2;
615 comp->steps[comp->nbStep].op = op;
616 comp->steps[comp->nbStep].value = value;
617 comp->steps[comp->nbStep].value2 = value2;
618 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000619 if ((comp->dict != NULL) &&
620 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
621 (op == XPATH_OP_COLLECT))) {
622 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000623 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000624 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000625 xmlFree(value4);
626 } else
627 comp->steps[comp->nbStep].value4 = NULL;
628 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000629 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000630 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000631 xmlFree(value5);
632 } else
633 comp->steps[comp->nbStep].value5 = NULL;
634 } else {
635 comp->steps[comp->nbStep].value4 = value4;
636 comp->steps[comp->nbStep].value5 = value5;
637 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000638 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000639 return(comp->nbStep++);
640}
641
Daniel Veillardf06307e2001-07-03 10:35:50 +0000642/**
643 * xmlXPathCompSwap:
644 * @comp: the compiled expression
645 * @op: operation index
646 *
647 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000648 */
649static void
650xmlXPathCompSwap(xmlXPathStepOpPtr op) {
651 int tmp;
652
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000653#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000654 /*
655 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000656 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000657 * application
658 */
659 if (xmlXPathDisableOptimizer)
660 return;
661#endif
662
Daniel Veillardf06307e2001-07-03 10:35:50 +0000663 tmp = op->ch1;
664 op->ch1 = op->ch2;
665 op->ch2 = tmp;
666}
667
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000668#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
669 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
670 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000671#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
672 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
673 (op), (val), (val2), (val3), (val4), (val5))
674
675#define PUSH_LEAVE_EXPR(op, val, val2) \
676xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
677
678#define PUSH_UNARY_EXPR(op, ch, val, val2) \
679xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
680
681#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000682xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
683 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000684
685/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000686 * *
687 * Debugging related functions *
688 * *
689 ************************************************************************/
690
Owen Taylor3473f882001-02-23 17:55:21 +0000691#define STRANGE \
692 xmlGenericError(xmlGenericErrorContext, \
693 "Internal error at %s:%d\n", \
694 __FILE__, __LINE__);
695
696#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000697static void
698xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000699 int i;
700 char shift[100];
701
702 for (i = 0;((i < depth) && (i < 25));i++)
703 shift[2 * i] = shift[2 * i + 1] = ' ';
704 shift[2 * i] = shift[2 * i + 1] = 0;
705 if (cur == NULL) {
706 fprintf(output, shift);
707 fprintf(output, "Node is NULL !\n");
708 return;
709
710 }
711
712 if ((cur->type == XML_DOCUMENT_NODE) ||
713 (cur->type == XML_HTML_DOCUMENT_NODE)) {
714 fprintf(output, shift);
715 fprintf(output, " /\n");
716 } else if (cur->type == XML_ATTRIBUTE_NODE)
717 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
718 else
719 xmlDebugDumpOneNode(output, cur, depth);
720}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000721static void
722xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000723 xmlNodePtr tmp;
724 int i;
725 char shift[100];
726
727 for (i = 0;((i < depth) && (i < 25));i++)
728 shift[2 * i] = shift[2 * i + 1] = ' ';
729 shift[2 * i] = shift[2 * i + 1] = 0;
730 if (cur == NULL) {
731 fprintf(output, shift);
732 fprintf(output, "Node is NULL !\n");
733 return;
734
735 }
736
737 while (cur != NULL) {
738 tmp = cur;
739 cur = cur->next;
740 xmlDebugDumpOneNode(output, tmp, depth);
741 }
742}
Owen Taylor3473f882001-02-23 17:55:21 +0000743
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000744static void
745xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000746 int i;
747 char shift[100];
748
749 for (i = 0;((i < depth) && (i < 25));i++)
750 shift[2 * i] = shift[2 * i + 1] = ' ';
751 shift[2 * i] = shift[2 * i + 1] = 0;
752
753 if (cur == NULL) {
754 fprintf(output, shift);
755 fprintf(output, "NodeSet is NULL !\n");
756 return;
757
758 }
759
Daniel Veillard911f49a2001-04-07 15:39:35 +0000760 if (cur != NULL) {
761 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
762 for (i = 0;i < cur->nodeNr;i++) {
763 fprintf(output, shift);
764 fprintf(output, "%d", i + 1);
765 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
766 }
Owen Taylor3473f882001-02-23 17:55:21 +0000767 }
768}
769
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000770static void
771xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000772 int i;
773 char shift[100];
774
775 for (i = 0;((i < depth) && (i < 25));i++)
776 shift[2 * i] = shift[2 * i + 1] = ' ';
777 shift[2 * i] = shift[2 * i + 1] = 0;
778
779 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
780 fprintf(output, shift);
781 fprintf(output, "Value Tree is NULL !\n");
782 return;
783
784 }
785
786 fprintf(output, shift);
787 fprintf(output, "%d", i + 1);
788 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
789}
Owen Taylor3473f882001-02-23 17:55:21 +0000790#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000791static void
792xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000793 int i;
794 char shift[100];
795
796 for (i = 0;((i < depth) && (i < 25));i++)
797 shift[2 * i] = shift[2 * i + 1] = ' ';
798 shift[2 * i] = shift[2 * i + 1] = 0;
799
800 if (cur == NULL) {
801 fprintf(output, shift);
802 fprintf(output, "LocationSet is NULL !\n");
803 return;
804
805 }
806
807 for (i = 0;i < cur->locNr;i++) {
808 fprintf(output, shift);
809 fprintf(output, "%d : ", i + 1);
810 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
811 }
812}
Daniel Veillard017b1082001-06-21 11:20:21 +0000813#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000814
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000815/**
816 * xmlXPathDebugDumpObject:
817 * @output: the FILE * to dump the output
818 * @cur: the object to inspect
819 * @depth: indentation level
820 *
821 * Dump the content of the object for debugging purposes
822 */
823void
824xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000825 int i;
826 char shift[100];
827
Daniel Veillarda82b1822004-11-08 16:24:57 +0000828 if (output == NULL) return;
829
Owen Taylor3473f882001-02-23 17:55:21 +0000830 for (i = 0;((i < depth) && (i < 25));i++)
831 shift[2 * i] = shift[2 * i + 1] = ' ';
832 shift[2 * i] = shift[2 * i + 1] = 0;
833
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000834
835 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000836
837 if (cur == NULL) {
838 fprintf(output, "Object is empty (NULL)\n");
839 return;
840 }
841 switch(cur->type) {
842 case XPATH_UNDEFINED:
843 fprintf(output, "Object is uninitialized\n");
844 break;
845 case XPATH_NODESET:
846 fprintf(output, "Object is a Node Set :\n");
847 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
848 break;
849 case XPATH_XSLT_TREE:
850 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000851 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000852 break;
853 case XPATH_BOOLEAN:
854 fprintf(output, "Object is a Boolean : ");
855 if (cur->boolval) fprintf(output, "true\n");
856 else fprintf(output, "false\n");
857 break;
858 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000859 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000860 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000861 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000862 break;
863 case -1:
864 fprintf(output, "Object is a number : -Infinity\n");
865 break;
866 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000867 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000868 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000869 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
870 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000871 } else {
872 fprintf(output, "Object is a number : %0g\n", cur->floatval);
873 }
874 }
Owen Taylor3473f882001-02-23 17:55:21 +0000875 break;
876 case XPATH_STRING:
877 fprintf(output, "Object is a string : ");
878 xmlDebugDumpString(output, cur->stringval);
879 fprintf(output, "\n");
880 break;
881 case XPATH_POINT:
882 fprintf(output, "Object is a point : index %d in node", cur->index);
883 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
884 fprintf(output, "\n");
885 break;
886 case XPATH_RANGE:
887 if ((cur->user2 == NULL) ||
888 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
889 fprintf(output, "Object is a collapsed range :\n");
890 fprintf(output, shift);
891 if (cur->index >= 0)
892 fprintf(output, "index %d in ", cur->index);
893 fprintf(output, "node\n");
894 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
895 depth + 1);
896 } else {
897 fprintf(output, "Object is a range :\n");
898 fprintf(output, shift);
899 fprintf(output, "From ");
900 if (cur->index >= 0)
901 fprintf(output, "index %d in ", cur->index);
902 fprintf(output, "node\n");
903 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
904 depth + 1);
905 fprintf(output, shift);
906 fprintf(output, "To ");
907 if (cur->index2 >= 0)
908 fprintf(output, "index %d in ", cur->index2);
909 fprintf(output, "node\n");
910 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
911 depth + 1);
912 fprintf(output, "\n");
913 }
914 break;
915 case XPATH_LOCATIONSET:
916#if defined(LIBXML_XPTR_ENABLED)
917 fprintf(output, "Object is a Location Set:\n");
918 xmlXPathDebugDumpLocationSet(output,
919 (xmlLocationSetPtr) cur->user, depth);
920#endif
921 break;
922 case XPATH_USERS:
923 fprintf(output, "Object is user defined\n");
924 break;
925 }
926}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000927
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000928static void
929xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000930 xmlXPathStepOpPtr op, int depth) {
931 int i;
932 char shift[100];
933
934 for (i = 0;((i < depth) && (i < 25));i++)
935 shift[2 * i] = shift[2 * i + 1] = ' ';
936 shift[2 * i] = shift[2 * i + 1] = 0;
937
938 fprintf(output, shift);
939 if (op == NULL) {
940 fprintf(output, "Step is NULL\n");
941 return;
942 }
943 switch (op->op) {
944 case XPATH_OP_END:
945 fprintf(output, "END"); break;
946 case XPATH_OP_AND:
947 fprintf(output, "AND"); break;
948 case XPATH_OP_OR:
949 fprintf(output, "OR"); break;
950 case XPATH_OP_EQUAL:
951 if (op->value)
952 fprintf(output, "EQUAL =");
953 else
954 fprintf(output, "EQUAL !=");
955 break;
956 case XPATH_OP_CMP:
957 if (op->value)
958 fprintf(output, "CMP <");
959 else
960 fprintf(output, "CMP >");
961 if (!op->value2)
962 fprintf(output, "=");
963 break;
964 case XPATH_OP_PLUS:
965 if (op->value == 0)
966 fprintf(output, "PLUS -");
967 else if (op->value == 1)
968 fprintf(output, "PLUS +");
969 else if (op->value == 2)
970 fprintf(output, "PLUS unary -");
971 else if (op->value == 3)
972 fprintf(output, "PLUS unary - -");
973 break;
974 case XPATH_OP_MULT:
975 if (op->value == 0)
976 fprintf(output, "MULT *");
977 else if (op->value == 1)
978 fprintf(output, "MULT div");
979 else
980 fprintf(output, "MULT mod");
981 break;
982 case XPATH_OP_UNION:
983 fprintf(output, "UNION"); break;
984 case XPATH_OP_ROOT:
985 fprintf(output, "ROOT"); break;
986 case XPATH_OP_NODE:
987 fprintf(output, "NODE"); break;
988 case XPATH_OP_RESET:
989 fprintf(output, "RESET"); break;
990 case XPATH_OP_SORT:
991 fprintf(output, "SORT"); break;
992 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000993 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
994 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
995 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000996 const xmlChar *prefix = op->value4;
997 const xmlChar *name = op->value5;
998
999 fprintf(output, "COLLECT ");
1000 switch (axis) {
1001 case AXIS_ANCESTOR:
1002 fprintf(output, " 'ancestors' "); break;
1003 case AXIS_ANCESTOR_OR_SELF:
1004 fprintf(output, " 'ancestors-or-self' "); break;
1005 case AXIS_ATTRIBUTE:
1006 fprintf(output, " 'attributes' "); break;
1007 case AXIS_CHILD:
1008 fprintf(output, " 'child' "); break;
1009 case AXIS_DESCENDANT:
1010 fprintf(output, " 'descendant' "); break;
1011 case AXIS_DESCENDANT_OR_SELF:
1012 fprintf(output, " 'descendant-or-self' "); break;
1013 case AXIS_FOLLOWING:
1014 fprintf(output, " 'following' "); break;
1015 case AXIS_FOLLOWING_SIBLING:
1016 fprintf(output, " 'following-siblings' "); break;
1017 case AXIS_NAMESPACE:
1018 fprintf(output, " 'namespace' "); break;
1019 case AXIS_PARENT:
1020 fprintf(output, " 'parent' "); break;
1021 case AXIS_PRECEDING:
1022 fprintf(output, " 'preceding' "); break;
1023 case AXIS_PRECEDING_SIBLING:
1024 fprintf(output, " 'preceding-sibling' "); break;
1025 case AXIS_SELF:
1026 fprintf(output, " 'self' "); break;
1027 }
1028 switch (test) {
1029 case NODE_TEST_NONE:
1030 fprintf(output, "'none' "); break;
1031 case NODE_TEST_TYPE:
1032 fprintf(output, "'type' "); break;
1033 case NODE_TEST_PI:
1034 fprintf(output, "'PI' "); break;
1035 case NODE_TEST_ALL:
1036 fprintf(output, "'all' "); break;
1037 case NODE_TEST_NS:
1038 fprintf(output, "'namespace' "); break;
1039 case NODE_TEST_NAME:
1040 fprintf(output, "'name' "); break;
1041 }
1042 switch (type) {
1043 case NODE_TYPE_NODE:
1044 fprintf(output, "'node' "); break;
1045 case NODE_TYPE_COMMENT:
1046 fprintf(output, "'comment' "); break;
1047 case NODE_TYPE_TEXT:
1048 fprintf(output, "'text' "); break;
1049 case NODE_TYPE_PI:
1050 fprintf(output, "'PI' "); break;
1051 }
1052 if (prefix != NULL)
1053 fprintf(output, "%s:", prefix);
1054 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001055 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001056 break;
1057
1058 }
1059 case XPATH_OP_VALUE: {
1060 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1061
1062 fprintf(output, "ELEM ");
1063 xmlXPathDebugDumpObject(output, object, 0);
1064 goto finish;
1065 }
1066 case XPATH_OP_VARIABLE: {
1067 const xmlChar *prefix = op->value5;
1068 const xmlChar *name = op->value4;
1069
1070 if (prefix != NULL)
1071 fprintf(output, "VARIABLE %s:%s", prefix, name);
1072 else
1073 fprintf(output, "VARIABLE %s", name);
1074 break;
1075 }
1076 case XPATH_OP_FUNCTION: {
1077 int nbargs = op->value;
1078 const xmlChar *prefix = op->value5;
1079 const xmlChar *name = op->value4;
1080
1081 if (prefix != NULL)
1082 fprintf(output, "FUNCTION %s:%s(%d args)",
1083 prefix, name, nbargs);
1084 else
1085 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1086 break;
1087 }
1088 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1089 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001090 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001091#ifdef LIBXML_XPTR_ENABLED
1092 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1093#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001094 default:
1095 fprintf(output, "UNKNOWN %d\n", op->op); return;
1096 }
1097 fprintf(output, "\n");
1098finish:
1099 if (op->ch1 >= 0)
1100 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1101 if (op->ch2 >= 0)
1102 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1103}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001104
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001105/**
1106 * xmlXPathDebugDumpCompExpr:
1107 * @output: the FILE * for the output
1108 * @comp: the precompiled XPath expression
1109 * @depth: the indentation level.
1110 *
1111 * Dumps the tree of the compiled XPath expression.
1112 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001113void
1114xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1115 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001116 int i;
1117 char shift[100];
1118
Daniel Veillarda82b1822004-11-08 16:24:57 +00001119 if ((output == NULL) || (comp == NULL)) return;
1120
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001121 for (i = 0;((i < depth) && (i < 25));i++)
1122 shift[2 * i] = shift[2 * i + 1] = ' ';
1123 shift[2 * i] = shift[2 * i + 1] = 0;
1124
1125 fprintf(output, shift);
1126
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001127 fprintf(output, "Compiled Expression : %d elements\n",
1128 comp->nbStep);
1129 i = comp->last;
1130 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1131}
Daniel Veillard017b1082001-06-21 11:20:21 +00001132#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001133
1134/************************************************************************
1135 * *
1136 * Parser stacks related functions and macros *
1137 * *
1138 ************************************************************************/
1139
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001140/**
1141 * valuePop:
1142 * @ctxt: an XPath evaluation context
1143 *
1144 * Pops the top XPath object from the value stack
1145 *
1146 * Returns the XPath object just removed
1147 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001148xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00001149valuePop(xmlXPathParserContextPtr ctxt)
1150{
1151 xmlXPathObjectPtr ret;
1152
Daniel Veillarda82b1822004-11-08 16:24:57 +00001153 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00001154 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001155 ctxt->valueNr--;
1156 if (ctxt->valueNr > 0)
1157 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1158 else
1159 ctxt->value = NULL;
1160 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001161 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001162 return (ret);
1163}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001164/**
1165 * valuePush:
1166 * @ctxt: an XPath evaluation context
1167 * @value: the XPath object
1168 *
1169 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001170 *
1171 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001172 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001173int
Daniel Veillard1c732d22002-11-30 11:22:59 +00001174valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1175{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001176 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001177 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001178 xmlXPathObjectPtr *tmp;
1179
1180 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1181 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001182 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001183 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001184 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1185 return (0);
1186 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001187 ctxt->valueMax *= 2;
1188 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001189 }
1190 ctxt->valueTab[ctxt->valueNr] = value;
1191 ctxt->value = value;
1192 return (ctxt->valueNr++);
1193}
Owen Taylor3473f882001-02-23 17:55:21 +00001194
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001195/**
1196 * xmlXPathPopBoolean:
1197 * @ctxt: an XPath parser context
1198 *
1199 * Pops a boolean from the stack, handling conversion if needed.
1200 * Check error with #xmlXPathCheckError.
1201 *
1202 * Returns the boolean
1203 */
1204int
1205xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1206 xmlXPathObjectPtr obj;
1207 int ret;
1208
1209 obj = valuePop(ctxt);
1210 if (obj == NULL) {
1211 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1212 return(0);
1213 }
William M. Brack08171912003-12-29 02:52:11 +00001214 if (obj->type != XPATH_BOOLEAN)
1215 ret = xmlXPathCastToBoolean(obj);
1216 else
1217 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001218 xmlXPathFreeObject(obj);
1219 return(ret);
1220}
1221
1222/**
1223 * xmlXPathPopNumber:
1224 * @ctxt: an XPath parser context
1225 *
1226 * Pops a number from the stack, handling conversion if needed.
1227 * Check error with #xmlXPathCheckError.
1228 *
1229 * Returns the number
1230 */
1231double
1232xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1233 xmlXPathObjectPtr obj;
1234 double ret;
1235
1236 obj = valuePop(ctxt);
1237 if (obj == NULL) {
1238 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1239 return(0);
1240 }
William M. Brack08171912003-12-29 02:52:11 +00001241 if (obj->type != XPATH_NUMBER)
1242 ret = xmlXPathCastToNumber(obj);
1243 else
1244 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001245 xmlXPathFreeObject(obj);
1246 return(ret);
1247}
1248
1249/**
1250 * xmlXPathPopString:
1251 * @ctxt: an XPath parser context
1252 *
1253 * Pops a string from the stack, handling conversion if needed.
1254 * Check error with #xmlXPathCheckError.
1255 *
1256 * Returns the string
1257 */
1258xmlChar *
1259xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1260 xmlXPathObjectPtr obj;
1261 xmlChar * ret;
1262
1263 obj = valuePop(ctxt);
1264 if (obj == NULL) {
1265 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1266 return(NULL);
1267 }
William M. Brack08171912003-12-29 02:52:11 +00001268 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001269 /* TODO: needs refactoring somewhere else */
1270 if (obj->stringval == ret)
1271 obj->stringval = NULL;
1272 xmlXPathFreeObject(obj);
1273 return(ret);
1274}
1275
1276/**
1277 * xmlXPathPopNodeSet:
1278 * @ctxt: an XPath parser context
1279 *
1280 * Pops a node-set from the stack, handling conversion if needed.
1281 * Check error with #xmlXPathCheckError.
1282 *
1283 * Returns the node-set
1284 */
1285xmlNodeSetPtr
1286xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1287 xmlXPathObjectPtr obj;
1288 xmlNodeSetPtr ret;
1289
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001290 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001291 if (ctxt->value == NULL) {
1292 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1293 return(NULL);
1294 }
1295 if (!xmlXPathStackIsNodeSet(ctxt)) {
1296 xmlXPathSetTypeError(ctxt);
1297 return(NULL);
1298 }
1299 obj = valuePop(ctxt);
1300 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001301#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001302 /* to fix memory leak of not clearing obj->user */
1303 if (obj->boolval && obj->user != NULL)
1304 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001305#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001306 xmlXPathFreeNodeSetList(obj);
1307 return(ret);
1308}
1309
1310/**
1311 * xmlXPathPopExternal:
1312 * @ctxt: an XPath parser context
1313 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001314 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001315 * Check error with #xmlXPathCheckError.
1316 *
1317 * Returns the object
1318 */
1319void *
1320xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1321 xmlXPathObjectPtr obj;
1322 void * ret;
1323
Daniel Veillarda82b1822004-11-08 16:24:57 +00001324 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001325 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1326 return(NULL);
1327 }
1328 if (ctxt->value->type != XPATH_USERS) {
1329 xmlXPathSetTypeError(ctxt);
1330 return(NULL);
1331 }
1332 obj = valuePop(ctxt);
1333 ret = obj->user;
1334 xmlXPathFreeObject(obj);
1335 return(ret);
1336}
1337
Owen Taylor3473f882001-02-23 17:55:21 +00001338/*
1339 * Macros for accessing the content. Those should be used only by the parser,
1340 * and not exported.
1341 *
1342 * Dirty macros, i.e. one need to make assumption on the context to use them
1343 *
1344 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1345 * CUR returns the current xmlChar value, i.e. a 8 bit value
1346 * in ISO-Latin or UTF-8.
1347 * This should be used internally by the parser
1348 * only to compare to ASCII values otherwise it would break when
1349 * running with UTF-8 encoding.
1350 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1351 * to compare on ASCII based substring.
1352 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1353 * strings within the parser.
1354 * CURRENT Returns the current char value, with the full decoding of
1355 * UTF-8 if we are using this mode. It returns an int.
1356 * NEXT Skip to the next character, this does the proper decoding
1357 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1358 * It returns the pointer to the current xmlChar.
1359 */
1360
1361#define CUR (*ctxt->cur)
1362#define SKIP(val) ctxt->cur += (val)
1363#define NXT(val) ctxt->cur[(val)]
1364#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001365#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1366
1367#define COPY_BUF(l,b,i,v) \
1368 if (l == 1) b[i++] = (xmlChar) v; \
1369 else i += xmlCopyChar(l,&b[i],v)
1370
1371#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001372
1373#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001374 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001375
1376#define CURRENT (*ctxt->cur)
1377#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1378
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001379
1380#ifndef DBL_DIG
1381#define DBL_DIG 16
1382#endif
1383#ifndef DBL_EPSILON
1384#define DBL_EPSILON 1E-9
1385#endif
1386
1387#define UPPER_DOUBLE 1E9
1388#define LOWER_DOUBLE 1E-5
1389
1390#define INTEGER_DIGITS DBL_DIG
1391#define FRACTION_DIGITS (DBL_DIG + 1)
1392#define EXPONENT_DIGITS (3 + 2)
1393
1394/**
1395 * xmlXPathFormatNumber:
1396 * @number: number to format
1397 * @buffer: output buffer
1398 * @buffersize: size of output buffer
1399 *
1400 * Convert the number into a string representation.
1401 */
1402static void
1403xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1404{
Daniel Veillardcda96922001-08-21 10:56:31 +00001405 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001406 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001407 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001408 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001409 break;
1410 case -1:
1411 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001412 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001413 break;
1414 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001415 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001416 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001417 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001418 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001419 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001420 } else if (number == ((int) number)) {
1421 char work[30];
1422 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00001423 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001424
1425 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001426 if (value == 0) {
1427 *ptr++ = '0';
1428 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00001429 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001430 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00001431 while ((*cur) && (ptr - buffer < buffersize)) {
1432 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001433 }
1434 }
1435 if (ptr - buffer < buffersize) {
1436 *ptr = 0;
1437 } else if (buffersize > 0) {
1438 ptr--;
1439 *ptr = 0;
1440 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001441 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001442 /* 3 is sign, decimal point, and terminating zero */
1443 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1444 int integer_place, fraction_place;
1445 char *ptr;
1446 char *after_fraction;
1447 double absolute_value;
1448 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001449
Bjorn Reese70a9da52001-04-21 16:57:29 +00001450 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001451
Bjorn Reese70a9da52001-04-21 16:57:29 +00001452 /*
1453 * First choose format - scientific or regular floating point.
1454 * In either case, result is in work, and after_fraction points
1455 * just past the fractional part.
1456 */
1457 if ( ((absolute_value > UPPER_DOUBLE) ||
1458 (absolute_value < LOWER_DOUBLE)) &&
1459 (absolute_value != 0.0) ) {
1460 /* Use scientific notation */
1461 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1462 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00001463 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00001464 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00001465 while ((size > 0) && (work[size] != 'e')) size--;
1466 after_fraction = work + size;
1467
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001468 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001469 else {
1470 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001471 if (absolute_value > 0.0)
1472 integer_place = 1 + (int)log10(absolute_value);
1473 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001474 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001475 fraction_place = (integer_place > 0)
1476 ? DBL_DIG - integer_place
1477 : DBL_DIG;
1478 size = snprintf(work, sizeof(work), "%0.*f",
1479 fraction_place, number);
1480 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001481 }
1482
Bjorn Reese70a9da52001-04-21 16:57:29 +00001483 /* Remove fractional trailing zeroes */
1484 ptr = after_fraction;
1485 while (*(--ptr) == '0')
1486 ;
1487 if (*ptr != '.')
1488 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001489 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001490
1491 /* Finally copy result back to caller */
1492 size = strlen(work) + 1;
1493 if (size > buffersize) {
1494 work[buffersize - 1] = 0;
1495 size = buffersize;
1496 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001497 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001498 }
1499 break;
1500 }
1501}
1502
Owen Taylor3473f882001-02-23 17:55:21 +00001503
1504/************************************************************************
1505 * *
1506 * Routines to handle NodeSets *
1507 * *
1508 ************************************************************************/
1509
1510/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001511 * xmlXPathOrderDocElems:
1512 * @doc: an input document
1513 *
1514 * Call this routine to speed up XPath computation on static documents.
1515 * This stamps all the element nodes with the document order
1516 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001517 * field, the value stored is actually - the node number (starting at -1)
1518 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001519 *
William M. Brack08171912003-12-29 02:52:11 +00001520 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001521 * of error.
1522 */
1523long
1524xmlXPathOrderDocElems(xmlDocPtr doc) {
1525 long count = 0;
1526 xmlNodePtr cur;
1527
1528 if (doc == NULL)
1529 return(-1);
1530 cur = doc->children;
1531 while (cur != NULL) {
1532 if (cur->type == XML_ELEMENT_NODE) {
1533 cur->content = (void *) (-(++count));
1534 if (cur->children != NULL) {
1535 cur = cur->children;
1536 continue;
1537 }
1538 }
1539 if (cur->next != NULL) {
1540 cur = cur->next;
1541 continue;
1542 }
1543 do {
1544 cur = cur->parent;
1545 if (cur == NULL)
1546 break;
1547 if (cur == (xmlNodePtr) doc) {
1548 cur = NULL;
1549 break;
1550 }
1551 if (cur->next != NULL) {
1552 cur = cur->next;
1553 break;
1554 }
1555 } while (cur != NULL);
1556 }
1557 return(count);
1558}
1559
1560/**
Owen Taylor3473f882001-02-23 17:55:21 +00001561 * xmlXPathCmpNodes:
1562 * @node1: the first node
1563 * @node2: the second node
1564 *
1565 * Compare two nodes w.r.t document order
1566 *
1567 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001568 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001569 */
1570int
1571xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1572 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001573 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001574 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001575 xmlNodePtr cur, root;
1576
1577 if ((node1 == NULL) || (node2 == NULL))
1578 return(-2);
1579 /*
1580 * a couple of optimizations which will avoid computations in most cases
1581 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001582 if (node1->type == XML_ATTRIBUTE_NODE) {
1583 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001584 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001585 node1 = node1->parent;
1586 }
1587 if (node2->type == XML_ATTRIBUTE_NODE) {
1588 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001589 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001590 node2 = node2->parent;
1591 }
1592 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001593 if (attr1 == attr2) {
1594 /* not required, but we keep attributes in order */
1595 if (attr1 != 0) {
1596 cur = attrNode2->prev;
1597 while (cur != NULL) {
1598 if (cur == attrNode1)
1599 return (1);
1600 cur = cur->prev;
1601 }
1602 return (-1);
1603 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001604 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001605 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001606 if (attr2 == 1)
1607 return(1);
1608 return(-1);
1609 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001610 if ((node1->type == XML_NAMESPACE_DECL) ||
1611 (node2->type == XML_NAMESPACE_DECL))
1612 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001613 if (node1 == node2->prev)
1614 return(1);
1615 if (node1 == node2->next)
1616 return(-1);
1617
1618 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001619 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001620 */
1621 if ((node1->type == XML_ELEMENT_NODE) &&
1622 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001623 (0 > (long) node1->content) &&
1624 (0 > (long) node2->content) &&
1625 (node1->doc == node2->doc)) {
1626 long l1, l2;
1627
1628 l1 = -((long) node1->content);
1629 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001630 if (l1 < l2)
1631 return(1);
1632 if (l1 > l2)
1633 return(-1);
1634 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001635
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001636 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001637 * compute depth to root
1638 */
1639 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1640 if (cur == node1)
1641 return(1);
1642 depth2++;
1643 }
1644 root = cur;
1645 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1646 if (cur == node2)
1647 return(-1);
1648 depth1++;
1649 }
1650 /*
1651 * Distinct document (or distinct entities :-( ) case.
1652 */
1653 if (root != cur) {
1654 return(-2);
1655 }
1656 /*
1657 * get the nearest common ancestor.
1658 */
1659 while (depth1 > depth2) {
1660 depth1--;
1661 node1 = node1->parent;
1662 }
1663 while (depth2 > depth1) {
1664 depth2--;
1665 node2 = node2->parent;
1666 }
1667 while (node1->parent != node2->parent) {
1668 node1 = node1->parent;
1669 node2 = node2->parent;
1670 /* should not happen but just in case ... */
1671 if ((node1 == NULL) || (node2 == NULL))
1672 return(-2);
1673 }
1674 /*
1675 * Find who's first.
1676 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001677 if (node1 == node2->prev)
1678 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001679 if (node1 == node2->next)
1680 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001681 /*
1682 * Speedup using document order if availble.
1683 */
1684 if ((node1->type == XML_ELEMENT_NODE) &&
1685 (node2->type == XML_ELEMENT_NODE) &&
1686 (0 > (long) node1->content) &&
1687 (0 > (long) node2->content) &&
1688 (node1->doc == node2->doc)) {
1689 long l1, l2;
1690
1691 l1 = -((long) node1->content);
1692 l2 = -((long) node2->content);
1693 if (l1 < l2)
1694 return(1);
1695 if (l1 > l2)
1696 return(-1);
1697 }
1698
Owen Taylor3473f882001-02-23 17:55:21 +00001699 for (cur = node1->next;cur != NULL;cur = cur->next)
1700 if (cur == node2)
1701 return(1);
1702 return(-1); /* assume there is no sibling list corruption */
1703}
1704
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001705#ifdef XP_FAST_NON_ELEM_COMPARISON
1706/**
1707 * xmlXPathCmpNodesExt:
1708 * @node1: the first node
1709 * @node2: the second node
1710 *
1711 * Compare two nodes w.r.t document order.
1712 * This one is optimized for handling of non-element nodes.
1713 *
1714 * Returns -2 in case of error 1 if first point < second point, 0 if
1715 * it's the same node, -1 otherwise
1716 */
1717static int
1718xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
1719 int depth1, depth2;
1720 int misc = 0, precedence1 = 0, precedence2 = 0;
1721 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
1722 xmlNodePtr cur, root;
1723
1724 if ((node1 == NULL) || (node2 == NULL))
1725 return(-2);
1726
1727 if (node1 == node2)
1728 return(0);
1729
1730 /*
1731 * a couple of optimizations which will avoid computations in most cases
1732 */
1733
1734 switch (node1->type) {
1735 case XML_ELEMENT_NODE:
1736 break;
1737 case XML_ATTRIBUTE_NODE:
1738 precedence1 = 1; /* element is owner */
1739 miscNode1 = node1;
1740 node1 = node1->parent;
1741 misc = 1;
1742 break;
1743 case XML_TEXT_NODE:
1744 case XML_CDATA_SECTION_NODE:
1745 case XML_COMMENT_NODE:
1746 case XML_PI_NODE: {
1747 miscNode1 = node1;
1748 /*
1749 * Find nearest element node.
1750 */
1751 if (node1->prev != NULL) {
1752 do {
1753 node1 = node1->prev;
1754 if (node1->type == XML_ELEMENT_NODE) {
1755 precedence1 = 3; /* element in prev-sibl axis */
1756 break;
1757 }
1758 if (node1->prev == NULL) {
1759 precedence1 = 2; /* element is parent */
1760 /*
1761 * URGENT TODO: Are there any cases, where the
1762 * parent of such a node is not an element node?
1763 */
1764 node1 = node1->parent;
1765 break;
1766 }
1767 } while (1);
1768 } else {
1769 precedence1 = 2; /* element is parent */
1770 node1 = node1->parent;
1771 }
1772 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
1773 /*
1774 * Fallback for whatever case.
1775 */
1776 node1 = miscNode1;
1777 precedence1 = 0;
1778 } else
1779 misc = 1;
1780 }
1781 break;
1782 case XML_NAMESPACE_DECL:
1783 /*
1784 * TODO: why do we return 1 for namespace nodes?
1785 */
1786 return(1);
1787 default:
1788 break;
1789 }
1790 switch (node2->type) {
1791 case XML_ELEMENT_NODE:
1792 break;
1793 case XML_ATTRIBUTE_NODE:
1794 precedence2 = 1; /* element is owner */
1795 miscNode2 = node2;
1796 node2 = node2->parent;
1797 misc = 1;
1798 break;
1799 case XML_TEXT_NODE:
1800 case XML_CDATA_SECTION_NODE:
1801 case XML_COMMENT_NODE:
1802 case XML_PI_NODE: {
1803 miscNode2 = node2;
1804 if (node2->prev != NULL) {
1805 do {
1806 node2 = node2->prev;
1807 if (node2->type == XML_ELEMENT_NODE) {
1808 precedence2 = 3; /* element in prev-sibl axis */
1809 break;
1810 }
1811 if (node2->prev == NULL) {
1812 precedence2 = 2; /* element is parent */
1813 node2 = node2->parent;
1814 break;
1815 }
1816 } while (1);
1817 } else {
1818 precedence2 = 2; /* element is parent */
1819 node2 = node2->parent;
1820 }
1821 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
1822 (0 <= (long) node1->content))
1823 {
1824 node2 = miscNode2;
1825 precedence2 = 0;
1826 } else
1827 misc = 1;
1828 }
1829 break;
1830 case XML_NAMESPACE_DECL:
1831 return(1);
1832 default:
1833 break;
1834 }
1835 if (misc) {
1836 if (node1 == node2) {
1837 if (precedence1 == precedence2) {
1838 /*
1839 * The ugly case; but normally there aren't many
1840 * adjacent non-element nodes around.
1841 */
1842 cur = miscNode2->prev;
1843 while (cur != NULL) {
1844 if (cur == miscNode1)
1845 return(1);
1846 if (cur->type == XML_ELEMENT_NODE)
1847 return(-1);
1848 cur = cur->prev;
1849 }
1850 return (-1);
1851 } else {
1852 /*
1853 * Evaluate based on higher precedence wrt to the element.
1854 * TODO: This assumes attributes are sorted before content.
1855 * Is this 100% correct?
1856 */
1857 if (precedence1 < precedence2)
1858 return(1);
1859 else
1860 return(-1);
1861 }
1862 }
1863 /*
1864 * Special case: One of the helper-elements is contained by the other.
1865 * <foo>
1866 * <node2>
1867 * <node1>Text-1(precedence1 == 2)</node1>
1868 * </node2>
1869 * Text-6(precedence2 == 3)
1870 * </foo>
1871 */
1872 if ((precedence2 == 3) && (precedence1 > 1)) {
1873 cur = node1->parent;
1874 while (cur) {
1875 if (cur == node2)
1876 return(1);
1877 cur = cur->parent;
1878 }
1879 }
1880 if ((precedence1 == 3) && (precedence2 > 1)) {
1881 cur = node2->parent;
1882 while (cur) {
1883 if (cur == node1)
1884 return(-1);
1885 cur = cur->parent;
1886 }
1887 }
1888 }
1889
1890 if (node1 == node2->prev)
1891 return(1);
1892 if (node1 == node2->next)
1893 return(-1);
1894
1895 /*
1896 * Speedup using document order if availble.
1897 */
1898 if ((node1->type == XML_ELEMENT_NODE) &&
1899 (node2->type == XML_ELEMENT_NODE) &&
1900 (0 > (long) node1->content) &&
1901 (0 > (long) node2->content) &&
1902 (node1->doc == node2->doc)) {
1903 long l1, l2;
1904
1905 l1 = -((long) node1->content);
1906 l2 = -((long) node2->content);
1907 if (l1 < l2)
1908 return(1);
1909 if (l1 > l2)
1910 return(-1);
1911 }
1912
1913 /*
1914 * compute depth to root
1915 */
1916 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1917 if (cur == node1)
1918 return(1);
1919 depth2++;
1920 }
1921 root = cur;
1922 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1923 if (cur == node2)
1924 return(-1);
1925 depth1++;
1926 }
1927 /*
1928 * Distinct document (or distinct entities :-( ) case.
1929 */
1930 if (root != cur) {
1931 return(-2);
1932 }
1933 /*
1934 * get the nearest common ancestor.
1935 */
1936 while (depth1 > depth2) {
1937 depth1--;
1938 node1 = node1->parent;
1939 }
1940 while (depth2 > depth1) {
1941 depth2--;
1942 node2 = node2->parent;
1943 }
1944 while (node1->parent != node2->parent) {
1945 node1 = node1->parent;
1946 node2 = node2->parent;
1947 /* should not happen but just in case ... */
1948 if ((node1 == NULL) || (node2 == NULL))
1949 return(-2);
1950 }
1951 /*
1952 * Find who's first.
1953 */
1954 if (node1 == node2->prev)
1955 return(1);
1956 if (node1 == node2->next)
1957 return(-1);
1958 /*
1959 * Speedup using document order if availble.
1960 */
1961 if ((node1->type == XML_ELEMENT_NODE) &&
1962 (node2->type == XML_ELEMENT_NODE) &&
1963 (0 > (long) node1->content) &&
1964 (0 > (long) node2->content) &&
1965 (node1->doc == node2->doc)) {
1966 long l1, l2;
1967
1968 l1 = -((long) node1->content);
1969 l2 = -((long) node2->content);
1970 if (l1 < l2)
1971 return(1);
1972 if (l1 > l2)
1973 return(-1);
1974 }
1975
1976 for (cur = node1->next;cur != NULL;cur = cur->next)
1977 if (cur == node2)
1978 return(1);
1979 return(-1); /* assume there is no sibling list corruption */
1980}
1981#endif /* XP_FAST_NON_ELEM_COMPARISON */
1982
Owen Taylor3473f882001-02-23 17:55:21 +00001983/**
1984 * xmlXPathNodeSetSort:
1985 * @set: the node set
1986 *
1987 * Sort the node set in document order
1988 */
1989void
1990xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001991 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001992 xmlNodePtr tmp;
1993
1994 if (set == NULL)
1995 return;
1996
1997 /* Use Shell's sort to sort the node-set */
1998 len = set->nodeNr;
1999 for (incr = len / 2; incr > 0; incr /= 2) {
2000 for (i = incr; i < len; i++) {
2001 j = i - incr;
2002 while (j >= 0) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002003#ifdef XP_FAST_NON_ELEM_COMPARISON
2004 if (xmlXPathCmpNodesExt(set->nodeTab[j],
2005 set->nodeTab[j + incr]) == -1)
2006#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002007 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002008 set->nodeTab[j + incr]) == -1)
2009#endif
2010 {
Owen Taylor3473f882001-02-23 17:55:21 +00002011 tmp = set->nodeTab[j];
2012 set->nodeTab[j] = set->nodeTab[j + incr];
2013 set->nodeTab[j + incr] = tmp;
2014 j -= incr;
2015 } else
2016 break;
2017 }
2018 }
2019 }
2020}
2021
2022#define XML_NODESET_DEFAULT 10
2023/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002024 * xmlXPathNodeSetDupNs:
2025 * @node: the parent node of the namespace XPath node
2026 * @ns: the libxml namespace declaration node.
2027 *
2028 * Namespace node in libxml don't match the XPath semantic. In a node set
2029 * the namespace nodes are duplicated and the next pointer is set to the
2030 * parent node in the XPath semantic.
2031 *
2032 * Returns the newly created object.
2033 */
2034static xmlNodePtr
2035xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2036 xmlNsPtr cur;
2037
2038 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2039 return(NULL);
2040 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2041 return((xmlNodePtr) ns);
2042
2043 /*
2044 * Allocate a new Namespace and fill the fields.
2045 */
2046 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2047 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002048 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002049 return(NULL);
2050 }
2051 memset(cur, 0, sizeof(xmlNs));
2052 cur->type = XML_NAMESPACE_DECL;
2053 if (ns->href != NULL)
2054 cur->href = xmlStrdup(ns->href);
2055 if (ns->prefix != NULL)
2056 cur->prefix = xmlStrdup(ns->prefix);
2057 cur->next = (xmlNsPtr) node;
2058 return((xmlNodePtr) cur);
2059}
2060
2061/**
2062 * xmlXPathNodeSetFreeNs:
2063 * @ns: the XPath namespace node found in a nodeset.
2064 *
William M. Brack08171912003-12-29 02:52:11 +00002065 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002066 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00002067 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002068 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00002069void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002070xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2071 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2072 return;
2073
2074 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2075 if (ns->href != NULL)
2076 xmlFree((xmlChar *)ns->href);
2077 if (ns->prefix != NULL)
2078 xmlFree((xmlChar *)ns->prefix);
2079 xmlFree(ns);
2080 }
2081}
2082
2083/**
Owen Taylor3473f882001-02-23 17:55:21 +00002084 * xmlXPathNodeSetCreate:
2085 * @val: an initial xmlNodePtr, or NULL
2086 *
2087 * Create a new xmlNodeSetPtr of type double and of value @val
2088 *
2089 * Returns the newly created object.
2090 */
2091xmlNodeSetPtr
2092xmlXPathNodeSetCreate(xmlNodePtr val) {
2093 xmlNodeSetPtr ret;
2094
2095 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2096 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002097 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002098 return(NULL);
2099 }
2100 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
2101 if (val != NULL) {
2102 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2103 sizeof(xmlNodePtr));
2104 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002105 xmlXPathErrMemory(NULL, "creating nodeset\n");
2106 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002107 return(NULL);
2108 }
2109 memset(ret->nodeTab, 0 ,
2110 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2111 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002112 if (val->type == XML_NAMESPACE_DECL) {
2113 xmlNsPtr ns = (xmlNsPtr) val;
2114
2115 ret->nodeTab[ret->nodeNr++] =
2116 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2117 } else
2118 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002119 }
2120 return(ret);
2121}
2122
2123/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002124 * xmlXPathNodeSetContains:
2125 * @cur: the node-set
2126 * @val: the node
2127 *
2128 * checks whether @cur contains @val
2129 *
2130 * Returns true (1) if @cur contains @val, false (0) otherwise
2131 */
2132int
2133xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2134 int i;
2135
Daniel Veillarda82b1822004-11-08 16:24:57 +00002136 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002137 if (val->type == XML_NAMESPACE_DECL) {
2138 for (i = 0; i < cur->nodeNr; i++) {
2139 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2140 xmlNsPtr ns1, ns2;
2141
2142 ns1 = (xmlNsPtr) val;
2143 ns2 = (xmlNsPtr) cur->nodeTab[i];
2144 if (ns1 == ns2)
2145 return(1);
2146 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2147 (xmlStrEqual(ns1->prefix, ns2->prefix)))
2148 return(1);
2149 }
2150 }
2151 } else {
2152 for (i = 0; i < cur->nodeNr; i++) {
2153 if (cur->nodeTab[i] == val)
2154 return(1);
2155 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002156 }
2157 return(0);
2158}
2159
2160/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002161 * xmlXPathNodeSetAddNs:
2162 * @cur: the initial node set
2163 * @node: the hosting node
2164 * @ns: a the namespace node
2165 *
2166 * add a new namespace node to an existing NodeSet
2167 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00002168void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002169xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2170 int i;
2171
Daniel Veillarda82b1822004-11-08 16:24:57 +00002172
2173 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2174 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002175 (node->type != XML_ELEMENT_NODE))
2176 return;
2177
William M. Brack08171912003-12-29 02:52:11 +00002178 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002179 /*
William M. Brack08171912003-12-29 02:52:11 +00002180 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002181 */
2182 for (i = 0;i < cur->nodeNr;i++) {
2183 if ((cur->nodeTab[i] != NULL) &&
2184 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00002185 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002186 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2187 return;
2188 }
2189
2190 /*
2191 * grow the nodeTab if needed
2192 */
2193 if (cur->nodeMax == 0) {
2194 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2195 sizeof(xmlNodePtr));
2196 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002197 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002198 return;
2199 }
2200 memset(cur->nodeTab, 0 ,
2201 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2202 cur->nodeMax = XML_NODESET_DEFAULT;
2203 } else if (cur->nodeNr == cur->nodeMax) {
2204 xmlNodePtr *temp;
2205
2206 cur->nodeMax *= 2;
2207 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2208 sizeof(xmlNodePtr));
2209 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002210 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002211 return;
2212 }
2213 cur->nodeTab = temp;
2214 }
2215 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
2216}
2217
2218/**
Owen Taylor3473f882001-02-23 17:55:21 +00002219 * xmlXPathNodeSetAdd:
2220 * @cur: the initial node set
2221 * @val: a new xmlNodePtr
2222 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002223 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00002224 */
2225void
2226xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2227 int i;
2228
Daniel Veillarda82b1822004-11-08 16:24:57 +00002229 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002230
Daniel Veillardef0b4502003-03-24 13:57:34 +00002231#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00002232 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
2233 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00002234#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00002235
William M. Brack08171912003-12-29 02:52:11 +00002236 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002237 /*
William M. Brack08171912003-12-29 02:52:11 +00002238 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00002239 */
2240 for (i = 0;i < cur->nodeNr;i++)
2241 if (cur->nodeTab[i] == val) return;
2242
2243 /*
2244 * grow the nodeTab if needed
2245 */
2246 if (cur->nodeMax == 0) {
2247 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2248 sizeof(xmlNodePtr));
2249 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002250 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002251 return;
2252 }
2253 memset(cur->nodeTab, 0 ,
2254 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2255 cur->nodeMax = XML_NODESET_DEFAULT;
2256 } else if (cur->nodeNr == cur->nodeMax) {
2257 xmlNodePtr *temp;
2258
2259 cur->nodeMax *= 2;
2260 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2261 sizeof(xmlNodePtr));
2262 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002263 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002264 return;
2265 }
2266 cur->nodeTab = temp;
2267 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002268 if (val->type == XML_NAMESPACE_DECL) {
2269 xmlNsPtr ns = (xmlNsPtr) val;
2270
2271 cur->nodeTab[cur->nodeNr++] =
2272 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2273 } else
2274 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002275}
2276
2277/**
2278 * xmlXPathNodeSetAddUnique:
2279 * @cur: the initial node set
2280 * @val: a new xmlNodePtr
2281 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002282 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00002283 * when we are sure the node is not already in the set.
2284 */
2285void
2286xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00002287 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002288
Daniel Veillardef0b4502003-03-24 13:57:34 +00002289#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00002290 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
2291 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00002292#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00002293
William M. Brack08171912003-12-29 02:52:11 +00002294 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002295 /*
2296 * grow the nodeTab if needed
2297 */
2298 if (cur->nodeMax == 0) {
2299 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2300 sizeof(xmlNodePtr));
2301 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002302 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002303 return;
2304 }
2305 memset(cur->nodeTab, 0 ,
2306 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2307 cur->nodeMax = XML_NODESET_DEFAULT;
2308 } else if (cur->nodeNr == cur->nodeMax) {
2309 xmlNodePtr *temp;
2310
2311 cur->nodeMax *= 2;
2312 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2313 sizeof(xmlNodePtr));
2314 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002315 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002316 return;
2317 }
2318 cur->nodeTab = temp;
2319 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002320 if (val->type == XML_NAMESPACE_DECL) {
2321 xmlNsPtr ns = (xmlNsPtr) val;
2322
2323 cur->nodeTab[cur->nodeNr++] =
2324 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2325 } else
2326 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002327}
2328
2329/**
2330 * xmlXPathNodeSetMerge:
2331 * @val1: the first NodeSet or NULL
2332 * @val2: the second NodeSet
2333 *
2334 * Merges two nodesets, all nodes from @val2 are added to @val1
2335 * if @val1 is NULL, a new set is created and copied from @val2
2336 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002337 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002338 */
2339xmlNodeSetPtr
2340xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002341 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002342
2343 if (val2 == NULL) return(val1);
2344 if (val1 == NULL) {
2345 val1 = xmlXPathNodeSetCreate(NULL);
2346 }
2347
William M. Brack08171912003-12-29 02:52:11 +00002348 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002349 initNr = val1->nodeNr;
2350
2351 for (i = 0;i < val2->nodeNr;i++) {
2352 /*
William M. Brack08171912003-12-29 02:52:11 +00002353 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002354 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002355 skip = 0;
2356 for (j = 0; j < initNr; j++) {
2357 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2358 skip = 1;
2359 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002360 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2361 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2362 xmlNsPtr ns1, ns2;
2363 ns1 = (xmlNsPtr) val1->nodeTab[j];
2364 ns2 = (xmlNsPtr) val2->nodeTab[i];
2365 if ((ns1->next == ns2->next) &&
2366 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2367 skip = 1;
2368 break;
2369 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002370 }
2371 }
2372 if (skip)
2373 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002374
2375 /*
2376 * grow the nodeTab if needed
2377 */
2378 if (val1->nodeMax == 0) {
2379 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2380 sizeof(xmlNodePtr));
2381 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002382 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002383 return(NULL);
2384 }
2385 memset(val1->nodeTab, 0 ,
2386 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2387 val1->nodeMax = XML_NODESET_DEFAULT;
2388 } else if (val1->nodeNr == val1->nodeMax) {
2389 xmlNodePtr *temp;
2390
2391 val1->nodeMax *= 2;
2392 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2393 sizeof(xmlNodePtr));
2394 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002395 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002396 return(NULL);
2397 }
2398 val1->nodeTab = temp;
2399 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002400 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2401 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2402
2403 val1->nodeTab[val1->nodeNr++] =
2404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2405 } else
2406 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002407 }
2408
2409 return(val1);
2410}
2411
2412/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002413 * xmlXPathNodeSetMergeUnique:
2414 * @val1: the first NodeSet or NULL
2415 * @val2: the second NodeSet
2416 *
2417 * Merges two nodesets, all nodes from @val2 are added to @val1
2418 * if @val1 is NULL, a new set is created and copied from @val2
2419 *
2420 * Returns @val1 once extended or NULL in case of error.
2421 */
2422static xmlNodeSetPtr
2423xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002424 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002425
2426 if (val2 == NULL) return(val1);
2427 if (val1 == NULL) {
2428 val1 = xmlXPathNodeSetCreate(NULL);
2429 }
2430
William M. Brack08171912003-12-29 02:52:11 +00002431 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002432
2433 for (i = 0;i < val2->nodeNr;i++) {
2434 /*
2435 * grow the nodeTab if needed
2436 */
2437 if (val1->nodeMax == 0) {
2438 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2439 sizeof(xmlNodePtr));
2440 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002441 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002442 return(NULL);
2443 }
2444 memset(val1->nodeTab, 0 ,
2445 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2446 val1->nodeMax = XML_NODESET_DEFAULT;
2447 } else if (val1->nodeNr == val1->nodeMax) {
2448 xmlNodePtr *temp;
2449
2450 val1->nodeMax *= 2;
2451 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2452 sizeof(xmlNodePtr));
2453 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002454 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002455 return(NULL);
2456 }
2457 val1->nodeTab = temp;
2458 }
2459 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2460 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2461
2462 val1->nodeTab[val1->nodeNr++] =
2463 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2464 } else
2465 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2466 }
2467
2468 return(val1);
2469}
2470
2471/**
Owen Taylor3473f882001-02-23 17:55:21 +00002472 * xmlXPathNodeSetDel:
2473 * @cur: the initial node set
2474 * @val: an xmlNodePtr
2475 *
2476 * Removes an xmlNodePtr from an existing NodeSet
2477 */
2478void
2479xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2480 int i;
2481
2482 if (cur == NULL) return;
2483 if (val == NULL) return;
2484
2485 /*
William M. Brack08171912003-12-29 02:52:11 +00002486 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002487 */
2488 for (i = 0;i < cur->nodeNr;i++)
2489 if (cur->nodeTab[i] == val) break;
2490
William M. Brack08171912003-12-29 02:52:11 +00002491 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002492#ifdef DEBUG
2493 xmlGenericError(xmlGenericErrorContext,
2494 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2495 val->name);
2496#endif
2497 return;
2498 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002499 if ((cur->nodeTab[i] != NULL) &&
2500 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2501 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002502 cur->nodeNr--;
2503 for (;i < cur->nodeNr;i++)
2504 cur->nodeTab[i] = cur->nodeTab[i + 1];
2505 cur->nodeTab[cur->nodeNr] = NULL;
2506}
2507
2508/**
2509 * xmlXPathNodeSetRemove:
2510 * @cur: the initial node set
2511 * @val: the index to remove
2512 *
2513 * Removes an entry from an existing NodeSet list.
2514 */
2515void
2516xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2517 if (cur == NULL) return;
2518 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002519 if ((cur->nodeTab[val] != NULL) &&
2520 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2521 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002522 cur->nodeNr--;
2523 for (;val < cur->nodeNr;val++)
2524 cur->nodeTab[val] = cur->nodeTab[val + 1];
2525 cur->nodeTab[cur->nodeNr] = NULL;
2526}
2527
2528/**
2529 * xmlXPathFreeNodeSet:
2530 * @obj: the xmlNodeSetPtr to free
2531 *
2532 * Free the NodeSet compound (not the actual nodes !).
2533 */
2534void
2535xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2536 if (obj == NULL) return;
2537 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002538 int i;
2539
William M. Brack08171912003-12-29 02:52:11 +00002540 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002541 for (i = 0;i < obj->nodeNr;i++)
2542 if ((obj->nodeTab[i] != NULL) &&
2543 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2544 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002545 xmlFree(obj->nodeTab);
2546 }
Owen Taylor3473f882001-02-23 17:55:21 +00002547 xmlFree(obj);
2548}
2549
2550/**
2551 * xmlXPathFreeValueTree:
2552 * @obj: the xmlNodeSetPtr to free
2553 *
2554 * Free the NodeSet compound and the actual tree, this is different
2555 * from xmlXPathFreeNodeSet()
2556 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002557static void
Owen Taylor3473f882001-02-23 17:55:21 +00002558xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2559 int i;
2560
2561 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002562
2563 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002564 for (i = 0;i < obj->nodeNr;i++) {
2565 if (obj->nodeTab[i] != NULL) {
2566 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2567 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2568 } else {
2569 xmlFreeNodeList(obj->nodeTab[i]);
2570 }
2571 }
2572 }
Owen Taylor3473f882001-02-23 17:55:21 +00002573 xmlFree(obj->nodeTab);
2574 }
Owen Taylor3473f882001-02-23 17:55:21 +00002575 xmlFree(obj);
2576}
2577
2578#if defined(DEBUG) || defined(DEBUG_STEP)
2579/**
2580 * xmlGenericErrorContextNodeSet:
2581 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002582 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002583 *
2584 * Quick display of a NodeSet
2585 */
2586void
2587xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2588 int i;
2589
2590 if (output == NULL) output = xmlGenericErrorContext;
2591 if (obj == NULL) {
2592 fprintf(output, "NodeSet == NULL !\n");
2593 return;
2594 }
2595 if (obj->nodeNr == 0) {
2596 fprintf(output, "NodeSet is empty\n");
2597 return;
2598 }
2599 if (obj->nodeTab == NULL) {
2600 fprintf(output, " nodeTab == NULL !\n");
2601 return;
2602 }
2603 for (i = 0; i < obj->nodeNr; i++) {
2604 if (obj->nodeTab[i] == NULL) {
2605 fprintf(output, " NULL !\n");
2606 return;
2607 }
2608 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2609 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2610 fprintf(output, " /");
2611 else if (obj->nodeTab[i]->name == NULL)
2612 fprintf(output, " noname!");
2613 else fprintf(output, " %s", obj->nodeTab[i]->name);
2614 }
2615 fprintf(output, "\n");
2616}
2617#endif
2618
2619/**
2620 * xmlXPathNewNodeSet:
2621 * @val: the NodePtr value
2622 *
2623 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2624 * it with the single Node @val
2625 *
2626 * Returns the newly created object.
2627 */
2628xmlXPathObjectPtr
2629xmlXPathNewNodeSet(xmlNodePtr val) {
2630 xmlXPathObjectPtr ret;
2631
2632 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2633 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002634 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002635 return(NULL);
2636 }
2637 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2638 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002639 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002640 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002641 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002642 return(ret);
2643}
2644
2645/**
2646 * xmlXPathNewValueTree:
2647 * @val: the NodePtr value
2648 *
2649 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2650 * it with the tree root @val
2651 *
2652 * Returns the newly created object.
2653 */
2654xmlXPathObjectPtr
2655xmlXPathNewValueTree(xmlNodePtr val) {
2656 xmlXPathObjectPtr ret;
2657
2658 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2659 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002660 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002661 return(NULL);
2662 }
2663 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2664 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002665 ret->boolval = 1;
2666 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002667 ret->nodesetval = xmlXPathNodeSetCreate(val);
2668 return(ret);
2669}
2670
2671/**
2672 * xmlXPathNewNodeSetList:
2673 * @val: an existing NodeSet
2674 *
2675 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2676 * it with the Nodeset @val
2677 *
2678 * Returns the newly created object.
2679 */
2680xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002681xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2682{
Owen Taylor3473f882001-02-23 17:55:21 +00002683 xmlXPathObjectPtr ret;
2684 int i;
2685
2686 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002687 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002688 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002689 ret = xmlXPathNewNodeSet(NULL);
2690 else {
2691 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2692 for (i = 1; i < val->nodeNr; ++i)
2693 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2694 }
Owen Taylor3473f882001-02-23 17:55:21 +00002695
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002696 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002697}
2698
2699/**
2700 * xmlXPathWrapNodeSet:
2701 * @val: the NodePtr value
2702 *
2703 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2704 *
2705 * Returns the newly created object.
2706 */
2707xmlXPathObjectPtr
2708xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2709 xmlXPathObjectPtr ret;
2710
2711 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2712 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002713 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002714 return(NULL);
2715 }
2716 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2717 ret->type = XPATH_NODESET;
2718 ret->nodesetval = val;
2719 return(ret);
2720}
2721
2722/**
2723 * xmlXPathFreeNodeSetList:
2724 * @obj: an existing NodeSetList object
2725 *
2726 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2727 * the list contrary to xmlXPathFreeObject().
2728 */
2729void
2730xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2731 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002732 xmlFree(obj);
2733}
2734
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002735/**
2736 * xmlXPathDifference:
2737 * @nodes1: a node-set
2738 * @nodes2: a node-set
2739 *
2740 * Implements the EXSLT - Sets difference() function:
2741 * node-set set:difference (node-set, node-set)
2742 *
2743 * Returns the difference between the two node sets, or nodes1 if
2744 * nodes2 is empty
2745 */
2746xmlNodeSetPtr
2747xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2748 xmlNodeSetPtr ret;
2749 int i, l1;
2750 xmlNodePtr cur;
2751
2752 if (xmlXPathNodeSetIsEmpty(nodes2))
2753 return(nodes1);
2754
2755 ret = xmlXPathNodeSetCreate(NULL);
2756 if (xmlXPathNodeSetIsEmpty(nodes1))
2757 return(ret);
2758
2759 l1 = xmlXPathNodeSetGetLength(nodes1);
2760
2761 for (i = 0; i < l1; i++) {
2762 cur = xmlXPathNodeSetItem(nodes1, i);
2763 if (!xmlXPathNodeSetContains(nodes2, cur))
2764 xmlXPathNodeSetAddUnique(ret, cur);
2765 }
2766 return(ret);
2767}
2768
2769/**
2770 * xmlXPathIntersection:
2771 * @nodes1: a node-set
2772 * @nodes2: a node-set
2773 *
2774 * Implements the EXSLT - Sets intersection() function:
2775 * node-set set:intersection (node-set, node-set)
2776 *
2777 * Returns a node set comprising the nodes that are within both the
2778 * node sets passed as arguments
2779 */
2780xmlNodeSetPtr
2781xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2782 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2783 int i, l1;
2784 xmlNodePtr cur;
2785
2786 if (xmlXPathNodeSetIsEmpty(nodes1))
2787 return(ret);
2788 if (xmlXPathNodeSetIsEmpty(nodes2))
2789 return(ret);
2790
2791 l1 = xmlXPathNodeSetGetLength(nodes1);
2792
2793 for (i = 0; i < l1; i++) {
2794 cur = xmlXPathNodeSetItem(nodes1, i);
2795 if (xmlXPathNodeSetContains(nodes2, cur))
2796 xmlXPathNodeSetAddUnique(ret, cur);
2797 }
2798 return(ret);
2799}
2800
2801/**
2802 * xmlXPathDistinctSorted:
2803 * @nodes: a node-set, sorted by document order
2804 *
2805 * Implements the EXSLT - Sets distinct() function:
2806 * node-set set:distinct (node-set)
2807 *
2808 * Returns a subset of the nodes contained in @nodes, or @nodes if
2809 * it is empty
2810 */
2811xmlNodeSetPtr
2812xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2813 xmlNodeSetPtr ret;
2814 xmlHashTablePtr hash;
2815 int i, l;
2816 xmlChar * strval;
2817 xmlNodePtr cur;
2818
2819 if (xmlXPathNodeSetIsEmpty(nodes))
2820 return(nodes);
2821
2822 ret = xmlXPathNodeSetCreate(NULL);
2823 l = xmlXPathNodeSetGetLength(nodes);
2824 hash = xmlHashCreate (l);
2825 for (i = 0; i < l; i++) {
2826 cur = xmlXPathNodeSetItem(nodes, i);
2827 strval = xmlXPathCastNodeToString(cur);
2828 if (xmlHashLookup(hash, strval) == NULL) {
2829 xmlHashAddEntry(hash, strval, strval);
2830 xmlXPathNodeSetAddUnique(ret, cur);
2831 } else {
2832 xmlFree(strval);
2833 }
2834 }
2835 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2836 return(ret);
2837}
2838
2839/**
2840 * xmlXPathDistinct:
2841 * @nodes: a node-set
2842 *
2843 * Implements the EXSLT - Sets distinct() function:
2844 * node-set set:distinct (node-set)
2845 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2846 * is called with the sorted node-set
2847 *
2848 * Returns a subset of the nodes contained in @nodes, or @nodes if
2849 * it is empty
2850 */
2851xmlNodeSetPtr
2852xmlXPathDistinct (xmlNodeSetPtr nodes) {
2853 if (xmlXPathNodeSetIsEmpty(nodes))
2854 return(nodes);
2855
2856 xmlXPathNodeSetSort(nodes);
2857 return(xmlXPathDistinctSorted(nodes));
2858}
2859
2860/**
2861 * xmlXPathHasSameNodes:
2862 * @nodes1: a node-set
2863 * @nodes2: a node-set
2864 *
2865 * Implements the EXSLT - Sets has-same-nodes function:
2866 * boolean set:has-same-node(node-set, node-set)
2867 *
2868 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2869 * otherwise
2870 */
2871int
2872xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2873 int i, l;
2874 xmlNodePtr cur;
2875
2876 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2877 xmlXPathNodeSetIsEmpty(nodes2))
2878 return(0);
2879
2880 l = xmlXPathNodeSetGetLength(nodes1);
2881 for (i = 0; i < l; i++) {
2882 cur = xmlXPathNodeSetItem(nodes1, i);
2883 if (xmlXPathNodeSetContains(nodes2, cur))
2884 return(1);
2885 }
2886 return(0);
2887}
2888
2889/**
2890 * xmlXPathNodeLeadingSorted:
2891 * @nodes: a node-set, sorted by document order
2892 * @node: a node
2893 *
2894 * Implements the EXSLT - Sets leading() function:
2895 * node-set set:leading (node-set, node-set)
2896 *
2897 * Returns the nodes in @nodes that precede @node in document order,
2898 * @nodes if @node is NULL or an empty node-set if @nodes
2899 * doesn't contain @node
2900 */
2901xmlNodeSetPtr
2902xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2903 int i, l;
2904 xmlNodePtr cur;
2905 xmlNodeSetPtr ret;
2906
2907 if (node == NULL)
2908 return(nodes);
2909
2910 ret = xmlXPathNodeSetCreate(NULL);
2911 if (xmlXPathNodeSetIsEmpty(nodes) ||
2912 (!xmlXPathNodeSetContains(nodes, node)))
2913 return(ret);
2914
2915 l = xmlXPathNodeSetGetLength(nodes);
2916 for (i = 0; i < l; i++) {
2917 cur = xmlXPathNodeSetItem(nodes, i);
2918 if (cur == node)
2919 break;
2920 xmlXPathNodeSetAddUnique(ret, cur);
2921 }
2922 return(ret);
2923}
2924
2925/**
2926 * xmlXPathNodeLeading:
2927 * @nodes: a node-set
2928 * @node: a node
2929 *
2930 * Implements the EXSLT - Sets leading() function:
2931 * node-set set:leading (node-set, node-set)
2932 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2933 * is called.
2934 *
2935 * Returns the nodes in @nodes that precede @node in document order,
2936 * @nodes if @node is NULL or an empty node-set if @nodes
2937 * doesn't contain @node
2938 */
2939xmlNodeSetPtr
2940xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2941 xmlXPathNodeSetSort(nodes);
2942 return(xmlXPathNodeLeadingSorted(nodes, node));
2943}
2944
2945/**
2946 * xmlXPathLeadingSorted:
2947 * @nodes1: a node-set, sorted by document order
2948 * @nodes2: a node-set, sorted by document order
2949 *
2950 * Implements the EXSLT - Sets leading() function:
2951 * node-set set:leading (node-set, node-set)
2952 *
2953 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2954 * in document order, @nodes1 if @nodes2 is NULL or empty or
2955 * an empty node-set if @nodes1 doesn't contain @nodes2
2956 */
2957xmlNodeSetPtr
2958xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2959 if (xmlXPathNodeSetIsEmpty(nodes2))
2960 return(nodes1);
2961 return(xmlXPathNodeLeadingSorted(nodes1,
2962 xmlXPathNodeSetItem(nodes2, 1)));
2963}
2964
2965/**
2966 * xmlXPathLeading:
2967 * @nodes1: a node-set
2968 * @nodes2: a node-set
2969 *
2970 * Implements the EXSLT - Sets leading() function:
2971 * node-set set:leading (node-set, node-set)
2972 * @nodes1 and @nodes2 are sorted by document order, then
2973 * #exslSetsLeadingSorted is called.
2974 *
2975 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2976 * in document order, @nodes1 if @nodes2 is NULL or empty or
2977 * an empty node-set if @nodes1 doesn't contain @nodes2
2978 */
2979xmlNodeSetPtr
2980xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2981 if (xmlXPathNodeSetIsEmpty(nodes2))
2982 return(nodes1);
2983 if (xmlXPathNodeSetIsEmpty(nodes1))
2984 return(xmlXPathNodeSetCreate(NULL));
2985 xmlXPathNodeSetSort(nodes1);
2986 xmlXPathNodeSetSort(nodes2);
2987 return(xmlXPathNodeLeadingSorted(nodes1,
2988 xmlXPathNodeSetItem(nodes2, 1)));
2989}
2990
2991/**
2992 * xmlXPathNodeTrailingSorted:
2993 * @nodes: a node-set, sorted by document order
2994 * @node: a node
2995 *
2996 * Implements the EXSLT - Sets trailing() function:
2997 * node-set set:trailing (node-set, node-set)
2998 *
2999 * Returns the nodes in @nodes that follow @node in document order,
3000 * @nodes if @node is NULL or an empty node-set if @nodes
3001 * doesn't contain @node
3002 */
3003xmlNodeSetPtr
3004xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3005 int i, l;
3006 xmlNodePtr cur;
3007 xmlNodeSetPtr ret;
3008
3009 if (node == NULL)
3010 return(nodes);
3011
3012 ret = xmlXPathNodeSetCreate(NULL);
3013 if (xmlXPathNodeSetIsEmpty(nodes) ||
3014 (!xmlXPathNodeSetContains(nodes, node)))
3015 return(ret);
3016
3017 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00003018 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003019 cur = xmlXPathNodeSetItem(nodes, i);
3020 if (cur == node)
3021 break;
3022 xmlXPathNodeSetAddUnique(ret, cur);
3023 }
3024 return(ret);
3025}
3026
3027/**
3028 * xmlXPathNodeTrailing:
3029 * @nodes: a node-set
3030 * @node: a node
3031 *
3032 * Implements the EXSLT - Sets trailing() function:
3033 * node-set set:trailing (node-set, node-set)
3034 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3035 * is called.
3036 *
3037 * Returns the nodes in @nodes that follow @node in document order,
3038 * @nodes if @node is NULL or an empty node-set if @nodes
3039 * doesn't contain @node
3040 */
3041xmlNodeSetPtr
3042xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3043 xmlXPathNodeSetSort(nodes);
3044 return(xmlXPathNodeTrailingSorted(nodes, node));
3045}
3046
3047/**
3048 * xmlXPathTrailingSorted:
3049 * @nodes1: a node-set, sorted by document order
3050 * @nodes2: a node-set, sorted by document order
3051 *
3052 * Implements the EXSLT - Sets trailing() function:
3053 * node-set set:trailing (node-set, node-set)
3054 *
3055 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3056 * in document order, @nodes1 if @nodes2 is NULL or empty or
3057 * an empty node-set if @nodes1 doesn't contain @nodes2
3058 */
3059xmlNodeSetPtr
3060xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3061 if (xmlXPathNodeSetIsEmpty(nodes2))
3062 return(nodes1);
3063 return(xmlXPathNodeTrailingSorted(nodes1,
3064 xmlXPathNodeSetItem(nodes2, 0)));
3065}
3066
3067/**
3068 * xmlXPathTrailing:
3069 * @nodes1: a node-set
3070 * @nodes2: a node-set
3071 *
3072 * Implements the EXSLT - Sets trailing() function:
3073 * node-set set:trailing (node-set, node-set)
3074 * @nodes1 and @nodes2 are sorted by document order, then
3075 * #xmlXPathTrailingSorted is called.
3076 *
3077 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3078 * in document order, @nodes1 if @nodes2 is NULL or empty or
3079 * an empty node-set if @nodes1 doesn't contain @nodes2
3080 */
3081xmlNodeSetPtr
3082xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3083 if (xmlXPathNodeSetIsEmpty(nodes2))
3084 return(nodes1);
3085 if (xmlXPathNodeSetIsEmpty(nodes1))
3086 return(xmlXPathNodeSetCreate(NULL));
3087 xmlXPathNodeSetSort(nodes1);
3088 xmlXPathNodeSetSort(nodes2);
3089 return(xmlXPathNodeTrailingSorted(nodes1,
3090 xmlXPathNodeSetItem(nodes2, 0)));
3091}
3092
Owen Taylor3473f882001-02-23 17:55:21 +00003093/************************************************************************
3094 * *
3095 * Routines to handle extra functions *
3096 * *
3097 ************************************************************************/
3098
3099/**
3100 * xmlXPathRegisterFunc:
3101 * @ctxt: the XPath context
3102 * @name: the function name
3103 * @f: the function implementation or NULL
3104 *
3105 * Register a new function. If @f is NULL it unregisters the function
3106 *
3107 * Returns 0 in case of success, -1 in case of error
3108 */
3109int
3110xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3111 xmlXPathFunction f) {
3112 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3113}
3114
3115/**
3116 * xmlXPathRegisterFuncNS:
3117 * @ctxt: the XPath context
3118 * @name: the function name
3119 * @ns_uri: the function namespace URI
3120 * @f: the function implementation or NULL
3121 *
3122 * Register a new function. If @f is NULL it unregisters the function
3123 *
3124 * Returns 0 in case of success, -1 in case of error
3125 */
3126int
3127xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3128 const xmlChar *ns_uri, xmlXPathFunction f) {
3129 if (ctxt == NULL)
3130 return(-1);
3131 if (name == NULL)
3132 return(-1);
3133
3134 if (ctxt->funcHash == NULL)
3135 ctxt->funcHash = xmlHashCreate(0);
3136 if (ctxt->funcHash == NULL)
3137 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00003138 if (f == NULL)
3139 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00003140 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00003141}
3142
3143/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00003144 * xmlXPathRegisterFuncLookup:
3145 * @ctxt: the XPath context
3146 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003147 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00003148 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003149 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00003150 */
3151void
3152xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3153 xmlXPathFuncLookupFunc f,
3154 void *funcCtxt) {
3155 if (ctxt == NULL)
3156 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003157 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003158 ctxt->funcLookupData = funcCtxt;
3159}
3160
3161/**
Owen Taylor3473f882001-02-23 17:55:21 +00003162 * xmlXPathFunctionLookup:
3163 * @ctxt: the XPath context
3164 * @name: the function name
3165 *
3166 * Search in the Function array of the context for the given
3167 * function.
3168 *
3169 * Returns the xmlXPathFunction or NULL if not found
3170 */
3171xmlXPathFunction
3172xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00003173 if (ctxt == NULL)
3174 return (NULL);
3175
3176 if (ctxt->funcLookupFunc != NULL) {
3177 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00003178 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003179
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003180 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00003181 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00003182 if (ret != NULL)
3183 return(ret);
3184 }
Owen Taylor3473f882001-02-23 17:55:21 +00003185 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3186}
3187
3188/**
3189 * xmlXPathFunctionLookupNS:
3190 * @ctxt: the XPath context
3191 * @name: the function name
3192 * @ns_uri: the function namespace URI
3193 *
3194 * Search in the Function array of the context for the given
3195 * function.
3196 *
3197 * Returns the xmlXPathFunction or NULL if not found
3198 */
3199xmlXPathFunction
3200xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3201 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00003202 xmlXPathFunction ret;
3203
Owen Taylor3473f882001-02-23 17:55:21 +00003204 if (ctxt == NULL)
3205 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003206 if (name == NULL)
3207 return(NULL);
3208
Thomas Broyerba4ad322001-07-26 16:55:21 +00003209 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00003210 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003211
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003212 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00003213 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00003214 if (ret != NULL)
3215 return(ret);
3216 }
3217
3218 if (ctxt->funcHash == NULL)
3219 return(NULL);
3220
William M. Brackad0e67c2004-12-01 14:35:10 +00003221 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3222 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003223}
3224
3225/**
3226 * xmlXPathRegisteredFuncsCleanup:
3227 * @ctxt: the XPath context
3228 *
3229 * Cleanup the XPath context data associated to registered functions
3230 */
3231void
3232xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3233 if (ctxt == NULL)
3234 return;
3235
3236 xmlHashFree(ctxt->funcHash, NULL);
3237 ctxt->funcHash = NULL;
3238}
3239
3240/************************************************************************
3241 * *
William M. Brack08171912003-12-29 02:52:11 +00003242 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00003243 * *
3244 ************************************************************************/
3245
3246/**
3247 * xmlXPathRegisterVariable:
3248 * @ctxt: the XPath context
3249 * @name: the variable name
3250 * @value: the variable value or NULL
3251 *
3252 * Register a new variable value. If @value is NULL it unregisters
3253 * the variable
3254 *
3255 * Returns 0 in case of success, -1 in case of error
3256 */
3257int
3258xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3259 xmlXPathObjectPtr value) {
3260 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3261}
3262
3263/**
3264 * xmlXPathRegisterVariableNS:
3265 * @ctxt: the XPath context
3266 * @name: the variable name
3267 * @ns_uri: the variable namespace URI
3268 * @value: the variable value or NULL
3269 *
3270 * Register a new variable value. If @value is NULL it unregisters
3271 * the variable
3272 *
3273 * Returns 0 in case of success, -1 in case of error
3274 */
3275int
3276xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3277 const xmlChar *ns_uri,
3278 xmlXPathObjectPtr value) {
3279 if (ctxt == NULL)
3280 return(-1);
3281 if (name == NULL)
3282 return(-1);
3283
3284 if (ctxt->varHash == NULL)
3285 ctxt->varHash = xmlHashCreate(0);
3286 if (ctxt->varHash == NULL)
3287 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00003288 if (value == NULL)
3289 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3290 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00003291 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3292 (void *) value,
3293 (xmlHashDeallocator)xmlXPathFreeObject));
3294}
3295
3296/**
3297 * xmlXPathRegisterVariableLookup:
3298 * @ctxt: the XPath context
3299 * @f: the lookup function
3300 * @data: the lookup data
3301 *
3302 * register an external mechanism to do variable lookup
3303 */
3304void
3305xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3306 xmlXPathVariableLookupFunc f, void *data) {
3307 if (ctxt == NULL)
3308 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003309 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003310 ctxt->varLookupData = data;
3311}
3312
3313/**
3314 * xmlXPathVariableLookup:
3315 * @ctxt: the XPath context
3316 * @name: the variable name
3317 *
3318 * Search in the Variable array of the context for the given
3319 * variable value.
3320 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003321 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003322 */
3323xmlXPathObjectPtr
3324xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3325 if (ctxt == NULL)
3326 return(NULL);
3327
3328 if (ctxt->varLookupFunc != NULL) {
3329 xmlXPathObjectPtr ret;
3330
3331 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3332 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003333 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003334 }
3335 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3336}
3337
3338/**
3339 * xmlXPathVariableLookupNS:
3340 * @ctxt: the XPath context
3341 * @name: the variable name
3342 * @ns_uri: the variable namespace URI
3343 *
3344 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003345 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003346 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003347 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003348 */
3349xmlXPathObjectPtr
3350xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3351 const xmlChar *ns_uri) {
3352 if (ctxt == NULL)
3353 return(NULL);
3354
3355 if (ctxt->varLookupFunc != NULL) {
3356 xmlXPathObjectPtr ret;
3357
3358 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3359 (ctxt->varLookupData, name, ns_uri);
3360 if (ret != NULL) return(ret);
3361 }
3362
3363 if (ctxt->varHash == NULL)
3364 return(NULL);
3365 if (name == NULL)
3366 return(NULL);
3367
Daniel Veillard8c357d52001-07-03 23:43:33 +00003368 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3369 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003370}
3371
3372/**
3373 * xmlXPathRegisteredVariablesCleanup:
3374 * @ctxt: the XPath context
3375 *
3376 * Cleanup the XPath context data associated to registered variables
3377 */
3378void
3379xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3380 if (ctxt == NULL)
3381 return;
3382
Daniel Veillard76d66f42001-05-16 21:05:17 +00003383 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003384 ctxt->varHash = NULL;
3385}
3386
3387/**
3388 * xmlXPathRegisterNs:
3389 * @ctxt: the XPath context
3390 * @prefix: the namespace prefix
3391 * @ns_uri: the namespace name
3392 *
3393 * Register a new namespace. If @ns_uri is NULL it unregisters
3394 * the namespace
3395 *
3396 * Returns 0 in case of success, -1 in case of error
3397 */
3398int
3399xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3400 const xmlChar *ns_uri) {
3401 if (ctxt == NULL)
3402 return(-1);
3403 if (prefix == NULL)
3404 return(-1);
3405
3406 if (ctxt->nsHash == NULL)
3407 ctxt->nsHash = xmlHashCreate(10);
3408 if (ctxt->nsHash == NULL)
3409 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003410 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003411 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003412 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003413 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003414 (xmlHashDeallocator)xmlFree));
3415}
3416
3417/**
3418 * xmlXPathNsLookup:
3419 * @ctxt: the XPath context
3420 * @prefix: the namespace prefix value
3421 *
3422 * Search in the namespace declaration array of the context for the given
3423 * namespace name associated to the given prefix
3424 *
3425 * Returns the value or NULL if not found
3426 */
3427const xmlChar *
3428xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3429 if (ctxt == NULL)
3430 return(NULL);
3431 if (prefix == NULL)
3432 return(NULL);
3433
3434#ifdef XML_XML_NAMESPACE
3435 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3436 return(XML_XML_NAMESPACE);
3437#endif
3438
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003439 if (ctxt->namespaces != NULL) {
3440 int i;
3441
3442 for (i = 0;i < ctxt->nsNr;i++) {
3443 if ((ctxt->namespaces[i] != NULL) &&
3444 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3445 return(ctxt->namespaces[i]->href);
3446 }
3447 }
Owen Taylor3473f882001-02-23 17:55:21 +00003448
3449 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3450}
3451
3452/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003453 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003454 * @ctxt: the XPath context
3455 *
3456 * Cleanup the XPath context data associated to registered variables
3457 */
3458void
3459xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3460 if (ctxt == NULL)
3461 return;
3462
Daniel Veillard42766c02002-08-22 20:52:17 +00003463 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003464 ctxt->nsHash = NULL;
3465}
3466
3467/************************************************************************
3468 * *
3469 * Routines to handle Values *
3470 * *
3471 ************************************************************************/
3472
William M. Brack08171912003-12-29 02:52:11 +00003473/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003474
3475/**
3476 * xmlXPathNewFloat:
3477 * @val: the double value
3478 *
3479 * Create a new xmlXPathObjectPtr of type double and of value @val
3480 *
3481 * Returns the newly created object.
3482 */
3483xmlXPathObjectPtr
3484xmlXPathNewFloat(double val) {
3485 xmlXPathObjectPtr ret;
3486
3487 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3488 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003489 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003490 return(NULL);
3491 }
3492 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3493 ret->type = XPATH_NUMBER;
3494 ret->floatval = val;
3495 return(ret);
3496}
3497
3498/**
3499 * xmlXPathNewBoolean:
3500 * @val: the boolean value
3501 *
3502 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3503 *
3504 * Returns the newly created object.
3505 */
3506xmlXPathObjectPtr
3507xmlXPathNewBoolean(int val) {
3508 xmlXPathObjectPtr ret;
3509
3510 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3511 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003512 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003513 return(NULL);
3514 }
3515 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3516 ret->type = XPATH_BOOLEAN;
3517 ret->boolval = (val != 0);
3518 return(ret);
3519}
3520
3521/**
3522 * xmlXPathNewString:
3523 * @val: the xmlChar * value
3524 *
3525 * Create a new xmlXPathObjectPtr of type string and of value @val
3526 *
3527 * Returns the newly created object.
3528 */
3529xmlXPathObjectPtr
3530xmlXPathNewString(const xmlChar *val) {
3531 xmlXPathObjectPtr ret;
3532
3533 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3534 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003535 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003536 return(NULL);
3537 }
3538 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3539 ret->type = XPATH_STRING;
3540 if (val != NULL)
3541 ret->stringval = xmlStrdup(val);
3542 else
3543 ret->stringval = xmlStrdup((const xmlChar *)"");
3544 return(ret);
3545}
3546
3547/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003548 * xmlXPathWrapString:
3549 * @val: the xmlChar * value
3550 *
3551 * Wraps the @val string into an XPath object.
3552 *
3553 * Returns the newly created object.
3554 */
3555xmlXPathObjectPtr
3556xmlXPathWrapString (xmlChar *val) {
3557 xmlXPathObjectPtr ret;
3558
3559 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3560 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003561 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003562 return(NULL);
3563 }
3564 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3565 ret->type = XPATH_STRING;
3566 ret->stringval = val;
3567 return(ret);
3568}
3569
3570/**
Owen Taylor3473f882001-02-23 17:55:21 +00003571 * xmlXPathNewCString:
3572 * @val: the char * value
3573 *
3574 * Create a new xmlXPathObjectPtr of type string and of value @val
3575 *
3576 * Returns the newly created object.
3577 */
3578xmlXPathObjectPtr
3579xmlXPathNewCString(const char *val) {
3580 xmlXPathObjectPtr ret;
3581
3582 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3583 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003584 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003585 return(NULL);
3586 }
3587 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3588 ret->type = XPATH_STRING;
3589 ret->stringval = xmlStrdup(BAD_CAST val);
3590 return(ret);
3591}
3592
3593/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003594 * xmlXPathWrapCString:
3595 * @val: the char * value
3596 *
3597 * Wraps a string into an XPath object.
3598 *
3599 * Returns the newly created object.
3600 */
3601xmlXPathObjectPtr
3602xmlXPathWrapCString (char * val) {
3603 return(xmlXPathWrapString((xmlChar *)(val)));
3604}
3605
3606/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003607 * xmlXPathWrapExternal:
3608 * @val: the user data
3609 *
3610 * Wraps the @val data into an XPath object.
3611 *
3612 * Returns the newly created object.
3613 */
3614xmlXPathObjectPtr
3615xmlXPathWrapExternal (void *val) {
3616 xmlXPathObjectPtr ret;
3617
3618 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3619 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003620 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003621 return(NULL);
3622 }
3623 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3624 ret->type = XPATH_USERS;
3625 ret->user = val;
3626 return(ret);
3627}
3628
3629/**
Owen Taylor3473f882001-02-23 17:55:21 +00003630 * xmlXPathObjectCopy:
3631 * @val: the original object
3632 *
3633 * allocate a new copy of a given object
3634 *
3635 * Returns the newly created object.
3636 */
3637xmlXPathObjectPtr
3638xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3639 xmlXPathObjectPtr ret;
3640
3641 if (val == NULL)
3642 return(NULL);
3643
3644 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3645 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003646 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003647 return(NULL);
3648 }
3649 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3650 switch (val->type) {
3651 case XPATH_BOOLEAN:
3652 case XPATH_NUMBER:
3653 case XPATH_POINT:
3654 case XPATH_RANGE:
3655 break;
3656 case XPATH_STRING:
3657 ret->stringval = xmlStrdup(val->stringval);
3658 break;
3659 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003660#if 0
3661/*
3662 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3663 this previous handling is no longer correct, and can cause some serious
3664 problems (ref. bug 145547)
3665*/
Owen Taylor3473f882001-02-23 17:55:21 +00003666 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003667 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003668 xmlNodePtr cur, tmp;
3669 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003670
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003671 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003672 top = xmlNewDoc(NULL);
3673 top->name = (char *)
3674 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003675 ret->user = top;
3676 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003677 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003678 cur = val->nodesetval->nodeTab[0]->children;
3679 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003680 tmp = xmlDocCopyNode(cur, top, 1);
3681 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003682 cur = cur->next;
3683 }
3684 }
William M. Bracke9449c52004-07-11 14:41:20 +00003685
Daniel Veillard9adc0462003-03-24 18:39:54 +00003686 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003687 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003688 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003689 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003690 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003691#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003692 case XPATH_NODESET:
3693 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003694 /* Do not deallocate the copied tree value */
3695 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003696 break;
3697 case XPATH_LOCATIONSET:
3698#ifdef LIBXML_XPTR_ENABLED
3699 {
3700 xmlLocationSetPtr loc = val->user;
3701 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3702 break;
3703 }
3704#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003705 case XPATH_USERS:
3706 ret->user = val->user;
3707 break;
3708 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003709 xmlGenericError(xmlGenericErrorContext,
3710 "xmlXPathObjectCopy: unsupported type %d\n",
3711 val->type);
3712 break;
3713 }
3714 return(ret);
3715}
3716
3717/**
3718 * xmlXPathFreeObject:
3719 * @obj: the object to free
3720 *
3721 * Free up an xmlXPathObjectPtr object.
3722 */
3723void
3724xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3725 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003726 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003727 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003728#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003729 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003730 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003731 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003732 } else
3733#endif
3734 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003735 xmlXPathFreeValueTree(obj->nodesetval);
3736 } else {
3737 if (obj->nodesetval != NULL)
3738 xmlXPathFreeNodeSet(obj->nodesetval);
3739 }
Owen Taylor3473f882001-02-23 17:55:21 +00003740#ifdef LIBXML_XPTR_ENABLED
3741 } else if (obj->type == XPATH_LOCATIONSET) {
3742 if (obj->user != NULL)
3743 xmlXPtrFreeLocationSet(obj->user);
3744#endif
3745 } else if (obj->type == XPATH_STRING) {
3746 if (obj->stringval != NULL)
3747 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003748 }
3749
Owen Taylor3473f882001-02-23 17:55:21 +00003750 xmlFree(obj);
3751}
3752
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003753
3754/************************************************************************
3755 * *
3756 * Type Casting Routines *
3757 * *
3758 ************************************************************************/
3759
3760/**
3761 * xmlXPathCastBooleanToString:
3762 * @val: a boolean
3763 *
3764 * Converts a boolean to its string value.
3765 *
3766 * Returns a newly allocated string.
3767 */
3768xmlChar *
3769xmlXPathCastBooleanToString (int val) {
3770 xmlChar *ret;
3771 if (val)
3772 ret = xmlStrdup((const xmlChar *) "true");
3773 else
3774 ret = xmlStrdup((const xmlChar *) "false");
3775 return(ret);
3776}
3777
3778/**
3779 * xmlXPathCastNumberToString:
3780 * @val: a number
3781 *
3782 * Converts a number to its string value.
3783 *
3784 * Returns a newly allocated string.
3785 */
3786xmlChar *
3787xmlXPathCastNumberToString (double val) {
3788 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003789 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003790 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003791 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003792 break;
3793 case -1:
3794 ret = xmlStrdup((const xmlChar *) "-Infinity");
3795 break;
3796 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003797 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003798 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003799 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3800 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003801 } else {
3802 /* could be improved */
3803 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00003804 xmlXPathFormatNumber(val, buf, 99);
3805 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003806 ret = xmlStrdup((const xmlChar *) buf);
3807 }
3808 }
3809 return(ret);
3810}
3811
3812/**
3813 * xmlXPathCastNodeToString:
3814 * @node: a node
3815 *
3816 * Converts a node to its string value.
3817 *
3818 * Returns a newly allocated string.
3819 */
3820xmlChar *
3821xmlXPathCastNodeToString (xmlNodePtr node) {
3822 return(xmlNodeGetContent(node));
3823}
3824
3825/**
3826 * xmlXPathCastNodeSetToString:
3827 * @ns: a node-set
3828 *
3829 * Converts a node-set to its string value.
3830 *
3831 * Returns a newly allocated string.
3832 */
3833xmlChar *
3834xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3835 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3836 return(xmlStrdup((const xmlChar *) ""));
3837
3838 xmlXPathNodeSetSort(ns);
3839 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3840}
3841
3842/**
3843 * xmlXPathCastToString:
3844 * @val: an XPath object
3845 *
3846 * Converts an existing object to its string() equivalent
3847 *
3848 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003849 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003850 * string object).
3851 */
3852xmlChar *
3853xmlXPathCastToString(xmlXPathObjectPtr val) {
3854 xmlChar *ret = NULL;
3855
3856 if (val == NULL)
3857 return(xmlStrdup((const xmlChar *) ""));
3858 switch (val->type) {
3859 case XPATH_UNDEFINED:
3860#ifdef DEBUG_EXPR
3861 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3862#endif
3863 ret = xmlStrdup((const xmlChar *) "");
3864 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003865 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003866 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003867 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3868 break;
3869 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003870 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003871 case XPATH_BOOLEAN:
3872 ret = xmlXPathCastBooleanToString(val->boolval);
3873 break;
3874 case XPATH_NUMBER: {
3875 ret = xmlXPathCastNumberToString(val->floatval);
3876 break;
3877 }
3878 case XPATH_USERS:
3879 case XPATH_POINT:
3880 case XPATH_RANGE:
3881 case XPATH_LOCATIONSET:
3882 TODO
3883 ret = xmlStrdup((const xmlChar *) "");
3884 break;
3885 }
3886 return(ret);
3887}
3888
3889/**
3890 * xmlXPathConvertString:
3891 * @val: an XPath object
3892 *
3893 * Converts an existing object to its string() equivalent
3894 *
3895 * Returns the new object, the old one is freed (or the operation
3896 * is done directly on @val)
3897 */
3898xmlXPathObjectPtr
3899xmlXPathConvertString(xmlXPathObjectPtr val) {
3900 xmlChar *res = NULL;
3901
3902 if (val == NULL)
3903 return(xmlXPathNewCString(""));
3904
3905 switch (val->type) {
3906 case XPATH_UNDEFINED:
3907#ifdef DEBUG_EXPR
3908 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3909#endif
3910 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003911 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003912 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003913 res = xmlXPathCastNodeSetToString(val->nodesetval);
3914 break;
3915 case XPATH_STRING:
3916 return(val);
3917 case XPATH_BOOLEAN:
3918 res = xmlXPathCastBooleanToString(val->boolval);
3919 break;
3920 case XPATH_NUMBER:
3921 res = xmlXPathCastNumberToString(val->floatval);
3922 break;
3923 case XPATH_USERS:
3924 case XPATH_POINT:
3925 case XPATH_RANGE:
3926 case XPATH_LOCATIONSET:
3927 TODO;
3928 break;
3929 }
3930 xmlXPathFreeObject(val);
3931 if (res == NULL)
3932 return(xmlXPathNewCString(""));
3933 return(xmlXPathWrapString(res));
3934}
3935
3936/**
3937 * xmlXPathCastBooleanToNumber:
3938 * @val: a boolean
3939 *
3940 * Converts a boolean to its number value
3941 *
3942 * Returns the number value
3943 */
3944double
3945xmlXPathCastBooleanToNumber(int val) {
3946 if (val)
3947 return(1.0);
3948 return(0.0);
3949}
3950
3951/**
3952 * xmlXPathCastStringToNumber:
3953 * @val: a string
3954 *
3955 * Converts a string to its number value
3956 *
3957 * Returns the number value
3958 */
3959double
3960xmlXPathCastStringToNumber(const xmlChar * val) {
3961 return(xmlXPathStringEvalNumber(val));
3962}
3963
3964/**
3965 * xmlXPathCastNodeToNumber:
3966 * @node: a node
3967 *
3968 * Converts a node to its number value
3969 *
3970 * Returns the number value
3971 */
3972double
3973xmlXPathCastNodeToNumber (xmlNodePtr node) {
3974 xmlChar *strval;
3975 double ret;
3976
3977 if (node == NULL)
3978 return(xmlXPathNAN);
3979 strval = xmlXPathCastNodeToString(node);
3980 if (strval == NULL)
3981 return(xmlXPathNAN);
3982 ret = xmlXPathCastStringToNumber(strval);
3983 xmlFree(strval);
3984
3985 return(ret);
3986}
3987
3988/**
3989 * xmlXPathCastNodeSetToNumber:
3990 * @ns: a node-set
3991 *
3992 * Converts a node-set to its number value
3993 *
3994 * Returns the number value
3995 */
3996double
3997xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3998 xmlChar *str;
3999 double ret;
4000
4001 if (ns == NULL)
4002 return(xmlXPathNAN);
4003 str = xmlXPathCastNodeSetToString(ns);
4004 ret = xmlXPathCastStringToNumber(str);
4005 xmlFree(str);
4006 return(ret);
4007}
4008
4009/**
4010 * xmlXPathCastToNumber:
4011 * @val: an XPath object
4012 *
4013 * Converts an XPath object to its number value
4014 *
4015 * Returns the number value
4016 */
4017double
4018xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4019 double ret = 0.0;
4020
4021 if (val == NULL)
4022 return(xmlXPathNAN);
4023 switch (val->type) {
4024 case XPATH_UNDEFINED:
4025#ifdef DEGUB_EXPR
4026 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4027#endif
4028 ret = xmlXPathNAN;
4029 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004030 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00004031 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004032 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
4033 break;
4034 case XPATH_STRING:
4035 ret = xmlXPathCastStringToNumber(val->stringval);
4036 break;
4037 case XPATH_NUMBER:
4038 ret = val->floatval;
4039 break;
4040 case XPATH_BOOLEAN:
4041 ret = xmlXPathCastBooleanToNumber(val->boolval);
4042 break;
4043 case XPATH_USERS:
4044 case XPATH_POINT:
4045 case XPATH_RANGE:
4046 case XPATH_LOCATIONSET:
4047 TODO;
4048 ret = xmlXPathNAN;
4049 break;
4050 }
4051 return(ret);
4052}
4053
4054/**
4055 * xmlXPathConvertNumber:
4056 * @val: an XPath object
4057 *
4058 * Converts an existing object to its number() equivalent
4059 *
4060 * Returns the new object, the old one is freed (or the operation
4061 * is done directly on @val)
4062 */
4063xmlXPathObjectPtr
4064xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4065 xmlXPathObjectPtr ret;
4066
4067 if (val == NULL)
4068 return(xmlXPathNewFloat(0.0));
4069 if (val->type == XPATH_NUMBER)
4070 return(val);
4071 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4072 xmlXPathFreeObject(val);
4073 return(ret);
4074}
4075
4076/**
4077 * xmlXPathCastNumberToBoolean:
4078 * @val: a number
4079 *
4080 * Converts a number to its boolean value
4081 *
4082 * Returns the boolean value
4083 */
4084int
4085xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00004086 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004087 return(0);
4088 return(1);
4089}
4090
4091/**
4092 * xmlXPathCastStringToBoolean:
4093 * @val: a string
4094 *
4095 * Converts a string to its boolean value
4096 *
4097 * Returns the boolean value
4098 */
4099int
4100xmlXPathCastStringToBoolean (const xmlChar *val) {
4101 if ((val == NULL) || (xmlStrlen(val) == 0))
4102 return(0);
4103 return(1);
4104}
4105
4106/**
4107 * xmlXPathCastNodeSetToBoolean:
4108 * @ns: a node-set
4109 *
4110 * Converts a node-set to its boolean value
4111 *
4112 * Returns the boolean value
4113 */
4114int
4115xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4116 if ((ns == NULL) || (ns->nodeNr == 0))
4117 return(0);
4118 return(1);
4119}
4120
4121/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004122 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004123 * @val: an XPath object
4124 *
4125 * Converts an XPath object to its boolean value
4126 *
4127 * Returns the boolean value
4128 */
4129int
4130xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4131 int ret = 0;
4132
4133 if (val == NULL)
4134 return(0);
4135 switch (val->type) {
4136 case XPATH_UNDEFINED:
4137#ifdef DEBUG_EXPR
4138 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
4139#endif
4140 ret = 0;
4141 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004142 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00004143 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004144 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4145 break;
4146 case XPATH_STRING:
4147 ret = xmlXPathCastStringToBoolean(val->stringval);
4148 break;
4149 case XPATH_NUMBER:
4150 ret = xmlXPathCastNumberToBoolean(val->floatval);
4151 break;
4152 case XPATH_BOOLEAN:
4153 ret = val->boolval;
4154 break;
4155 case XPATH_USERS:
4156 case XPATH_POINT:
4157 case XPATH_RANGE:
4158 case XPATH_LOCATIONSET:
4159 TODO;
4160 ret = 0;
4161 break;
4162 }
4163 return(ret);
4164}
4165
4166
4167/**
4168 * xmlXPathConvertBoolean:
4169 * @val: an XPath object
4170 *
4171 * Converts an existing object to its boolean() equivalent
4172 *
4173 * Returns the new object, the old one is freed (or the operation
4174 * is done directly on @val)
4175 */
4176xmlXPathObjectPtr
4177xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4178 xmlXPathObjectPtr ret;
4179
4180 if (val == NULL)
4181 return(xmlXPathNewBoolean(0));
4182 if (val->type == XPATH_BOOLEAN)
4183 return(val);
4184 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4185 xmlXPathFreeObject(val);
4186 return(ret);
4187}
4188
Owen Taylor3473f882001-02-23 17:55:21 +00004189/************************************************************************
4190 * *
4191 * Routines to handle XPath contexts *
4192 * *
4193 ************************************************************************/
4194
4195/**
4196 * xmlXPathNewContext:
4197 * @doc: the XML document
4198 *
4199 * Create a new xmlXPathContext
4200 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00004201 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00004202 */
4203xmlXPathContextPtr
4204xmlXPathNewContext(xmlDocPtr doc) {
4205 xmlXPathContextPtr ret;
4206
4207 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4208 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004209 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004210 return(NULL);
4211 }
4212 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
4213 ret->doc = doc;
4214 ret->node = NULL;
4215
4216 ret->varHash = NULL;
4217
4218 ret->nb_types = 0;
4219 ret->max_types = 0;
4220 ret->types = NULL;
4221
4222 ret->funcHash = xmlHashCreate(0);
4223
4224 ret->nb_axis = 0;
4225 ret->max_axis = 0;
4226 ret->axis = NULL;
4227
4228 ret->nsHash = NULL;
4229 ret->user = NULL;
4230
4231 ret->contextSize = -1;
4232 ret->proximityPosition = -1;
4233
4234 xmlXPathRegisterAllFunctions(ret);
4235
4236 return(ret);
4237}
4238
4239/**
4240 * xmlXPathFreeContext:
4241 * @ctxt: the context to free
4242 *
4243 * Free up an xmlXPathContext
4244 */
4245void
4246xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00004247 if (ctxt == NULL) return;
4248
Owen Taylor3473f882001-02-23 17:55:21 +00004249 xmlXPathRegisteredNsCleanup(ctxt);
4250 xmlXPathRegisteredFuncsCleanup(ctxt);
4251 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00004252 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00004253 xmlFree(ctxt);
4254}
4255
4256/************************************************************************
4257 * *
4258 * Routines to handle XPath parser contexts *
4259 * *
4260 ************************************************************************/
4261
4262#define CHECK_CTXT(ctxt) \
4263 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00004264 __xmlRaiseError(NULL, NULL, NULL, \
4265 NULL, NULL, XML_FROM_XPATH, \
4266 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
4267 __FILE__, __LINE__, \
4268 NULL, NULL, NULL, 0, 0, \
4269 "NULL context pointer\n"); \
4270 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00004271 } \
4272
4273
4274#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00004275 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
4276 (ctxt->doc->children == NULL)) { \
4277 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00004278 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00004279 }
Owen Taylor3473f882001-02-23 17:55:21 +00004280
4281
4282/**
4283 * xmlXPathNewParserContext:
4284 * @str: the XPath expression
4285 * @ctxt: the XPath context
4286 *
4287 * Create a new xmlXPathParserContext
4288 *
4289 * Returns the xmlXPathParserContext just allocated.
4290 */
4291xmlXPathParserContextPtr
4292xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
4293 xmlXPathParserContextPtr ret;
4294
4295 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4296 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004297 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004298 return(NULL);
4299 }
4300 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4301 ret->cur = ret->base = str;
4302 ret->context = ctxt;
4303
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004304 ret->comp = xmlXPathNewCompExpr();
4305 if (ret->comp == NULL) {
4306 xmlFree(ret->valueTab);
4307 xmlFree(ret);
4308 return(NULL);
4309 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004310 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4311 ret->comp->dict = ctxt->dict;
4312 xmlDictReference(ret->comp->dict);
4313 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004314
4315 return(ret);
4316}
4317
4318/**
4319 * xmlXPathCompParserContext:
4320 * @comp: the XPath compiled expression
4321 * @ctxt: the XPath context
4322 *
4323 * Create a new xmlXPathParserContext when processing a compiled expression
4324 *
4325 * Returns the xmlXPathParserContext just allocated.
4326 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004327static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004328xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4329 xmlXPathParserContextPtr ret;
4330
4331 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4332 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004333 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004334 return(NULL);
4335 }
4336 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4337
Owen Taylor3473f882001-02-23 17:55:21 +00004338 /* Allocate the value stack */
4339 ret->valueTab = (xmlXPathObjectPtr *)
4340 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004341 if (ret->valueTab == NULL) {
4342 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004343 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004344 return(NULL);
4345 }
Owen Taylor3473f882001-02-23 17:55:21 +00004346 ret->valueNr = 0;
4347 ret->valueMax = 10;
4348 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004349
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004350 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004351 ret->comp = comp;
4352
Owen Taylor3473f882001-02-23 17:55:21 +00004353 return(ret);
4354}
4355
4356/**
4357 * xmlXPathFreeParserContext:
4358 * @ctxt: the context to free
4359 *
4360 * Free up an xmlXPathParserContext
4361 */
4362void
4363xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4364 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004365 xmlFree(ctxt->valueTab);
4366 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004367 if (ctxt->comp != NULL) {
4368#ifdef XPATH_STREAMING
4369 if (ctxt->comp->stream != NULL) {
4370 xmlFreePatternList(ctxt->comp->stream);
4371 ctxt->comp->stream = NULL;
4372 }
4373#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004374 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004375 }
Owen Taylor3473f882001-02-23 17:55:21 +00004376 xmlFree(ctxt);
4377}
4378
4379/************************************************************************
4380 * *
4381 * The implicit core function library *
4382 * *
4383 ************************************************************************/
4384
Owen Taylor3473f882001-02-23 17:55:21 +00004385/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004386 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004387 * @node: a node pointer
4388 *
4389 * Function computing the beginning of the string value of the node,
4390 * used to speed up comparisons
4391 *
4392 * Returns an int usable as a hash
4393 */
4394static unsigned int
4395xmlXPathNodeValHash(xmlNodePtr node) {
4396 int len = 2;
4397 const xmlChar * string = NULL;
4398 xmlNodePtr tmp = NULL;
4399 unsigned int ret = 0;
4400
4401 if (node == NULL)
4402 return(0);
4403
Daniel Veillard9adc0462003-03-24 18:39:54 +00004404 if (node->type == XML_DOCUMENT_NODE) {
4405 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4406 if (tmp == NULL)
4407 node = node->children;
4408 else
4409 node = tmp;
4410
4411 if (node == NULL)
4412 return(0);
4413 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004414
4415 switch (node->type) {
4416 case XML_COMMENT_NODE:
4417 case XML_PI_NODE:
4418 case XML_CDATA_SECTION_NODE:
4419 case XML_TEXT_NODE:
4420 string = node->content;
4421 if (string == NULL)
4422 return(0);
4423 if (string[0] == 0)
4424 return(0);
4425 return(((unsigned int) string[0]) +
4426 (((unsigned int) string[1]) << 8));
4427 case XML_NAMESPACE_DECL:
4428 string = ((xmlNsPtr)node)->href;
4429 if (string == NULL)
4430 return(0);
4431 if (string[0] == 0)
4432 return(0);
4433 return(((unsigned int) string[0]) +
4434 (((unsigned int) string[1]) << 8));
4435 case XML_ATTRIBUTE_NODE:
4436 tmp = ((xmlAttrPtr) node)->children;
4437 break;
4438 case XML_ELEMENT_NODE:
4439 tmp = node->children;
4440 break;
4441 default:
4442 return(0);
4443 }
4444 while (tmp != NULL) {
4445 switch (tmp->type) {
4446 case XML_COMMENT_NODE:
4447 case XML_PI_NODE:
4448 case XML_CDATA_SECTION_NODE:
4449 case XML_TEXT_NODE:
4450 string = tmp->content;
4451 break;
4452 case XML_NAMESPACE_DECL:
4453 string = ((xmlNsPtr)tmp)->href;
4454 break;
4455 default:
4456 break;
4457 }
4458 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004459 if (len == 1) {
4460 return(ret + (((unsigned int) string[0]) << 8));
4461 }
4462 if (string[1] == 0) {
4463 len = 1;
4464 ret = (unsigned int) string[0];
4465 } else {
4466 return(((unsigned int) string[0]) +
4467 (((unsigned int) string[1]) << 8));
4468 }
4469 }
4470 /*
4471 * Skip to next node
4472 */
4473 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4474 if (tmp->children->type != XML_ENTITY_DECL) {
4475 tmp = tmp->children;
4476 continue;
4477 }
4478 }
4479 if (tmp == node)
4480 break;
4481
4482 if (tmp->next != NULL) {
4483 tmp = tmp->next;
4484 continue;
4485 }
4486
4487 do {
4488 tmp = tmp->parent;
4489 if (tmp == NULL)
4490 break;
4491 if (tmp == node) {
4492 tmp = NULL;
4493 break;
4494 }
4495 if (tmp->next != NULL) {
4496 tmp = tmp->next;
4497 break;
4498 }
4499 } while (tmp != NULL);
4500 }
4501 return(ret);
4502}
4503
4504/**
4505 * xmlXPathStringHash:
4506 * @string: a string
4507 *
4508 * Function computing the beginning of the string value of the node,
4509 * used to speed up comparisons
4510 *
4511 * Returns an int usable as a hash
4512 */
4513static unsigned int
4514xmlXPathStringHash(const xmlChar * string) {
4515 if (string == NULL)
4516 return((unsigned int) 0);
4517 if (string[0] == 0)
4518 return(0);
4519 return(((unsigned int) string[0]) +
4520 (((unsigned int) string[1]) << 8));
4521}
4522
4523/**
Owen Taylor3473f882001-02-23 17:55:21 +00004524 * xmlXPathCompareNodeSetFloat:
4525 * @ctxt: the XPath Parser context
4526 * @inf: less than (1) or greater than (0)
4527 * @strict: is the comparison strict
4528 * @arg: the node set
4529 * @f: the value
4530 *
4531 * Implement the compare operation between a nodeset and a number
4532 * @ns < @val (1, 1, ...
4533 * @ns <= @val (1, 0, ...
4534 * @ns > @val (0, 1, ...
4535 * @ns >= @val (0, 0, ...
4536 *
4537 * If one object to be compared is a node-set and the other is a number,
4538 * then the comparison will be true if and only if there is a node in the
4539 * node-set such that the result of performing the comparison on the number
4540 * to be compared and on the result of converting the string-value of that
4541 * node to a number using the number function is true.
4542 *
4543 * Returns 0 or 1 depending on the results of the test.
4544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004545static int
Owen Taylor3473f882001-02-23 17:55:21 +00004546xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4547 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4548 int i, ret = 0;
4549 xmlNodeSetPtr ns;
4550 xmlChar *str2;
4551
4552 if ((f == NULL) || (arg == NULL) ||
4553 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4554 xmlXPathFreeObject(arg);
4555 xmlXPathFreeObject(f);
4556 return(0);
4557 }
4558 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004559 if (ns != NULL) {
4560 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004561 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004562 if (str2 != NULL) {
4563 valuePush(ctxt,
4564 xmlXPathNewString(str2));
4565 xmlFree(str2);
4566 xmlXPathNumberFunction(ctxt, 1);
4567 valuePush(ctxt, xmlXPathObjectCopy(f));
4568 ret = xmlXPathCompareValues(ctxt, inf, strict);
4569 if (ret)
4570 break;
4571 }
4572 }
Owen Taylor3473f882001-02-23 17:55:21 +00004573 }
4574 xmlXPathFreeObject(arg);
4575 xmlXPathFreeObject(f);
4576 return(ret);
4577}
4578
4579/**
4580 * xmlXPathCompareNodeSetString:
4581 * @ctxt: the XPath Parser context
4582 * @inf: less than (1) or greater than (0)
4583 * @strict: is the comparison strict
4584 * @arg: the node set
4585 * @s: the value
4586 *
4587 * Implement the compare operation between a nodeset and a string
4588 * @ns < @val (1, 1, ...
4589 * @ns <= @val (1, 0, ...
4590 * @ns > @val (0, 1, ...
4591 * @ns >= @val (0, 0, ...
4592 *
4593 * If one object to be compared is a node-set and the other is a string,
4594 * then the comparison will be true if and only if there is a node in
4595 * the node-set such that the result of performing the comparison on the
4596 * string-value of the node and the other string is true.
4597 *
4598 * Returns 0 or 1 depending on the results of the test.
4599 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004600static int
Owen Taylor3473f882001-02-23 17:55:21 +00004601xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4602 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4603 int i, ret = 0;
4604 xmlNodeSetPtr ns;
4605 xmlChar *str2;
4606
4607 if ((s == NULL) || (arg == NULL) ||
4608 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4609 xmlXPathFreeObject(arg);
4610 xmlXPathFreeObject(s);
4611 return(0);
4612 }
4613 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004614 if (ns != NULL) {
4615 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004616 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004617 if (str2 != NULL) {
4618 valuePush(ctxt,
4619 xmlXPathNewString(str2));
4620 xmlFree(str2);
4621 valuePush(ctxt, xmlXPathObjectCopy(s));
4622 ret = xmlXPathCompareValues(ctxt, inf, strict);
4623 if (ret)
4624 break;
4625 }
4626 }
Owen Taylor3473f882001-02-23 17:55:21 +00004627 }
4628 xmlXPathFreeObject(arg);
4629 xmlXPathFreeObject(s);
4630 return(ret);
4631}
4632
4633/**
4634 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004635 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004636 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004637 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004638 * @arg2: the second node set object
4639 *
4640 * Implement the compare operation on nodesets:
4641 *
4642 * If both objects to be compared are node-sets, then the comparison
4643 * will be true if and only if there is a node in the first node-set
4644 * and a node in the second node-set such that the result of performing
4645 * the comparison on the string-values of the two nodes is true.
4646 * ....
4647 * When neither object to be compared is a node-set and the operator
4648 * is <=, <, >= or >, then the objects are compared by converting both
4649 * objects to numbers and comparing the numbers according to IEEE 754.
4650 * ....
4651 * The number function converts its argument to a number as follows:
4652 * - a string that consists of optional whitespace followed by an
4653 * optional minus sign followed by a Number followed by whitespace
4654 * is converted to the IEEE 754 number that is nearest (according
4655 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4656 * represented by the string; any other string is converted to NaN
4657 *
4658 * Conclusion all nodes need to be converted first to their string value
4659 * and then the comparison must be done when possible
4660 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004661static int
4662xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004663 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4664 int i, j, init = 0;
4665 double val1;
4666 double *values2;
4667 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004668 xmlNodeSetPtr ns1;
4669 xmlNodeSetPtr ns2;
4670
4671 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004672 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4673 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004674 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004675 }
Owen Taylor3473f882001-02-23 17:55:21 +00004676 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004677 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4678 xmlXPathFreeObject(arg1);
4679 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004680 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004681 }
Owen Taylor3473f882001-02-23 17:55:21 +00004682
4683 ns1 = arg1->nodesetval;
4684 ns2 = arg2->nodesetval;
4685
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004686 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004687 xmlXPathFreeObject(arg1);
4688 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004689 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004690 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004691 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004692 xmlXPathFreeObject(arg1);
4693 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004694 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004695 }
Owen Taylor3473f882001-02-23 17:55:21 +00004696
4697 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4698 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004699 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004700 xmlXPathFreeObject(arg1);
4701 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004702 return(0);
4703 }
4704 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004705 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004706 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004707 continue;
4708 for (j = 0;j < ns2->nodeNr;j++) {
4709 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004710 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004711 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004712 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004713 continue;
4714 if (inf && strict)
4715 ret = (val1 < values2[j]);
4716 else if (inf && !strict)
4717 ret = (val1 <= values2[j]);
4718 else if (!inf && strict)
4719 ret = (val1 > values2[j]);
4720 else if (!inf && !strict)
4721 ret = (val1 >= values2[j]);
4722 if (ret)
4723 break;
4724 }
4725 if (ret)
4726 break;
4727 init = 1;
4728 }
4729 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004730 xmlXPathFreeObject(arg1);
4731 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004732 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004733}
4734
4735/**
4736 * xmlXPathCompareNodeSetValue:
4737 * @ctxt: the XPath Parser context
4738 * @inf: less than (1) or greater than (0)
4739 * @strict: is the comparison strict
4740 * @arg: the node set
4741 * @val: the value
4742 *
4743 * Implement the compare operation between a nodeset and a value
4744 * @ns < @val (1, 1, ...
4745 * @ns <= @val (1, 0, ...
4746 * @ns > @val (0, 1, ...
4747 * @ns >= @val (0, 0, ...
4748 *
4749 * If one object to be compared is a node-set and the other is a boolean,
4750 * then the comparison will be true if and only if the result of performing
4751 * the comparison on the boolean and on the result of converting
4752 * the node-set to a boolean using the boolean function is true.
4753 *
4754 * Returns 0 or 1 depending on the results of the test.
4755 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004756static int
Owen Taylor3473f882001-02-23 17:55:21 +00004757xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4758 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4759 if ((val == NULL) || (arg == NULL) ||
4760 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4761 return(0);
4762
4763 switch(val->type) {
4764 case XPATH_NUMBER:
4765 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4766 case XPATH_NODESET:
4767 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004768 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004769 case XPATH_STRING:
4770 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4771 case XPATH_BOOLEAN:
4772 valuePush(ctxt, arg);
4773 xmlXPathBooleanFunction(ctxt, 1);
4774 valuePush(ctxt, val);
4775 return(xmlXPathCompareValues(ctxt, inf, strict));
4776 default:
4777 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004778 }
4779 return(0);
4780}
4781
4782/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004783 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004784 * @arg: the nodeset object argument
4785 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004786 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004787 *
4788 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4789 * If one object to be compared is a node-set and the other is a string,
4790 * then the comparison will be true if and only if there is a node in
4791 * the node-set such that the result of performing the comparison on the
4792 * string-value of the node and the other string is true.
4793 *
4794 * Returns 0 or 1 depending on the results of the test.
4795 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004796static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004797xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004798{
Owen Taylor3473f882001-02-23 17:55:21 +00004799 int i;
4800 xmlNodeSetPtr ns;
4801 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004802 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004803
4804 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004805 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4806 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004807 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004808 /*
4809 * A NULL nodeset compared with a string is always false
4810 * (since there is no node equal, and no node not equal)
4811 */
4812 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004813 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004814 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004815 for (i = 0; i < ns->nodeNr; i++) {
4816 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4817 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4818 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4819 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004820 if (neq)
4821 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004822 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004823 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4824 if (neq)
4825 continue;
4826 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004827 } else if (neq) {
4828 if (str2 != NULL)
4829 xmlFree(str2);
4830 return (1);
4831 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004832 if (str2 != NULL)
4833 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004834 } else if (neq)
4835 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004836 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004837 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004838}
4839
4840/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004841 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004842 * @arg: the nodeset object argument
4843 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004844 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004845 *
4846 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4847 * If one object to be compared is a node-set and the other is a number,
4848 * then the comparison will be true if and only if there is a node in
4849 * the node-set such that the result of performing the comparison on the
4850 * number to be compared and on the result of converting the string-value
4851 * of that node to a number using the number function is true.
4852 *
4853 * Returns 0 or 1 depending on the results of the test.
4854 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004855static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004856xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4857 xmlXPathObjectPtr arg, double f, int neq) {
4858 int i, ret=0;
4859 xmlNodeSetPtr ns;
4860 xmlChar *str2;
4861 xmlXPathObjectPtr val;
4862 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004863
4864 if ((arg == NULL) ||
4865 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4866 return(0);
4867
William M. Brack0c022ad2002-07-12 00:56:01 +00004868 ns = arg->nodesetval;
4869 if (ns != NULL) {
4870 for (i=0;i<ns->nodeNr;i++) {
4871 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4872 if (str2 != NULL) {
4873 valuePush(ctxt, xmlXPathNewString(str2));
4874 xmlFree(str2);
4875 xmlXPathNumberFunction(ctxt, 1);
4876 val = valuePop(ctxt);
4877 v = val->floatval;
4878 xmlXPathFreeObject(val);
4879 if (!xmlXPathIsNaN(v)) {
4880 if ((!neq) && (v==f)) {
4881 ret = 1;
4882 break;
4883 } else if ((neq) && (v!=f)) {
4884 ret = 1;
4885 break;
4886 }
William M. Brack32f0f712005-07-14 07:00:33 +00004887 } else { /* NaN is unequal to any value */
4888 if (neq)
4889 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00004890 }
4891 }
4892 }
4893 }
4894
4895 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004896}
4897
4898
4899/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004900 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004901 * @arg1: first nodeset object argument
4902 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004903 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004904 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004905 * Implement the equal / not equal operation on XPath nodesets:
4906 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004907 * If both objects to be compared are node-sets, then the comparison
4908 * will be true if and only if there is a node in the first node-set and
4909 * a node in the second node-set such that the result of performing the
4910 * comparison on the string-values of the two nodes is true.
4911 *
4912 * (needless to say, this is a costly operation)
4913 *
4914 * Returns 0 or 1 depending on the results of the test.
4915 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004916static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004917xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004918 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004919 unsigned int *hashs1;
4920 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004921 xmlChar **values1;
4922 xmlChar **values2;
4923 int ret = 0;
4924 xmlNodeSetPtr ns1;
4925 xmlNodeSetPtr ns2;
4926
4927 if ((arg1 == NULL) ||
4928 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4929 return(0);
4930 if ((arg2 == NULL) ||
4931 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4932 return(0);
4933
4934 ns1 = arg1->nodesetval;
4935 ns2 = arg2->nodesetval;
4936
Daniel Veillard911f49a2001-04-07 15:39:35 +00004937 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004938 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004939 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004940 return(0);
4941
4942 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004943 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004944 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004945 if (neq == 0)
4946 for (i = 0;i < ns1->nodeNr;i++)
4947 for (j = 0;j < ns2->nodeNr;j++)
4948 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4949 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004950
4951 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004952 if (values1 == NULL) {
4953 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004954 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004955 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004956 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4957 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004958 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004959 xmlFree(values1);
4960 return(0);
4961 }
Owen Taylor3473f882001-02-23 17:55:21 +00004962 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4963 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4964 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004965 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004966 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004967 xmlFree(values1);
4968 return(0);
4969 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004970 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4971 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004972 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004973 xmlFree(hashs1);
4974 xmlFree(values1);
4975 xmlFree(values2);
4976 return(0);
4977 }
Owen Taylor3473f882001-02-23 17:55:21 +00004978 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4979 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004980 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004981 for (j = 0;j < ns2->nodeNr;j++) {
4982 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004983 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004984 if (hashs1[i] != hashs2[j]) {
4985 if (neq) {
4986 ret = 1;
4987 break;
4988 }
4989 }
4990 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004991 if (values1[i] == NULL)
4992 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4993 if (values2[j] == NULL)
4994 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004995 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004996 if (ret)
4997 break;
4998 }
Owen Taylor3473f882001-02-23 17:55:21 +00004999 }
5000 if (ret)
5001 break;
5002 }
5003 for (i = 0;i < ns1->nodeNr;i++)
5004 if (values1[i] != NULL)
5005 xmlFree(values1[i]);
5006 for (j = 0;j < ns2->nodeNr;j++)
5007 if (values2[j] != NULL)
5008 xmlFree(values2[j]);
5009 xmlFree(values1);
5010 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005011 xmlFree(hashs1);
5012 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00005013 return(ret);
5014}
5015
William M. Brack0c022ad2002-07-12 00:56:01 +00005016static int
5017xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5018 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00005019 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00005020 /*
5021 *At this point we are assured neither arg1 nor arg2
5022 *is a nodeset, so we can just pick the appropriate routine.
5023 */
Owen Taylor3473f882001-02-23 17:55:21 +00005024 switch (arg1->type) {
5025 case XPATH_UNDEFINED:
5026#ifdef DEBUG_EXPR
5027 xmlGenericError(xmlGenericErrorContext,
5028 "Equal: undefined\n");
5029#endif
5030 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005031 case XPATH_BOOLEAN:
5032 switch (arg2->type) {
5033 case XPATH_UNDEFINED:
5034#ifdef DEBUG_EXPR
5035 xmlGenericError(xmlGenericErrorContext,
5036 "Equal: undefined\n");
5037#endif
5038 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005039 case XPATH_BOOLEAN:
5040#ifdef DEBUG_EXPR
5041 xmlGenericError(xmlGenericErrorContext,
5042 "Equal: %d boolean %d \n",
5043 arg1->boolval, arg2->boolval);
5044#endif
5045 ret = (arg1->boolval == arg2->boolval);
5046 break;
5047 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00005048 ret = (arg1->boolval ==
5049 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00005050 break;
5051 case XPATH_STRING:
5052 if ((arg2->stringval == NULL) ||
5053 (arg2->stringval[0] == 0)) ret = 0;
5054 else
5055 ret = 1;
5056 ret = (arg1->boolval == ret);
5057 break;
5058 case XPATH_USERS:
5059 case XPATH_POINT:
5060 case XPATH_RANGE:
5061 case XPATH_LOCATIONSET:
5062 TODO
5063 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005064 case XPATH_NODESET:
5065 case XPATH_XSLT_TREE:
5066 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005067 }
5068 break;
5069 case XPATH_NUMBER:
5070 switch (arg2->type) {
5071 case XPATH_UNDEFINED:
5072#ifdef DEBUG_EXPR
5073 xmlGenericError(xmlGenericErrorContext,
5074 "Equal: undefined\n");
5075#endif
5076 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005077 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00005078 ret = (arg2->boolval==
5079 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00005080 break;
5081 case XPATH_STRING:
5082 valuePush(ctxt, arg2);
5083 xmlXPathNumberFunction(ctxt, 1);
5084 arg2 = valuePop(ctxt);
5085 /* no break on purpose */
5086 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005087 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00005088 if (xmlXPathIsNaN(arg1->floatval) ||
5089 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00005090 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005091 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5092 if (xmlXPathIsInf(arg2->floatval) == 1)
5093 ret = 1;
5094 else
5095 ret = 0;
5096 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5097 if (xmlXPathIsInf(arg2->floatval) == -1)
5098 ret = 1;
5099 else
5100 ret = 0;
5101 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5102 if (xmlXPathIsInf(arg1->floatval) == 1)
5103 ret = 1;
5104 else
5105 ret = 0;
5106 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5107 if (xmlXPathIsInf(arg1->floatval) == -1)
5108 ret = 1;
5109 else
5110 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005111 } else {
5112 ret = (arg1->floatval == arg2->floatval);
5113 }
Owen Taylor3473f882001-02-23 17:55:21 +00005114 break;
5115 case XPATH_USERS:
5116 case XPATH_POINT:
5117 case XPATH_RANGE:
5118 case XPATH_LOCATIONSET:
5119 TODO
5120 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005121 case XPATH_NODESET:
5122 case XPATH_XSLT_TREE:
5123 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005124 }
5125 break;
5126 case XPATH_STRING:
5127 switch (arg2->type) {
5128 case XPATH_UNDEFINED:
5129#ifdef DEBUG_EXPR
5130 xmlGenericError(xmlGenericErrorContext,
5131 "Equal: undefined\n");
5132#endif
5133 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005134 case XPATH_BOOLEAN:
5135 if ((arg1->stringval == NULL) ||
5136 (arg1->stringval[0] == 0)) ret = 0;
5137 else
5138 ret = 1;
5139 ret = (arg2->boolval == ret);
5140 break;
5141 case XPATH_STRING:
5142 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5143 break;
5144 case XPATH_NUMBER:
5145 valuePush(ctxt, arg1);
5146 xmlXPathNumberFunction(ctxt, 1);
5147 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005148 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00005149 if (xmlXPathIsNaN(arg1->floatval) ||
5150 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00005151 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005152 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5153 if (xmlXPathIsInf(arg2->floatval) == 1)
5154 ret = 1;
5155 else
5156 ret = 0;
5157 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5158 if (xmlXPathIsInf(arg2->floatval) == -1)
5159 ret = 1;
5160 else
5161 ret = 0;
5162 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5163 if (xmlXPathIsInf(arg1->floatval) == 1)
5164 ret = 1;
5165 else
5166 ret = 0;
5167 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5168 if (xmlXPathIsInf(arg1->floatval) == -1)
5169 ret = 1;
5170 else
5171 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005172 } else {
5173 ret = (arg1->floatval == arg2->floatval);
5174 }
Owen Taylor3473f882001-02-23 17:55:21 +00005175 break;
5176 case XPATH_USERS:
5177 case XPATH_POINT:
5178 case XPATH_RANGE:
5179 case XPATH_LOCATIONSET:
5180 TODO
5181 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005182 case XPATH_NODESET:
5183 case XPATH_XSLT_TREE:
5184 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005185 }
5186 break;
5187 case XPATH_USERS:
5188 case XPATH_POINT:
5189 case XPATH_RANGE:
5190 case XPATH_LOCATIONSET:
5191 TODO
5192 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005193 case XPATH_NODESET:
5194 case XPATH_XSLT_TREE:
5195 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005196 }
5197 xmlXPathFreeObject(arg1);
5198 xmlXPathFreeObject(arg2);
5199 return(ret);
5200}
5201
William M. Brack0c022ad2002-07-12 00:56:01 +00005202/**
5203 * xmlXPathEqualValues:
5204 * @ctxt: the XPath Parser context
5205 *
5206 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5207 *
5208 * Returns 0 or 1 depending on the results of the test.
5209 */
5210int
5211xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5212 xmlXPathObjectPtr arg1, arg2, argtmp;
5213 int ret = 0;
5214
Daniel Veillard6128c012004-11-08 17:16:15 +00005215 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005216 arg2 = valuePop(ctxt);
5217 arg1 = valuePop(ctxt);
5218 if ((arg1 == NULL) || (arg2 == NULL)) {
5219 if (arg1 != NULL)
5220 xmlXPathFreeObject(arg1);
5221 else
5222 xmlXPathFreeObject(arg2);
5223 XP_ERROR0(XPATH_INVALID_OPERAND);
5224 }
5225
5226 if (arg1 == arg2) {
5227#ifdef DEBUG_EXPR
5228 xmlGenericError(xmlGenericErrorContext,
5229 "Equal: by pointer\n");
5230#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005231 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005232 return(1);
5233 }
5234
5235 /*
5236 *If either argument is a nodeset, it's a 'special case'
5237 */
5238 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5239 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5240 /*
5241 *Hack it to assure arg1 is the nodeset
5242 */
5243 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5244 argtmp = arg2;
5245 arg2 = arg1;
5246 arg1 = argtmp;
5247 }
5248 switch (arg2->type) {
5249 case XPATH_UNDEFINED:
5250#ifdef DEBUG_EXPR
5251 xmlGenericError(xmlGenericErrorContext,
5252 "Equal: undefined\n");
5253#endif
5254 break;
5255 case XPATH_NODESET:
5256 case XPATH_XSLT_TREE:
5257 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
5258 break;
5259 case XPATH_BOOLEAN:
5260 if ((arg1->nodesetval == NULL) ||
5261 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5262 else
5263 ret = 1;
5264 ret = (ret == arg2->boolval);
5265 break;
5266 case XPATH_NUMBER:
5267 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5268 break;
5269 case XPATH_STRING:
5270 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
5271 break;
5272 case XPATH_USERS:
5273 case XPATH_POINT:
5274 case XPATH_RANGE:
5275 case XPATH_LOCATIONSET:
5276 TODO
5277 break;
5278 }
5279 xmlXPathFreeObject(arg1);
5280 xmlXPathFreeObject(arg2);
5281 return(ret);
5282 }
5283
5284 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5285}
5286
5287/**
5288 * xmlXPathNotEqualValues:
5289 * @ctxt: the XPath Parser context
5290 *
5291 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5292 *
5293 * Returns 0 or 1 depending on the results of the test.
5294 */
5295int
5296xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
5297 xmlXPathObjectPtr arg1, arg2, argtmp;
5298 int ret = 0;
5299
Daniel Veillard6128c012004-11-08 17:16:15 +00005300 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005301 arg2 = valuePop(ctxt);
5302 arg1 = valuePop(ctxt);
5303 if ((arg1 == NULL) || (arg2 == NULL)) {
5304 if (arg1 != NULL)
5305 xmlXPathFreeObject(arg1);
5306 else
5307 xmlXPathFreeObject(arg2);
5308 XP_ERROR0(XPATH_INVALID_OPERAND);
5309 }
5310
5311 if (arg1 == arg2) {
5312#ifdef DEBUG_EXPR
5313 xmlGenericError(xmlGenericErrorContext,
5314 "NotEqual: by pointer\n");
5315#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005316 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005317 return(0);
5318 }
5319
5320 /*
5321 *If either argument is a nodeset, it's a 'special case'
5322 */
5323 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5324 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5325 /*
5326 *Hack it to assure arg1 is the nodeset
5327 */
5328 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5329 argtmp = arg2;
5330 arg2 = arg1;
5331 arg1 = argtmp;
5332 }
5333 switch (arg2->type) {
5334 case XPATH_UNDEFINED:
5335#ifdef DEBUG_EXPR
5336 xmlGenericError(xmlGenericErrorContext,
5337 "NotEqual: undefined\n");
5338#endif
5339 break;
5340 case XPATH_NODESET:
5341 case XPATH_XSLT_TREE:
5342 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5343 break;
5344 case XPATH_BOOLEAN:
5345 if ((arg1->nodesetval == NULL) ||
5346 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5347 else
5348 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005349 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005350 break;
5351 case XPATH_NUMBER:
5352 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5353 break;
5354 case XPATH_STRING:
5355 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5356 break;
5357 case XPATH_USERS:
5358 case XPATH_POINT:
5359 case XPATH_RANGE:
5360 case XPATH_LOCATIONSET:
5361 TODO
5362 break;
5363 }
5364 xmlXPathFreeObject(arg1);
5365 xmlXPathFreeObject(arg2);
5366 return(ret);
5367 }
5368
5369 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5370}
Owen Taylor3473f882001-02-23 17:55:21 +00005371
5372/**
5373 * xmlXPathCompareValues:
5374 * @ctxt: the XPath Parser context
5375 * @inf: less than (1) or greater than (0)
5376 * @strict: is the comparison strict
5377 *
5378 * Implement the compare operation on XPath objects:
5379 * @arg1 < @arg2 (1, 1, ...
5380 * @arg1 <= @arg2 (1, 0, ...
5381 * @arg1 > @arg2 (0, 1, ...
5382 * @arg1 >= @arg2 (0, 0, ...
5383 *
5384 * When neither object to be compared is a node-set and the operator is
5385 * <=, <, >=, >, then the objects are compared by converted both objects
5386 * to numbers and comparing the numbers according to IEEE 754. The <
5387 * comparison will be true if and only if the first number is less than the
5388 * second number. The <= comparison will be true if and only if the first
5389 * number is less than or equal to the second number. The > comparison
5390 * will be true if and only if the first number is greater than the second
5391 * number. The >= comparison will be true if and only if the first number
5392 * is greater than or equal to the second number.
5393 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005394 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005395 */
5396int
5397xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005398 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005399 xmlXPathObjectPtr arg1, arg2;
5400
Daniel Veillard6128c012004-11-08 17:16:15 +00005401 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005402 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005403 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005404 if ((arg1 == NULL) || (arg2 == NULL)) {
5405 if (arg1 != NULL)
5406 xmlXPathFreeObject(arg1);
5407 else
5408 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005409 XP_ERROR0(XPATH_INVALID_OPERAND);
5410 }
5411
William M. Brack0c022ad2002-07-12 00:56:01 +00005412 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5413 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00005414 /*
5415 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5416 * are not freed from within this routine; they will be freed from the
5417 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5418 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005419 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5420 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005421 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005422 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005423 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005424 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5425 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005426 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005427 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5428 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005429 }
5430 }
5431 return(ret);
5432 }
5433
5434 if (arg1->type != XPATH_NUMBER) {
5435 valuePush(ctxt, arg1);
5436 xmlXPathNumberFunction(ctxt, 1);
5437 arg1 = valuePop(ctxt);
5438 }
5439 if (arg1->type != XPATH_NUMBER) {
5440 xmlXPathFreeObject(arg1);
5441 xmlXPathFreeObject(arg2);
5442 XP_ERROR0(XPATH_INVALID_OPERAND);
5443 }
5444 if (arg2->type != XPATH_NUMBER) {
5445 valuePush(ctxt, arg2);
5446 xmlXPathNumberFunction(ctxt, 1);
5447 arg2 = valuePop(ctxt);
5448 }
5449 if (arg2->type != XPATH_NUMBER) {
5450 xmlXPathFreeObject(arg1);
5451 xmlXPathFreeObject(arg2);
5452 XP_ERROR0(XPATH_INVALID_OPERAND);
5453 }
5454 /*
5455 * Add tests for infinity and nan
5456 * => feedback on 3.4 for Inf and NaN
5457 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005458 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005459 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005460 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005461 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005462 arg1i=xmlXPathIsInf(arg1->floatval);
5463 arg2i=xmlXPathIsInf(arg2->floatval);
5464 if (inf && strict) {
5465 if ((arg1i == -1 && arg2i != -1) ||
5466 (arg2i == 1 && arg1i != 1)) {
5467 ret = 1;
5468 } else if (arg1i == 0 && arg2i == 0) {
5469 ret = (arg1->floatval < arg2->floatval);
5470 } else {
5471 ret = 0;
5472 }
5473 }
5474 else if (inf && !strict) {
5475 if (arg1i == -1 || arg2i == 1) {
5476 ret = 1;
5477 } else if (arg1i == 0 && arg2i == 0) {
5478 ret = (arg1->floatval <= arg2->floatval);
5479 } else {
5480 ret = 0;
5481 }
5482 }
5483 else if (!inf && strict) {
5484 if ((arg1i == 1 && arg2i != 1) ||
5485 (arg2i == -1 && arg1i != -1)) {
5486 ret = 1;
5487 } else if (arg1i == 0 && arg2i == 0) {
5488 ret = (arg1->floatval > arg2->floatval);
5489 } else {
5490 ret = 0;
5491 }
5492 }
5493 else if (!inf && !strict) {
5494 if (arg1i == 1 || arg2i == -1) {
5495 ret = 1;
5496 } else if (arg1i == 0 && arg2i == 0) {
5497 ret = (arg1->floatval >= arg2->floatval);
5498 } else {
5499 ret = 0;
5500 }
5501 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005502 }
Owen Taylor3473f882001-02-23 17:55:21 +00005503 xmlXPathFreeObject(arg1);
5504 xmlXPathFreeObject(arg2);
5505 return(ret);
5506}
5507
5508/**
5509 * xmlXPathValueFlipSign:
5510 * @ctxt: the XPath Parser context
5511 *
5512 * Implement the unary - operation on an XPath object
5513 * The numeric operators convert their operands to numbers as if
5514 * by calling the number function.
5515 */
5516void
5517xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005518 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005519 CAST_TO_NUMBER;
5520 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005521 if (xmlXPathIsNaN(ctxt->value->floatval))
5522 ctxt->value->floatval=xmlXPathNAN;
5523 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5524 ctxt->value->floatval=xmlXPathNINF;
5525 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5526 ctxt->value->floatval=xmlXPathPINF;
5527 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005528 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5529 ctxt->value->floatval = xmlXPathNZERO;
5530 else
5531 ctxt->value->floatval = 0;
5532 }
5533 else
5534 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005535}
5536
5537/**
5538 * xmlXPathAddValues:
5539 * @ctxt: the XPath Parser context
5540 *
5541 * Implement the add operation on XPath objects:
5542 * The numeric operators convert their operands to numbers as if
5543 * by calling the number function.
5544 */
5545void
5546xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5547 xmlXPathObjectPtr arg;
5548 double val;
5549
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005550 arg = valuePop(ctxt);
5551 if (arg == NULL)
5552 XP_ERROR(XPATH_INVALID_OPERAND);
5553 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005554 xmlXPathFreeObject(arg);
5555
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005556 CAST_TO_NUMBER;
5557 CHECK_TYPE(XPATH_NUMBER);
5558 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005559}
5560
5561/**
5562 * xmlXPathSubValues:
5563 * @ctxt: the XPath Parser context
5564 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005565 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005566 * The numeric operators convert their operands to numbers as if
5567 * by calling the number function.
5568 */
5569void
5570xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5571 xmlXPathObjectPtr arg;
5572 double val;
5573
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005574 arg = valuePop(ctxt);
5575 if (arg == NULL)
5576 XP_ERROR(XPATH_INVALID_OPERAND);
5577 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005578 xmlXPathFreeObject(arg);
5579
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005580 CAST_TO_NUMBER;
5581 CHECK_TYPE(XPATH_NUMBER);
5582 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005583}
5584
5585/**
5586 * xmlXPathMultValues:
5587 * @ctxt: the XPath Parser context
5588 *
5589 * Implement the multiply operation on XPath objects:
5590 * The numeric operators convert their operands to numbers as if
5591 * by calling the number function.
5592 */
5593void
5594xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5595 xmlXPathObjectPtr arg;
5596 double val;
5597
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005598 arg = valuePop(ctxt);
5599 if (arg == NULL)
5600 XP_ERROR(XPATH_INVALID_OPERAND);
5601 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005602 xmlXPathFreeObject(arg);
5603
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005604 CAST_TO_NUMBER;
5605 CHECK_TYPE(XPATH_NUMBER);
5606 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005607}
5608
5609/**
5610 * xmlXPathDivValues:
5611 * @ctxt: the XPath Parser context
5612 *
5613 * Implement the div operation on XPath objects @arg1 / @arg2:
5614 * The numeric operators convert their operands to numbers as if
5615 * by calling the number function.
5616 */
5617void
5618xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5619 xmlXPathObjectPtr arg;
5620 double val;
5621
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005622 arg = valuePop(ctxt);
5623 if (arg == NULL)
5624 XP_ERROR(XPATH_INVALID_OPERAND);
5625 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005626 xmlXPathFreeObject(arg);
5627
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005628 CAST_TO_NUMBER;
5629 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005630 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5631 ctxt->value->floatval = xmlXPathNAN;
5632 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005633 if (ctxt->value->floatval == 0)
5634 ctxt->value->floatval = xmlXPathNAN;
5635 else if (ctxt->value->floatval > 0)
5636 ctxt->value->floatval = xmlXPathNINF;
5637 else if (ctxt->value->floatval < 0)
5638 ctxt->value->floatval = xmlXPathPINF;
5639 }
5640 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005641 if (ctxt->value->floatval == 0)
5642 ctxt->value->floatval = xmlXPathNAN;
5643 else if (ctxt->value->floatval > 0)
5644 ctxt->value->floatval = xmlXPathPINF;
5645 else if (ctxt->value->floatval < 0)
5646 ctxt->value->floatval = xmlXPathNINF;
5647 } else
5648 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005649}
5650
5651/**
5652 * xmlXPathModValues:
5653 * @ctxt: the XPath Parser context
5654 *
5655 * Implement the mod operation on XPath objects: @arg1 / @arg2
5656 * The numeric operators convert their operands to numbers as if
5657 * by calling the number function.
5658 */
5659void
5660xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5661 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005662 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005663
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005664 arg = valuePop(ctxt);
5665 if (arg == NULL)
5666 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005667 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005668 xmlXPathFreeObject(arg);
5669
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005670 CAST_TO_NUMBER;
5671 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005672 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005673 if (arg2 == 0)
5674 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005675 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005676 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005677 }
Owen Taylor3473f882001-02-23 17:55:21 +00005678}
5679
5680/************************************************************************
5681 * *
5682 * The traversal functions *
5683 * *
5684 ************************************************************************/
5685
Owen Taylor3473f882001-02-23 17:55:21 +00005686/*
5687 * A traversal function enumerates nodes along an axis.
5688 * Initially it must be called with NULL, and it indicates
5689 * termination on the axis by returning NULL.
5690 */
5691typedef xmlNodePtr (*xmlXPathTraversalFunction)
5692 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5693
5694/**
5695 * xmlXPathNextSelf:
5696 * @ctxt: the XPath Parser context
5697 * @cur: the current node in the traversal
5698 *
5699 * Traversal function for the "self" direction
5700 * The self axis contains just the context node itself
5701 *
5702 * Returns the next element following that axis
5703 */
5704xmlNodePtr
5705xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005706 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005707 if (cur == NULL)
5708 return(ctxt->context->node);
5709 return(NULL);
5710}
5711
5712/**
5713 * xmlXPathNextChild:
5714 * @ctxt: the XPath Parser context
5715 * @cur: the current node in the traversal
5716 *
5717 * Traversal function for the "child" direction
5718 * The child axis contains the children of the context node in document order.
5719 *
5720 * Returns the next element following that axis
5721 */
5722xmlNodePtr
5723xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005724 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005725 if (cur == NULL) {
5726 if (ctxt->context->node == NULL) return(NULL);
5727 switch (ctxt->context->node->type) {
5728 case XML_ELEMENT_NODE:
5729 case XML_TEXT_NODE:
5730 case XML_CDATA_SECTION_NODE:
5731 case XML_ENTITY_REF_NODE:
5732 case XML_ENTITY_NODE:
5733 case XML_PI_NODE:
5734 case XML_COMMENT_NODE:
5735 case XML_NOTATION_NODE:
5736 case XML_DTD_NODE:
5737 return(ctxt->context->node->children);
5738 case XML_DOCUMENT_NODE:
5739 case XML_DOCUMENT_TYPE_NODE:
5740 case XML_DOCUMENT_FRAG_NODE:
5741 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005742#ifdef LIBXML_DOCB_ENABLED
5743 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005744#endif
5745 return(((xmlDocPtr) ctxt->context->node)->children);
5746 case XML_ELEMENT_DECL:
5747 case XML_ATTRIBUTE_DECL:
5748 case XML_ENTITY_DECL:
5749 case XML_ATTRIBUTE_NODE:
5750 case XML_NAMESPACE_DECL:
5751 case XML_XINCLUDE_START:
5752 case XML_XINCLUDE_END:
5753 return(NULL);
5754 }
5755 return(NULL);
5756 }
5757 if ((cur->type == XML_DOCUMENT_NODE) ||
5758 (cur->type == XML_HTML_DOCUMENT_NODE))
5759 return(NULL);
5760 return(cur->next);
5761}
5762
5763/**
5764 * xmlXPathNextDescendant:
5765 * @ctxt: the XPath Parser context
5766 * @cur: the current node in the traversal
5767 *
5768 * Traversal function for the "descendant" direction
5769 * the descendant axis contains the descendants of the context node in document
5770 * order; a descendant is a child or a child of a child and so on.
5771 *
5772 * Returns the next element following that axis
5773 */
5774xmlNodePtr
5775xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005776 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005777 if (cur == NULL) {
5778 if (ctxt->context->node == NULL)
5779 return(NULL);
5780 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5781 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5782 return(NULL);
5783
5784 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5785 return(ctxt->context->doc->children);
5786 return(ctxt->context->node->children);
5787 }
5788
Daniel Veillard567e1b42001-08-01 15:53:47 +00005789 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005790 /*
5791 * Do not descend on entities declarations
5792 */
5793 if (cur->children->type != XML_ENTITY_DECL) {
5794 cur = cur->children;
5795 /*
5796 * Skip DTDs
5797 */
5798 if (cur->type != XML_DTD_NODE)
5799 return(cur);
5800 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005801 }
5802
5803 if (cur == ctxt->context->node) return(NULL);
5804
Daniel Veillard68e9e742002-11-16 15:35:11 +00005805 while (cur->next != NULL) {
5806 cur = cur->next;
5807 if ((cur->type != XML_ENTITY_DECL) &&
5808 (cur->type != XML_DTD_NODE))
5809 return(cur);
5810 }
Owen Taylor3473f882001-02-23 17:55:21 +00005811
5812 do {
5813 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00005814 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00005815 if (cur == ctxt->context->node) return(NULL);
5816 if (cur->next != NULL) {
5817 cur = cur->next;
5818 return(cur);
5819 }
5820 } while (cur != NULL);
5821 return(cur);
5822}
5823
5824/**
5825 * xmlXPathNextDescendantOrSelf:
5826 * @ctxt: the XPath Parser context
5827 * @cur: the current node in the traversal
5828 *
5829 * Traversal function for the "descendant-or-self" direction
5830 * the descendant-or-self axis contains the context node and the descendants
5831 * of the context node in document order; thus the context node is the first
5832 * node on the axis, and the first child of the context node is the second node
5833 * on the axis
5834 *
5835 * Returns the next element following that axis
5836 */
5837xmlNodePtr
5838xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005839 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005840 if (cur == NULL) {
5841 if (ctxt->context->node == NULL)
5842 return(NULL);
5843 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5844 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5845 return(NULL);
5846 return(ctxt->context->node);
5847 }
5848
5849 return(xmlXPathNextDescendant(ctxt, cur));
5850}
5851
5852/**
5853 * xmlXPathNextParent:
5854 * @ctxt: the XPath Parser context
5855 * @cur: the current node in the traversal
5856 *
5857 * Traversal function for the "parent" direction
5858 * The parent axis contains the parent of the context node, if there is one.
5859 *
5860 * Returns the next element following that axis
5861 */
5862xmlNodePtr
5863xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005864 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005865 /*
5866 * the parent of an attribute or namespace node is the element
5867 * to which the attribute or namespace node is attached
5868 * Namespace handling !!!
5869 */
5870 if (cur == NULL) {
5871 if (ctxt->context->node == NULL) return(NULL);
5872 switch (ctxt->context->node->type) {
5873 case XML_ELEMENT_NODE:
5874 case XML_TEXT_NODE:
5875 case XML_CDATA_SECTION_NODE:
5876 case XML_ENTITY_REF_NODE:
5877 case XML_ENTITY_NODE:
5878 case XML_PI_NODE:
5879 case XML_COMMENT_NODE:
5880 case XML_NOTATION_NODE:
5881 case XML_DTD_NODE:
5882 case XML_ELEMENT_DECL:
5883 case XML_ATTRIBUTE_DECL:
5884 case XML_XINCLUDE_START:
5885 case XML_XINCLUDE_END:
5886 case XML_ENTITY_DECL:
5887 if (ctxt->context->node->parent == NULL)
5888 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005889 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005890 ((ctxt->context->node->parent->name[0] == ' ') ||
5891 (xmlStrEqual(ctxt->context->node->parent->name,
5892 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005893 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005894 return(ctxt->context->node->parent);
5895 case XML_ATTRIBUTE_NODE: {
5896 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5897
5898 return(att->parent);
5899 }
5900 case XML_DOCUMENT_NODE:
5901 case XML_DOCUMENT_TYPE_NODE:
5902 case XML_DOCUMENT_FRAG_NODE:
5903 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005904#ifdef LIBXML_DOCB_ENABLED
5905 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005906#endif
5907 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005908 case XML_NAMESPACE_DECL: {
5909 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5910
5911 if ((ns->next != NULL) &&
5912 (ns->next->type != XML_NAMESPACE_DECL))
5913 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005914 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005915 }
Owen Taylor3473f882001-02-23 17:55:21 +00005916 }
5917 }
5918 return(NULL);
5919}
5920
5921/**
5922 * xmlXPathNextAncestor:
5923 * @ctxt: the XPath Parser context
5924 * @cur: the current node in the traversal
5925 *
5926 * Traversal function for the "ancestor" direction
5927 * the ancestor axis contains the ancestors of the context node; the ancestors
5928 * of the context node consist of the parent of context node and the parent's
5929 * parent and so on; the nodes are ordered in reverse document order; thus the
5930 * parent is the first node on the axis, and the parent's parent is the second
5931 * node on the axis
5932 *
5933 * Returns the next element following that axis
5934 */
5935xmlNodePtr
5936xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005937 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005938 /*
5939 * the parent of an attribute or namespace node is the element
5940 * to which the attribute or namespace node is attached
5941 * !!!!!!!!!!!!!
5942 */
5943 if (cur == NULL) {
5944 if (ctxt->context->node == NULL) return(NULL);
5945 switch (ctxt->context->node->type) {
5946 case XML_ELEMENT_NODE:
5947 case XML_TEXT_NODE:
5948 case XML_CDATA_SECTION_NODE:
5949 case XML_ENTITY_REF_NODE:
5950 case XML_ENTITY_NODE:
5951 case XML_PI_NODE:
5952 case XML_COMMENT_NODE:
5953 case XML_DTD_NODE:
5954 case XML_ELEMENT_DECL:
5955 case XML_ATTRIBUTE_DECL:
5956 case XML_ENTITY_DECL:
5957 case XML_NOTATION_NODE:
5958 case XML_XINCLUDE_START:
5959 case XML_XINCLUDE_END:
5960 if (ctxt->context->node->parent == NULL)
5961 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005962 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005963 ((ctxt->context->node->parent->name[0] == ' ') ||
5964 (xmlStrEqual(ctxt->context->node->parent->name,
5965 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005966 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005967 return(ctxt->context->node->parent);
5968 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005969 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005970
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005971 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005972 }
5973 case XML_DOCUMENT_NODE:
5974 case XML_DOCUMENT_TYPE_NODE:
5975 case XML_DOCUMENT_FRAG_NODE:
5976 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005977#ifdef LIBXML_DOCB_ENABLED
5978 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005979#endif
5980 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005981 case XML_NAMESPACE_DECL: {
5982 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5983
5984 if ((ns->next != NULL) &&
5985 (ns->next->type != XML_NAMESPACE_DECL))
5986 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005987 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005988 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005989 }
Owen Taylor3473f882001-02-23 17:55:21 +00005990 }
5991 return(NULL);
5992 }
5993 if (cur == ctxt->context->doc->children)
5994 return((xmlNodePtr) ctxt->context->doc);
5995 if (cur == (xmlNodePtr) ctxt->context->doc)
5996 return(NULL);
5997 switch (cur->type) {
5998 case XML_ELEMENT_NODE:
5999 case XML_TEXT_NODE:
6000 case XML_CDATA_SECTION_NODE:
6001 case XML_ENTITY_REF_NODE:
6002 case XML_ENTITY_NODE:
6003 case XML_PI_NODE:
6004 case XML_COMMENT_NODE:
6005 case XML_NOTATION_NODE:
6006 case XML_DTD_NODE:
6007 case XML_ELEMENT_DECL:
6008 case XML_ATTRIBUTE_DECL:
6009 case XML_ENTITY_DECL:
6010 case XML_XINCLUDE_START:
6011 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006012 if (cur->parent == NULL)
6013 return(NULL);
6014 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00006015 ((cur->parent->name[0] == ' ') ||
6016 (xmlStrEqual(cur->parent->name,
6017 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006018 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006019 return(cur->parent);
6020 case XML_ATTRIBUTE_NODE: {
6021 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6022
6023 return(att->parent);
6024 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00006025 case XML_NAMESPACE_DECL: {
6026 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6027
6028 if ((ns->next != NULL) &&
6029 (ns->next->type != XML_NAMESPACE_DECL))
6030 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00006031 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00006032 return(NULL);
6033 }
Owen Taylor3473f882001-02-23 17:55:21 +00006034 case XML_DOCUMENT_NODE:
6035 case XML_DOCUMENT_TYPE_NODE:
6036 case XML_DOCUMENT_FRAG_NODE:
6037 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00006038#ifdef LIBXML_DOCB_ENABLED
6039 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00006040#endif
6041 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006042 }
6043 return(NULL);
6044}
6045
6046/**
6047 * xmlXPathNextAncestorOrSelf:
6048 * @ctxt: the XPath Parser context
6049 * @cur: the current node in the traversal
6050 *
6051 * Traversal function for the "ancestor-or-self" direction
6052 * he ancestor-or-self axis contains the context node and ancestors of
6053 * the context node in reverse document order; thus the context node is
6054 * the first node on the axis, and the context node's parent the second;
6055 * parent here is defined the same as with the parent axis.
6056 *
6057 * Returns the next element following that axis
6058 */
6059xmlNodePtr
6060xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006061 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006062 if (cur == NULL)
6063 return(ctxt->context->node);
6064 return(xmlXPathNextAncestor(ctxt, cur));
6065}
6066
6067/**
6068 * xmlXPathNextFollowingSibling:
6069 * @ctxt: the XPath Parser context
6070 * @cur: the current node in the traversal
6071 *
6072 * Traversal function for the "following-sibling" direction
6073 * The following-sibling axis contains the following siblings of the context
6074 * node in document order.
6075 *
6076 * Returns the next element following that axis
6077 */
6078xmlNodePtr
6079xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006080 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006081 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6082 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6083 return(NULL);
6084 if (cur == (xmlNodePtr) ctxt->context->doc)
6085 return(NULL);
6086 if (cur == NULL)
6087 return(ctxt->context->node->next);
6088 return(cur->next);
6089}
6090
6091/**
6092 * xmlXPathNextPrecedingSibling:
6093 * @ctxt: the XPath Parser context
6094 * @cur: the current node in the traversal
6095 *
6096 * Traversal function for the "preceding-sibling" direction
6097 * The preceding-sibling axis contains the preceding siblings of the context
6098 * node in reverse document order; the first preceding sibling is first on the
6099 * axis; the sibling preceding that node is the second on the axis and so on.
6100 *
6101 * Returns the next element following that axis
6102 */
6103xmlNodePtr
6104xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006105 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006106 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6107 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6108 return(NULL);
6109 if (cur == (xmlNodePtr) ctxt->context->doc)
6110 return(NULL);
6111 if (cur == NULL)
6112 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006113 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6114 cur = cur->prev;
6115 if (cur == NULL)
6116 return(ctxt->context->node->prev);
6117 }
Owen Taylor3473f882001-02-23 17:55:21 +00006118 return(cur->prev);
6119}
6120
6121/**
6122 * xmlXPathNextFollowing:
6123 * @ctxt: the XPath Parser context
6124 * @cur: the current node in the traversal
6125 *
6126 * Traversal function for the "following" direction
6127 * The following axis contains all nodes in the same document as the context
6128 * node that are after the context node in document order, excluding any
6129 * descendants and excluding attribute nodes and namespace nodes; the nodes
6130 * are ordered in document order
6131 *
6132 * Returns the next element following that axis
6133 */
6134xmlNodePtr
6135xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006136 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006137 if (cur != NULL && cur->children != NULL)
6138 return cur->children ;
6139 if (cur == NULL) cur = ctxt->context->node;
6140 if (cur == NULL) return(NULL) ; /* ERROR */
6141 if (cur->next != NULL) return(cur->next) ;
6142 do {
6143 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00006144 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00006145 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6146 if (cur->next != NULL) return(cur->next);
6147 } while (cur != NULL);
6148 return(cur);
6149}
6150
6151/*
6152 * xmlXPathIsAncestor:
6153 * @ancestor: the ancestor node
6154 * @node: the current node
6155 *
6156 * Check that @ancestor is a @node's ancestor
6157 *
6158 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
6159 */
6160static int
6161xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6162 if ((ancestor == NULL) || (node == NULL)) return(0);
6163 /* nodes need to be in the same document */
6164 if (ancestor->doc != node->doc) return(0);
6165 /* avoid searching if ancestor or node is the root node */
6166 if (ancestor == (xmlNodePtr) node->doc) return(1);
6167 if (node == (xmlNodePtr) ancestor->doc) return(0);
6168 while (node->parent != NULL) {
6169 if (node->parent == ancestor)
6170 return(1);
6171 node = node->parent;
6172 }
6173 return(0);
6174}
6175
6176/**
6177 * xmlXPathNextPreceding:
6178 * @ctxt: the XPath Parser context
6179 * @cur: the current node in the traversal
6180 *
6181 * Traversal function for the "preceding" direction
6182 * the preceding axis contains all nodes in the same document as the context
6183 * node that are before the context node in document order, excluding any
6184 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6185 * ordered in reverse document order
6186 *
6187 * Returns the next element following that axis
6188 */
6189xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00006190xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
6191{
Daniel Veillarda82b1822004-11-08 16:24:57 +00006192 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006193 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006194 cur = ctxt->context->node;
6195 if (cur == NULL)
6196 return (NULL);
6197 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6198 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00006199 do {
6200 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006201 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6202 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006203 }
6204
6205 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006206 if (cur == NULL)
6207 return (NULL);
6208 if (cur == ctxt->context->doc->children)
6209 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006210 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00006211 return (cur);
6212}
6213
6214/**
6215 * xmlXPathNextPrecedingInternal:
6216 * @ctxt: the XPath Parser context
6217 * @cur: the current node in the traversal
6218 *
6219 * Traversal function for the "preceding" direction
6220 * the preceding axis contains all nodes in the same document as the context
6221 * node that are before the context node in document order, excluding any
6222 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6223 * ordered in reverse document order
6224 * This is a faster implementation but internal only since it requires a
6225 * state kept in the parser context: ctxt->ancestor.
6226 *
6227 * Returns the next element following that axis
6228 */
6229static xmlNodePtr
6230xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6231 xmlNodePtr cur)
6232{
Daniel Veillarda82b1822004-11-08 16:24:57 +00006233 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006234 if (cur == NULL) {
6235 cur = ctxt->context->node;
6236 if (cur == NULL)
6237 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00006238 if (cur->type == XML_NAMESPACE_DECL)
6239 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006240 ctxt->ancestor = cur->parent;
6241 }
6242 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6243 cur = cur->prev;
6244 while (cur->prev == NULL) {
6245 cur = cur->parent;
6246 if (cur == NULL)
6247 return (NULL);
6248 if (cur == ctxt->context->doc->children)
6249 return (NULL);
6250 if (cur != ctxt->ancestor)
6251 return (cur);
6252 ctxt->ancestor = cur->parent;
6253 }
6254 cur = cur->prev;
6255 while (cur->last != NULL)
6256 cur = cur->last;
6257 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006258}
6259
6260/**
6261 * xmlXPathNextNamespace:
6262 * @ctxt: the XPath Parser context
6263 * @cur: the current attribute in the traversal
6264 *
6265 * Traversal function for the "namespace" direction
6266 * the namespace axis contains the namespace nodes of the context node;
6267 * the order of nodes on this axis is implementation-defined; the axis will
6268 * be empty unless the context node is an element
6269 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00006270 * We keep the XML namespace node at the end of the list.
6271 *
Owen Taylor3473f882001-02-23 17:55:21 +00006272 * Returns the next element following that axis
6273 */
6274xmlNodePtr
6275xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006276 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006277 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00006278 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006279 if (ctxt->context->tmpNsList != NULL)
6280 xmlFree(ctxt->context->tmpNsList);
6281 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00006282 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006283 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00006284 if (ctxt->context->tmpNsList != NULL) {
6285 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6286 ctxt->context->tmpNsNr++;
6287 }
6288 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00006289 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006290 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00006291 if (ctxt->context->tmpNsNr > 0) {
6292 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6293 } else {
6294 if (ctxt->context->tmpNsList != NULL)
6295 xmlFree(ctxt->context->tmpNsList);
6296 ctxt->context->tmpNsList = NULL;
6297 return(NULL);
6298 }
Owen Taylor3473f882001-02-23 17:55:21 +00006299}
6300
6301/**
6302 * xmlXPathNextAttribute:
6303 * @ctxt: the XPath Parser context
6304 * @cur: the current attribute in the traversal
6305 *
6306 * Traversal function for the "attribute" direction
6307 * TODO: support DTD inherited default attributes
6308 *
6309 * Returns the next element following that axis
6310 */
6311xmlNodePtr
6312xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006313 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006314 if (ctxt->context->node == NULL)
6315 return(NULL);
6316 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6317 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006318 if (cur == NULL) {
6319 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6320 return(NULL);
6321 return((xmlNodePtr)ctxt->context->node->properties);
6322 }
6323 return((xmlNodePtr)cur->next);
6324}
6325
6326/************************************************************************
6327 * *
6328 * NodeTest Functions *
6329 * *
6330 ************************************************************************/
6331
Owen Taylor3473f882001-02-23 17:55:21 +00006332#define IS_FUNCTION 200
6333
Owen Taylor3473f882001-02-23 17:55:21 +00006334
6335/************************************************************************
6336 * *
6337 * Implicit tree core function library *
6338 * *
6339 ************************************************************************/
6340
6341/**
6342 * xmlXPathRoot:
6343 * @ctxt: the XPath Parser context
6344 *
6345 * Initialize the context to the root of the document
6346 */
6347void
6348xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006349 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006350 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6351 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6352}
6353
6354/************************************************************************
6355 * *
6356 * The explicit core function library *
6357 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6358 * *
6359 ************************************************************************/
6360
6361
6362/**
6363 * xmlXPathLastFunction:
6364 * @ctxt: the XPath Parser context
6365 * @nargs: the number of arguments
6366 *
6367 * Implement the last() XPath function
6368 * number last()
6369 * The last function returns the number of nodes in the context node list.
6370 */
6371void
6372xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6373 CHECK_ARITY(0);
6374 if (ctxt->context->contextSize >= 0) {
6375 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6376#ifdef DEBUG_EXPR
6377 xmlGenericError(xmlGenericErrorContext,
6378 "last() : %d\n", ctxt->context->contextSize);
6379#endif
6380 } else {
6381 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6382 }
6383}
6384
6385/**
6386 * xmlXPathPositionFunction:
6387 * @ctxt: the XPath Parser context
6388 * @nargs: the number of arguments
6389 *
6390 * Implement the position() XPath function
6391 * number position()
6392 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006393 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006394 * will be equal to last().
6395 */
6396void
6397xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6398 CHECK_ARITY(0);
6399 if (ctxt->context->proximityPosition >= 0) {
6400 valuePush(ctxt,
6401 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6402#ifdef DEBUG_EXPR
6403 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6404 ctxt->context->proximityPosition);
6405#endif
6406 } else {
6407 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6408 }
6409}
6410
6411/**
6412 * xmlXPathCountFunction:
6413 * @ctxt: the XPath Parser context
6414 * @nargs: the number of arguments
6415 *
6416 * Implement the count() XPath function
6417 * number count(node-set)
6418 */
6419void
6420xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6421 xmlXPathObjectPtr cur;
6422
6423 CHECK_ARITY(1);
6424 if ((ctxt->value == NULL) ||
6425 ((ctxt->value->type != XPATH_NODESET) &&
6426 (ctxt->value->type != XPATH_XSLT_TREE)))
6427 XP_ERROR(XPATH_INVALID_TYPE);
6428 cur = valuePop(ctxt);
6429
Daniel Veillard911f49a2001-04-07 15:39:35 +00006430 if ((cur == NULL) || (cur->nodesetval == NULL))
6431 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006432 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006433 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006434 } else {
6435 if ((cur->nodesetval->nodeNr != 1) ||
6436 (cur->nodesetval->nodeTab == NULL)) {
6437 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6438 } else {
6439 xmlNodePtr tmp;
6440 int i = 0;
6441
6442 tmp = cur->nodesetval->nodeTab[0];
6443 if (tmp != NULL) {
6444 tmp = tmp->children;
6445 while (tmp != NULL) {
6446 tmp = tmp->next;
6447 i++;
6448 }
6449 }
6450 valuePush(ctxt, xmlXPathNewFloat((double) i));
6451 }
6452 }
Owen Taylor3473f882001-02-23 17:55:21 +00006453 xmlXPathFreeObject(cur);
6454}
6455
6456/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006457 * xmlXPathGetElementsByIds:
6458 * @doc: the document
6459 * @ids: a whitespace separated list of IDs
6460 *
6461 * Selects elements by their unique ID.
6462 *
6463 * Returns a node-set of selected elements.
6464 */
6465static xmlNodeSetPtr
6466xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6467 xmlNodeSetPtr ret;
6468 const xmlChar *cur = ids;
6469 xmlChar *ID;
6470 xmlAttrPtr attr;
6471 xmlNodePtr elem = NULL;
6472
Daniel Veillard7a985a12003-07-06 17:57:42 +00006473 if (ids == NULL) return(NULL);
6474
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006475 ret = xmlXPathNodeSetCreate(NULL);
6476
William M. Brack76e95df2003-10-18 16:20:14 +00006477 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006478 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006479 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006480 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006481
6482 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006483 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006484 /*
6485 * We used to check the fact that the value passed
6486 * was an NCName, but this generated much troubles for
6487 * me and Aleksey Sanin, people blatantly violated that
6488 * constaint, like Visa3D spec.
6489 * if (xmlValidateNCName(ID, 1) == 0)
6490 */
6491 attr = xmlGetID(doc, ID);
6492 if (attr != NULL) {
6493 if (attr->type == XML_ATTRIBUTE_NODE)
6494 elem = attr->parent;
6495 else if (attr->type == XML_ELEMENT_NODE)
6496 elem = (xmlNodePtr) attr;
6497 else
6498 elem = NULL;
6499 if (elem != NULL)
6500 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006501 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006502 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006503 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006504
William M. Brack76e95df2003-10-18 16:20:14 +00006505 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006506 ids = cur;
6507 }
6508 return(ret);
6509}
6510
6511/**
Owen Taylor3473f882001-02-23 17:55:21 +00006512 * xmlXPathIdFunction:
6513 * @ctxt: the XPath Parser context
6514 * @nargs: the number of arguments
6515 *
6516 * Implement the id() XPath function
6517 * node-set id(object)
6518 * The id function selects elements by their unique ID
6519 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6520 * then the result is the union of the result of applying id to the
6521 * string value of each of the nodes in the argument node-set. When the
6522 * argument to id is of any other type, the argument is converted to a
6523 * string as if by a call to the string function; the string is split
6524 * into a whitespace-separated list of tokens (whitespace is any sequence
6525 * of characters matching the production S); the result is a node-set
6526 * containing the elements in the same document as the context node that
6527 * have a unique ID equal to any of the tokens in the list.
6528 */
6529void
6530xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006531 xmlChar *tokens;
6532 xmlNodeSetPtr ret;
6533 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006534
6535 CHECK_ARITY(1);
6536 obj = valuePop(ctxt);
6537 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006538 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006539 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006540 int i;
6541
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006542 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006543
Daniel Veillard911f49a2001-04-07 15:39:35 +00006544 if (obj->nodesetval != NULL) {
6545 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006546 tokens =
6547 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6548 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6549 ret = xmlXPathNodeSetMerge(ret, ns);
6550 xmlXPathFreeNodeSet(ns);
6551 if (tokens != NULL)
6552 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006553 }
Owen Taylor3473f882001-02-23 17:55:21 +00006554 }
6555
6556 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006557 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006558 return;
6559 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006560 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006561
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006562 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6563 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006564
Owen Taylor3473f882001-02-23 17:55:21 +00006565 xmlXPathFreeObject(obj);
6566 return;
6567}
6568
6569/**
6570 * xmlXPathLocalNameFunction:
6571 * @ctxt: the XPath Parser context
6572 * @nargs: the number of arguments
6573 *
6574 * Implement the local-name() XPath function
6575 * string local-name(node-set?)
6576 * The local-name function returns a string containing the local part
6577 * of the name of the node in the argument node-set that is first in
6578 * document order. If the node-set is empty or the first node has no
6579 * name, an empty string is returned. If the argument is omitted it
6580 * defaults to the context node.
6581 */
6582void
6583xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6584 xmlXPathObjectPtr cur;
6585
Daniel Veillarda82b1822004-11-08 16:24:57 +00006586 if (ctxt == NULL) return;
6587
Owen Taylor3473f882001-02-23 17:55:21 +00006588 if (nargs == 0) {
6589 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6590 nargs = 1;
6591 }
6592
6593 CHECK_ARITY(1);
6594 if ((ctxt->value == NULL) ||
6595 ((ctxt->value->type != XPATH_NODESET) &&
6596 (ctxt->value->type != XPATH_XSLT_TREE)))
6597 XP_ERROR(XPATH_INVALID_TYPE);
6598 cur = valuePop(ctxt);
6599
Daniel Veillard911f49a2001-04-07 15:39:35 +00006600 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006601 valuePush(ctxt, xmlXPathNewCString(""));
6602 } else {
6603 int i = 0; /* Should be first in document order !!!!! */
6604 switch (cur->nodesetval->nodeTab[i]->type) {
6605 case XML_ELEMENT_NODE:
6606 case XML_ATTRIBUTE_NODE:
6607 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006608 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6609 valuePush(ctxt, xmlXPathNewCString(""));
6610 else
6611 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006612 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6613 break;
6614 case XML_NAMESPACE_DECL:
6615 valuePush(ctxt, xmlXPathNewString(
6616 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6617 break;
6618 default:
6619 valuePush(ctxt, xmlXPathNewCString(""));
6620 }
6621 }
6622 xmlXPathFreeObject(cur);
6623}
6624
6625/**
6626 * xmlXPathNamespaceURIFunction:
6627 * @ctxt: the XPath Parser context
6628 * @nargs: the number of arguments
6629 *
6630 * Implement the namespace-uri() XPath function
6631 * string namespace-uri(node-set?)
6632 * The namespace-uri function returns a string containing the
6633 * namespace URI of the expanded name of the node in the argument
6634 * node-set that is first in document order. If the node-set is empty,
6635 * the first node has no name, or the expanded name has no namespace
6636 * URI, an empty string is returned. If the argument is omitted it
6637 * defaults to the context node.
6638 */
6639void
6640xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6641 xmlXPathObjectPtr cur;
6642
Daniel Veillarda82b1822004-11-08 16:24:57 +00006643 if (ctxt == NULL) return;
6644
Owen Taylor3473f882001-02-23 17:55:21 +00006645 if (nargs == 0) {
6646 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6647 nargs = 1;
6648 }
6649 CHECK_ARITY(1);
6650 if ((ctxt->value == NULL) ||
6651 ((ctxt->value->type != XPATH_NODESET) &&
6652 (ctxt->value->type != XPATH_XSLT_TREE)))
6653 XP_ERROR(XPATH_INVALID_TYPE);
6654 cur = valuePop(ctxt);
6655
Daniel Veillard911f49a2001-04-07 15:39:35 +00006656 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006657 valuePush(ctxt, xmlXPathNewCString(""));
6658 } else {
6659 int i = 0; /* Should be first in document order !!!!! */
6660 switch (cur->nodesetval->nodeTab[i]->type) {
6661 case XML_ELEMENT_NODE:
6662 case XML_ATTRIBUTE_NODE:
6663 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6664 valuePush(ctxt, xmlXPathNewCString(""));
6665 else
6666 valuePush(ctxt, xmlXPathNewString(
6667 cur->nodesetval->nodeTab[i]->ns->href));
6668 break;
6669 default:
6670 valuePush(ctxt, xmlXPathNewCString(""));
6671 }
6672 }
6673 xmlXPathFreeObject(cur);
6674}
6675
6676/**
6677 * xmlXPathNameFunction:
6678 * @ctxt: the XPath Parser context
6679 * @nargs: the number of arguments
6680 *
6681 * Implement the name() XPath function
6682 * string name(node-set?)
6683 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006684 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006685 * order. The QName must represent the name with respect to the namespace
6686 * declarations in effect on the node whose name is being represented.
6687 * Typically, this will be the form in which the name occurred in the XML
6688 * source. This need not be the case if there are namespace declarations
6689 * in effect on the node that associate multiple prefixes with the same
6690 * namespace. However, an implementation may include information about
6691 * the original prefix in its representation of nodes; in this case, an
6692 * implementation can ensure that the returned string is always the same
6693 * as the QName used in the XML source. If the argument it omitted it
6694 * defaults to the context node.
6695 * Libxml keep the original prefix so the "real qualified name" used is
6696 * returned.
6697 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006698static void
Daniel Veillard04383752001-07-08 14:27:15 +00006699xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6700{
Owen Taylor3473f882001-02-23 17:55:21 +00006701 xmlXPathObjectPtr cur;
6702
6703 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006704 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6705 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006706 }
6707
6708 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006709 if ((ctxt->value == NULL) ||
6710 ((ctxt->value->type != XPATH_NODESET) &&
6711 (ctxt->value->type != XPATH_XSLT_TREE)))
6712 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006713 cur = valuePop(ctxt);
6714
Daniel Veillard911f49a2001-04-07 15:39:35 +00006715 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006716 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006717 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006718 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006719
Daniel Veillard04383752001-07-08 14:27:15 +00006720 switch (cur->nodesetval->nodeTab[i]->type) {
6721 case XML_ELEMENT_NODE:
6722 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006723 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6724 valuePush(ctxt, xmlXPathNewCString(""));
6725 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6726 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006727 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006728 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006729
Daniel Veillard652d8a92003-02-04 19:28:49 +00006730 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006731 xmlChar *fullname;
6732
6733 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6734 cur->nodesetval->nodeTab[i]->ns->prefix,
6735 NULL, 0);
6736 if (fullname == cur->nodesetval->nodeTab[i]->name)
6737 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6738 if (fullname == NULL) {
6739 XP_ERROR(XPATH_MEMORY_ERROR);
6740 }
6741 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006742 }
6743 break;
6744 default:
6745 valuePush(ctxt,
6746 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6747 xmlXPathLocalNameFunction(ctxt, 1);
6748 }
Owen Taylor3473f882001-02-23 17:55:21 +00006749 }
6750 xmlXPathFreeObject(cur);
6751}
6752
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006753
6754/**
Owen Taylor3473f882001-02-23 17:55:21 +00006755 * xmlXPathStringFunction:
6756 * @ctxt: the XPath Parser context
6757 * @nargs: the number of arguments
6758 *
6759 * Implement the string() XPath function
6760 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006761 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006762 * - A node-set is converted to a string by returning the value of
6763 * the node in the node-set that is first in document order.
6764 * If the node-set is empty, an empty string is returned.
6765 * - A number is converted to a string as follows
6766 * + NaN is converted to the string NaN
6767 * + positive zero is converted to the string 0
6768 * + negative zero is converted to the string 0
6769 * + positive infinity is converted to the string Infinity
6770 * + negative infinity is converted to the string -Infinity
6771 * + if the number is an integer, the number is represented in
6772 * decimal form as a Number with no decimal point and no leading
6773 * zeros, preceded by a minus sign (-) if the number is negative
6774 * + otherwise, the number is represented in decimal form as a
6775 * Number including a decimal point with at least one digit
6776 * before the decimal point and at least one digit after the
6777 * decimal point, preceded by a minus sign (-) if the number
6778 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006779 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006780 * before the decimal point; beyond the one required digit
6781 * after the decimal point there must be as many, but only as
6782 * many, more digits as are needed to uniquely distinguish the
6783 * number from all other IEEE 754 numeric values.
6784 * - The boolean false value is converted to the string false.
6785 * The boolean true value is converted to the string true.
6786 *
6787 * If the argument is omitted, it defaults to a node-set with the
6788 * context node as its only member.
6789 */
6790void
6791xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6792 xmlXPathObjectPtr cur;
6793
Daniel Veillarda82b1822004-11-08 16:24:57 +00006794 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006795 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006796 valuePush(ctxt,
6797 xmlXPathWrapString(
6798 xmlXPathCastNodeToString(ctxt->context->node)));
6799 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006800 }
6801
6802 CHECK_ARITY(1);
6803 cur = valuePop(ctxt);
6804 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006805 cur = xmlXPathConvertString(cur);
6806 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006807}
6808
6809/**
6810 * xmlXPathStringLengthFunction:
6811 * @ctxt: the XPath Parser context
6812 * @nargs: the number of arguments
6813 *
6814 * Implement the string-length() XPath function
6815 * number string-length(string?)
6816 * The string-length returns the number of characters in the string
6817 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6818 * the context node converted to a string, in other words the value
6819 * of the context node.
6820 */
6821void
6822xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6823 xmlXPathObjectPtr cur;
6824
6825 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006826 if ((ctxt == NULL) || (ctxt->context == NULL))
6827 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006828 if (ctxt->context->node == NULL) {
6829 valuePush(ctxt, xmlXPathNewFloat(0));
6830 } else {
6831 xmlChar *content;
6832
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006833 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006834 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006835 xmlFree(content);
6836 }
6837 return;
6838 }
6839 CHECK_ARITY(1);
6840 CAST_TO_STRING;
6841 CHECK_TYPE(XPATH_STRING);
6842 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006843 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006844 xmlXPathFreeObject(cur);
6845}
6846
6847/**
6848 * xmlXPathConcatFunction:
6849 * @ctxt: the XPath Parser context
6850 * @nargs: the number of arguments
6851 *
6852 * Implement the concat() XPath function
6853 * string concat(string, string, string*)
6854 * The concat function returns the concatenation of its arguments.
6855 */
6856void
6857xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6858 xmlXPathObjectPtr cur, newobj;
6859 xmlChar *tmp;
6860
Daniel Veillarda82b1822004-11-08 16:24:57 +00006861 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006862 if (nargs < 2) {
6863 CHECK_ARITY(2);
6864 }
6865
6866 CAST_TO_STRING;
6867 cur = valuePop(ctxt);
6868 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6869 xmlXPathFreeObject(cur);
6870 return;
6871 }
6872 nargs--;
6873
6874 while (nargs > 0) {
6875 CAST_TO_STRING;
6876 newobj = valuePop(ctxt);
6877 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6878 xmlXPathFreeObject(newobj);
6879 xmlXPathFreeObject(cur);
6880 XP_ERROR(XPATH_INVALID_TYPE);
6881 }
6882 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6883 newobj->stringval = cur->stringval;
6884 cur->stringval = tmp;
6885
6886 xmlXPathFreeObject(newobj);
6887 nargs--;
6888 }
6889 valuePush(ctxt, cur);
6890}
6891
6892/**
6893 * xmlXPathContainsFunction:
6894 * @ctxt: the XPath Parser context
6895 * @nargs: the number of arguments
6896 *
6897 * Implement the contains() XPath function
6898 * boolean contains(string, string)
6899 * The contains function returns true if the first argument string
6900 * contains the second argument string, and otherwise returns false.
6901 */
6902void
6903xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6904 xmlXPathObjectPtr hay, needle;
6905
6906 CHECK_ARITY(2);
6907 CAST_TO_STRING;
6908 CHECK_TYPE(XPATH_STRING);
6909 needle = valuePop(ctxt);
6910 CAST_TO_STRING;
6911 hay = valuePop(ctxt);
6912 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6913 xmlXPathFreeObject(hay);
6914 xmlXPathFreeObject(needle);
6915 XP_ERROR(XPATH_INVALID_TYPE);
6916 }
6917 if (xmlStrstr(hay->stringval, needle->stringval))
6918 valuePush(ctxt, xmlXPathNewBoolean(1));
6919 else
6920 valuePush(ctxt, xmlXPathNewBoolean(0));
6921 xmlXPathFreeObject(hay);
6922 xmlXPathFreeObject(needle);
6923}
6924
6925/**
6926 * xmlXPathStartsWithFunction:
6927 * @ctxt: the XPath Parser context
6928 * @nargs: the number of arguments
6929 *
6930 * Implement the starts-with() XPath function
6931 * boolean starts-with(string, string)
6932 * The starts-with function returns true if the first argument string
6933 * starts with the second argument string, and otherwise returns false.
6934 */
6935void
6936xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6937 xmlXPathObjectPtr hay, needle;
6938 int n;
6939
6940 CHECK_ARITY(2);
6941 CAST_TO_STRING;
6942 CHECK_TYPE(XPATH_STRING);
6943 needle = valuePop(ctxt);
6944 CAST_TO_STRING;
6945 hay = valuePop(ctxt);
6946 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6947 xmlXPathFreeObject(hay);
6948 xmlXPathFreeObject(needle);
6949 XP_ERROR(XPATH_INVALID_TYPE);
6950 }
6951 n = xmlStrlen(needle->stringval);
6952 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6953 valuePush(ctxt, xmlXPathNewBoolean(0));
6954 else
6955 valuePush(ctxt, xmlXPathNewBoolean(1));
6956 xmlXPathFreeObject(hay);
6957 xmlXPathFreeObject(needle);
6958}
6959
6960/**
6961 * xmlXPathSubstringFunction:
6962 * @ctxt: the XPath Parser context
6963 * @nargs: the number of arguments
6964 *
6965 * Implement the substring() XPath function
6966 * string substring(string, number, number?)
6967 * The substring function returns the substring of the first argument
6968 * starting at the position specified in the second argument with
6969 * length specified in the third argument. For example,
6970 * substring("12345",2,3) returns "234". If the third argument is not
6971 * specified, it returns the substring starting at the position specified
6972 * in the second argument and continuing to the end of the string. For
6973 * example, substring("12345",2) returns "2345". More precisely, each
6974 * character in the string (see [3.6 Strings]) is considered to have a
6975 * numeric position: the position of the first character is 1, the position
6976 * of the second character is 2 and so on. The returned substring contains
6977 * those characters for which the position of the character is greater than
6978 * or equal to the second argument and, if the third argument is specified,
6979 * less than the sum of the second and third arguments; the comparisons
6980 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6981 * - substring("12345", 1.5, 2.6) returns "234"
6982 * - substring("12345", 0, 3) returns "12"
6983 * - substring("12345", 0 div 0, 3) returns ""
6984 * - substring("12345", 1, 0 div 0) returns ""
6985 * - substring("12345", -42, 1 div 0) returns "12345"
6986 * - substring("12345", -1 div 0, 1 div 0) returns ""
6987 */
6988void
6989xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6990 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006991 double le=0, in;
6992 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006993 xmlChar *ret;
6994
Owen Taylor3473f882001-02-23 17:55:21 +00006995 if (nargs < 2) {
6996 CHECK_ARITY(2);
6997 }
6998 if (nargs > 3) {
6999 CHECK_ARITY(3);
7000 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007001 /*
7002 * take care of possible last (position) argument
7003 */
Owen Taylor3473f882001-02-23 17:55:21 +00007004 if (nargs == 3) {
7005 CAST_TO_NUMBER;
7006 CHECK_TYPE(XPATH_NUMBER);
7007 len = valuePop(ctxt);
7008 le = len->floatval;
7009 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00007010 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007011
Owen Taylor3473f882001-02-23 17:55:21 +00007012 CAST_TO_NUMBER;
7013 CHECK_TYPE(XPATH_NUMBER);
7014 start = valuePop(ctxt);
7015 in = start->floatval;
7016 xmlXPathFreeObject(start);
7017 CAST_TO_STRING;
7018 CHECK_TYPE(XPATH_STRING);
7019 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00007020 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00007021
Daniel Veillard97ac1312001-05-30 19:14:17 +00007022 /*
7023 * If last pos not present, calculate last position
7024 */
Daniel Veillard9e412302002-06-10 15:59:44 +00007025 if (nargs != 3) {
7026 le = (double)m;
7027 if (in < 1.0)
7028 in = 1.0;
7029 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007030
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007031 /* Need to check for the special cases where either
7032 * the index is NaN, the length is NaN, or both
7033 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00007034 */
Daniel Veillard9e412302002-06-10 15:59:44 +00007035 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007036 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00007037 * To meet the requirements of the spec, the arguments
7038 * must be converted to integer format before
7039 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007040 *
Daniel Veillard9e412302002-06-10 15:59:44 +00007041 * First we go to integer form, rounding up
7042 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007043 */
7044 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00007045 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00007046
Daniel Veillard9e412302002-06-10 15:59:44 +00007047 if (xmlXPathIsInf(le) == 1) {
7048 l = m;
7049 if (i < 1)
7050 i = 1;
7051 }
7052 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
7053 l = 0;
7054 else {
7055 l = (int) le;
7056 if (((double)l)+0.5 <= le) l++;
7057 }
7058
7059 /* Now we normalize inidices */
7060 i -= 1;
7061 l += i;
7062 if (i < 0)
7063 i = 0;
7064 if (l > m)
7065 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00007066
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007067 /* number of chars to copy */
7068 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00007069
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007070 ret = xmlUTF8Strsub(str->stringval, i, l);
7071 }
7072 else {
7073 ret = NULL;
7074 }
7075
Owen Taylor3473f882001-02-23 17:55:21 +00007076 if (ret == NULL)
7077 valuePush(ctxt, xmlXPathNewCString(""));
7078 else {
7079 valuePush(ctxt, xmlXPathNewString(ret));
7080 xmlFree(ret);
7081 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007082
Owen Taylor3473f882001-02-23 17:55:21 +00007083 xmlXPathFreeObject(str);
7084}
7085
7086/**
7087 * xmlXPathSubstringBeforeFunction:
7088 * @ctxt: the XPath Parser context
7089 * @nargs: the number of arguments
7090 *
7091 * Implement the substring-before() XPath function
7092 * string substring-before(string, string)
7093 * The substring-before function returns the substring of the first
7094 * argument string that precedes the first occurrence of the second
7095 * argument string in the first argument string, or the empty string
7096 * if the first argument string does not contain the second argument
7097 * string. For example, substring-before("1999/04/01","/") returns 1999.
7098 */
7099void
7100xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7101 xmlXPathObjectPtr str;
7102 xmlXPathObjectPtr find;
7103 xmlBufferPtr target;
7104 const xmlChar *point;
7105 int offset;
7106
7107 CHECK_ARITY(2);
7108 CAST_TO_STRING;
7109 find = valuePop(ctxt);
7110 CAST_TO_STRING;
7111 str = valuePop(ctxt);
7112
7113 target = xmlBufferCreate();
7114 if (target) {
7115 point = xmlStrstr(str->stringval, find->stringval);
7116 if (point) {
7117 offset = (int)(point - str->stringval);
7118 xmlBufferAdd(target, str->stringval, offset);
7119 }
7120 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7121 xmlBufferFree(target);
7122 }
7123
7124 xmlXPathFreeObject(str);
7125 xmlXPathFreeObject(find);
7126}
7127
7128/**
7129 * xmlXPathSubstringAfterFunction:
7130 * @ctxt: the XPath Parser context
7131 * @nargs: the number of arguments
7132 *
7133 * Implement the substring-after() XPath function
7134 * string substring-after(string, string)
7135 * The substring-after function returns the substring of the first
7136 * argument string that follows the first occurrence of the second
7137 * argument string in the first argument string, or the empty stringi
7138 * if the first argument string does not contain the second argument
7139 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7140 * and substring-after("1999/04/01","19") returns 99/04/01.
7141 */
7142void
7143xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7144 xmlXPathObjectPtr str;
7145 xmlXPathObjectPtr find;
7146 xmlBufferPtr target;
7147 const xmlChar *point;
7148 int offset;
7149
7150 CHECK_ARITY(2);
7151 CAST_TO_STRING;
7152 find = valuePop(ctxt);
7153 CAST_TO_STRING;
7154 str = valuePop(ctxt);
7155
7156 target = xmlBufferCreate();
7157 if (target) {
7158 point = xmlStrstr(str->stringval, find->stringval);
7159 if (point) {
7160 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
7161 xmlBufferAdd(target, &str->stringval[offset],
7162 xmlStrlen(str->stringval) - offset);
7163 }
7164 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7165 xmlBufferFree(target);
7166 }
7167
7168 xmlXPathFreeObject(str);
7169 xmlXPathFreeObject(find);
7170}
7171
7172/**
7173 * xmlXPathNormalizeFunction:
7174 * @ctxt: the XPath Parser context
7175 * @nargs: the number of arguments
7176 *
7177 * Implement the normalize-space() XPath function
7178 * string normalize-space(string?)
7179 * The normalize-space function returns the argument string with white
7180 * space normalized by stripping leading and trailing whitespace
7181 * and replacing sequences of whitespace characters by a single
7182 * space. Whitespace characters are the same allowed by the S production
7183 * in XML. If the argument is omitted, it defaults to the context
7184 * node converted to a string, in other words the value of the context node.
7185 */
7186void
7187xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7188 xmlXPathObjectPtr obj = NULL;
7189 xmlChar *source = NULL;
7190 xmlBufferPtr target;
7191 xmlChar blank;
7192
Daniel Veillarda82b1822004-11-08 16:24:57 +00007193 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007194 if (nargs == 0) {
7195 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007196 valuePush(ctxt,
7197 xmlXPathWrapString(
7198 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00007199 nargs = 1;
7200 }
7201
7202 CHECK_ARITY(1);
7203 CAST_TO_STRING;
7204 CHECK_TYPE(XPATH_STRING);
7205 obj = valuePop(ctxt);
7206 source = obj->stringval;
7207
7208 target = xmlBufferCreate();
7209 if (target && source) {
7210
7211 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00007212 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00007213 source++;
7214
7215 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7216 blank = 0;
7217 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00007218 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00007219 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00007220 } else {
7221 if (blank) {
7222 xmlBufferAdd(target, &blank, 1);
7223 blank = 0;
7224 }
7225 xmlBufferAdd(target, source, 1);
7226 }
7227 source++;
7228 }
7229
7230 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7231 xmlBufferFree(target);
7232 }
7233 xmlXPathFreeObject(obj);
7234}
7235
7236/**
7237 * xmlXPathTranslateFunction:
7238 * @ctxt: the XPath Parser context
7239 * @nargs: the number of arguments
7240 *
7241 * Implement the translate() XPath function
7242 * string translate(string, string, string)
7243 * The translate function returns the first argument string with
7244 * occurrences of characters in the second argument string replaced
7245 * by the character at the corresponding position in the third argument
7246 * string. For example, translate("bar","abc","ABC") returns the string
7247 * BAr. If there is a character in the second argument string with no
7248 * character at a corresponding position in the third argument string
7249 * (because the second argument string is longer than the third argument
7250 * string), then occurrences of that character in the first argument
7251 * string are removed. For example, translate("--aaa--","abc-","ABC")
7252 * returns "AAA". If a character occurs more than once in second
7253 * argument string, then the first occurrence determines the replacement
7254 * character. If the third argument string is longer than the second
7255 * argument string, then excess characters are ignored.
7256 */
7257void
7258xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00007259 xmlXPathObjectPtr str;
7260 xmlXPathObjectPtr from;
7261 xmlXPathObjectPtr to;
7262 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007263 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007264 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00007265 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007266 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00007267
Daniel Veillarde043ee12001-04-16 14:08:07 +00007268 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00007269
Daniel Veillarde043ee12001-04-16 14:08:07 +00007270 CAST_TO_STRING;
7271 to = valuePop(ctxt);
7272 CAST_TO_STRING;
7273 from = valuePop(ctxt);
7274 CAST_TO_STRING;
7275 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007276
Daniel Veillarde043ee12001-04-16 14:08:07 +00007277 target = xmlBufferCreate();
7278 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00007279 max = xmlUTF8Strlen(to->stringval);
7280 for (cptr = str->stringval; (ch=*cptr); ) {
7281 offset = xmlUTF8Strloc(from->stringval, cptr);
7282 if (offset >= 0) {
7283 if (offset < max) {
7284 point = xmlUTF8Strpos(to->stringval, offset);
7285 if (point)
7286 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
7287 }
7288 } else
7289 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7290
7291 /* Step to next character in input */
7292 cptr++;
7293 if ( ch & 0x80 ) {
7294 /* if not simple ascii, verify proper format */
7295 if ( (ch & 0xc0) != 0xc0 ) {
7296 xmlGenericError(xmlGenericErrorContext,
7297 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7298 break;
7299 }
7300 /* then skip over remaining bytes for this char */
7301 while ( (ch <<= 1) & 0x80 )
7302 if ( (*cptr++ & 0xc0) != 0x80 ) {
7303 xmlGenericError(xmlGenericErrorContext,
7304 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7305 break;
7306 }
7307 if (ch & 0x80) /* must have had error encountered */
7308 break;
7309 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007310 }
Owen Taylor3473f882001-02-23 17:55:21 +00007311 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007312 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7313 xmlBufferFree(target);
7314 xmlXPathFreeObject(str);
7315 xmlXPathFreeObject(from);
7316 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007317}
7318
7319/**
7320 * xmlXPathBooleanFunction:
7321 * @ctxt: the XPath Parser context
7322 * @nargs: the number of arguments
7323 *
7324 * Implement the boolean() XPath function
7325 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007326 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007327 * - a number is true if and only if it is neither positive or
7328 * negative zero nor NaN
7329 * - a node-set is true if and only if it is non-empty
7330 * - a string is true if and only if its length is non-zero
7331 */
7332void
7333xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7334 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007335
7336 CHECK_ARITY(1);
7337 cur = valuePop(ctxt);
7338 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007339 cur = xmlXPathConvertBoolean(cur);
7340 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007341}
7342
7343/**
7344 * xmlXPathNotFunction:
7345 * @ctxt: the XPath Parser context
7346 * @nargs: the number of arguments
7347 *
7348 * Implement the not() XPath function
7349 * boolean not(boolean)
7350 * The not function returns true if its argument is false,
7351 * and false otherwise.
7352 */
7353void
7354xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7355 CHECK_ARITY(1);
7356 CAST_TO_BOOLEAN;
7357 CHECK_TYPE(XPATH_BOOLEAN);
7358 ctxt->value->boolval = ! ctxt->value->boolval;
7359}
7360
7361/**
7362 * xmlXPathTrueFunction:
7363 * @ctxt: the XPath Parser context
7364 * @nargs: the number of arguments
7365 *
7366 * Implement the true() XPath function
7367 * boolean true()
7368 */
7369void
7370xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7371 CHECK_ARITY(0);
7372 valuePush(ctxt, xmlXPathNewBoolean(1));
7373}
7374
7375/**
7376 * xmlXPathFalseFunction:
7377 * @ctxt: the XPath Parser context
7378 * @nargs: the number of arguments
7379 *
7380 * Implement the false() XPath function
7381 * boolean false()
7382 */
7383void
7384xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7385 CHECK_ARITY(0);
7386 valuePush(ctxt, xmlXPathNewBoolean(0));
7387}
7388
7389/**
7390 * xmlXPathLangFunction:
7391 * @ctxt: the XPath Parser context
7392 * @nargs: the number of arguments
7393 *
7394 * Implement the lang() XPath function
7395 * boolean lang(string)
7396 * The lang function returns true or false depending on whether the
7397 * language of the context node as specified by xml:lang attributes
7398 * is the same as or is a sublanguage of the language specified by
7399 * the argument string. The language of the context node is determined
7400 * by the value of the xml:lang attribute on the context node, or, if
7401 * the context node has no xml:lang attribute, by the value of the
7402 * xml:lang attribute on the nearest ancestor of the context node that
7403 * has an xml:lang attribute. If there is no such attribute, then lang
7404 * returns false. If there is such an attribute, then lang returns
7405 * true if the attribute value is equal to the argument ignoring case,
7406 * or if there is some suffix starting with - such that the attribute
7407 * value is equal to the argument ignoring that suffix of the attribute
7408 * value and ignoring case.
7409 */
7410void
7411xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007412 xmlXPathObjectPtr val = NULL;
7413 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007414 const xmlChar *lang;
7415 int ret = 0;
7416 int i;
7417
7418 CHECK_ARITY(1);
7419 CAST_TO_STRING;
7420 CHECK_TYPE(XPATH_STRING);
7421 val = valuePop(ctxt);
7422 lang = val->stringval;
7423 theLang = xmlNodeGetLang(ctxt->context->node);
7424 if ((theLang != NULL) && (lang != NULL)) {
7425 for (i = 0;lang[i] != 0;i++)
7426 if (toupper(lang[i]) != toupper(theLang[i]))
7427 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007428 if ((theLang[i] == 0) || (theLang[i] == '-'))
7429 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007430 }
7431not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007432 if (theLang != NULL)
7433 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007434 xmlXPathFreeObject(val);
7435 valuePush(ctxt, xmlXPathNewBoolean(ret));
7436}
7437
7438/**
7439 * xmlXPathNumberFunction:
7440 * @ctxt: the XPath Parser context
7441 * @nargs: the number of arguments
7442 *
7443 * Implement the number() XPath function
7444 * number number(object?)
7445 */
7446void
7447xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7448 xmlXPathObjectPtr cur;
7449 double res;
7450
Daniel Veillarda82b1822004-11-08 16:24:57 +00007451 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007452 if (nargs == 0) {
7453 if (ctxt->context->node == NULL) {
7454 valuePush(ctxt, xmlXPathNewFloat(0.0));
7455 } else {
7456 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7457
7458 res = xmlXPathStringEvalNumber(content);
7459 valuePush(ctxt, xmlXPathNewFloat(res));
7460 xmlFree(content);
7461 }
7462 return;
7463 }
7464
7465 CHECK_ARITY(1);
7466 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007467 cur = xmlXPathConvertNumber(cur);
7468 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007469}
7470
7471/**
7472 * xmlXPathSumFunction:
7473 * @ctxt: the XPath Parser context
7474 * @nargs: the number of arguments
7475 *
7476 * Implement the sum() XPath function
7477 * number sum(node-set)
7478 * The sum function returns the sum of the values of the nodes in
7479 * the argument node-set.
7480 */
7481void
7482xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7483 xmlXPathObjectPtr cur;
7484 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007485 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007486
7487 CHECK_ARITY(1);
7488 if ((ctxt->value == NULL) ||
7489 ((ctxt->value->type != XPATH_NODESET) &&
7490 (ctxt->value->type != XPATH_XSLT_TREE)))
7491 XP_ERROR(XPATH_INVALID_TYPE);
7492 cur = valuePop(ctxt);
7493
William M. Brack08171912003-12-29 02:52:11 +00007494 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007495 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7496 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007497 }
7498 }
William M. Brack08171912003-12-29 02:52:11 +00007499 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007500 xmlXPathFreeObject(cur);
7501}
7502
William M. Brack3d426662005-04-19 14:40:28 +00007503/*
7504 * To assure working code on multiple platforms, we want to only depend
7505 * upon the characteristic truncation of converting a floating point value
7506 * to an integer. Unfortunately, because of the different storage sizes
7507 * of our internal floating point value (double) and integer (int), we
7508 * can't directly convert (see bug 301162). This macro is a messy
7509 * 'workaround'
7510 */
7511#define XTRUNC(f, v) \
7512 f = fmod((v), INT_MAX); \
7513 f = (v) - (f) + (double)((int)(f));
7514
Owen Taylor3473f882001-02-23 17:55:21 +00007515/**
7516 * xmlXPathFloorFunction:
7517 * @ctxt: the XPath Parser context
7518 * @nargs: the number of arguments
7519 *
7520 * Implement the floor() XPath function
7521 * number floor(number)
7522 * The floor function returns the largest (closest to positive infinity)
7523 * number that is not greater than the argument and that is an integer.
7524 */
7525void
7526xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007527 double f;
7528
Owen Taylor3473f882001-02-23 17:55:21 +00007529 CHECK_ARITY(1);
7530 CAST_TO_NUMBER;
7531 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007532
William M. Brack3d426662005-04-19 14:40:28 +00007533 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007534 if (f != ctxt->value->floatval) {
7535 if (ctxt->value->floatval > 0)
7536 ctxt->value->floatval = f;
7537 else
7538 ctxt->value->floatval = f - 1;
7539 }
Owen Taylor3473f882001-02-23 17:55:21 +00007540}
7541
7542/**
7543 * xmlXPathCeilingFunction:
7544 * @ctxt: the XPath Parser context
7545 * @nargs: the number of arguments
7546 *
7547 * Implement the ceiling() XPath function
7548 * number ceiling(number)
7549 * The ceiling function returns the smallest (closest to negative infinity)
7550 * number that is not less than the argument and that is an integer.
7551 */
7552void
7553xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7554 double f;
7555
7556 CHECK_ARITY(1);
7557 CAST_TO_NUMBER;
7558 CHECK_TYPE(XPATH_NUMBER);
7559
7560#if 0
7561 ctxt->value->floatval = ceil(ctxt->value->floatval);
7562#else
William M. Brack3d426662005-04-19 14:40:28 +00007563 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007564 if (f != ctxt->value->floatval) {
7565 if (ctxt->value->floatval > 0)
7566 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007567 else {
7568 if (ctxt->value->floatval < 0 && f == 0)
7569 ctxt->value->floatval = xmlXPathNZERO;
7570 else
7571 ctxt->value->floatval = f;
7572 }
7573
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007574 }
Owen Taylor3473f882001-02-23 17:55:21 +00007575#endif
7576}
7577
7578/**
7579 * xmlXPathRoundFunction:
7580 * @ctxt: the XPath Parser context
7581 * @nargs: the number of arguments
7582 *
7583 * Implement the round() XPath function
7584 * number round(number)
7585 * The round function returns the number that is closest to the
7586 * argument and that is an integer. If there are two such numbers,
7587 * then the one that is even is returned.
7588 */
7589void
7590xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7591 double f;
7592
7593 CHECK_ARITY(1);
7594 CAST_TO_NUMBER;
7595 CHECK_TYPE(XPATH_NUMBER);
7596
Daniel Veillardcda96922001-08-21 10:56:31 +00007597 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7598 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7599 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007600 (ctxt->value->floatval == 0.0))
7601 return;
7602
William M. Brack3d426662005-04-19 14:40:28 +00007603 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007604 if (ctxt->value->floatval < 0) {
7605 if (ctxt->value->floatval < f - 0.5)
7606 ctxt->value->floatval = f - 1;
7607 else
7608 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007609 if (ctxt->value->floatval == 0)
7610 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007611 } else {
7612 if (ctxt->value->floatval < f + 0.5)
7613 ctxt->value->floatval = f;
7614 else
7615 ctxt->value->floatval = f + 1;
7616 }
Owen Taylor3473f882001-02-23 17:55:21 +00007617}
7618
7619/************************************************************************
7620 * *
7621 * The Parser *
7622 * *
7623 ************************************************************************/
7624
7625/*
William M. Brack08171912003-12-29 02:52:11 +00007626 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007627 * implementation.
7628 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007629static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007630static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007631static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007632static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007633static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7634 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007635
7636/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007637 * xmlXPathCurrentChar:
7638 * @ctxt: the XPath parser context
7639 * @cur: pointer to the beginning of the char
7640 * @len: pointer to the length of the char read
7641 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007642 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007643 * bytes in the input buffer.
7644 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007645 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007646 */
7647
7648static int
7649xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7650 unsigned char c;
7651 unsigned int val;
7652 const xmlChar *cur;
7653
7654 if (ctxt == NULL)
7655 return(0);
7656 cur = ctxt->cur;
7657
7658 /*
7659 * We are supposed to handle UTF8, check it's valid
7660 * From rfc2044: encoding of the Unicode values on UTF-8:
7661 *
7662 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7663 * 0000 0000-0000 007F 0xxxxxxx
7664 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7665 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7666 *
7667 * Check for the 0x110000 limit too
7668 */
7669 c = *cur;
7670 if (c & 0x80) {
7671 if ((cur[1] & 0xc0) != 0x80)
7672 goto encoding_error;
7673 if ((c & 0xe0) == 0xe0) {
7674
7675 if ((cur[2] & 0xc0) != 0x80)
7676 goto encoding_error;
7677 if ((c & 0xf0) == 0xf0) {
7678 if (((c & 0xf8) != 0xf0) ||
7679 ((cur[3] & 0xc0) != 0x80))
7680 goto encoding_error;
7681 /* 4-byte code */
7682 *len = 4;
7683 val = (cur[0] & 0x7) << 18;
7684 val |= (cur[1] & 0x3f) << 12;
7685 val |= (cur[2] & 0x3f) << 6;
7686 val |= cur[3] & 0x3f;
7687 } else {
7688 /* 3-byte code */
7689 *len = 3;
7690 val = (cur[0] & 0xf) << 12;
7691 val |= (cur[1] & 0x3f) << 6;
7692 val |= cur[2] & 0x3f;
7693 }
7694 } else {
7695 /* 2-byte code */
7696 *len = 2;
7697 val = (cur[0] & 0x1f) << 6;
7698 val |= cur[1] & 0x3f;
7699 }
7700 if (!IS_CHAR(val)) {
7701 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7702 }
7703 return(val);
7704 } else {
7705 /* 1-byte code */
7706 *len = 1;
7707 return((int) *cur);
7708 }
7709encoding_error:
7710 /*
William M. Brack08171912003-12-29 02:52:11 +00007711 * If we detect an UTF8 error that probably means that the
7712 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007713 * declaration header. Report the error and switch the encoding
7714 * to ISO-Latin-1 (if you don't like this policy, just declare the
7715 * encoding !)
7716 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007717 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007718 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007719}
7720
7721/**
Owen Taylor3473f882001-02-23 17:55:21 +00007722 * xmlXPathParseNCName:
7723 * @ctxt: the XPath Parser context
7724 *
7725 * parse an XML namespace non qualified name.
7726 *
7727 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7728 *
7729 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7730 * CombiningChar | Extender
7731 *
7732 * Returns the namespace name or NULL
7733 */
7734
7735xmlChar *
7736xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007737 const xmlChar *in;
7738 xmlChar *ret;
7739 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007740
Daniel Veillarda82b1822004-11-08 16:24:57 +00007741 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007742 /*
7743 * Accelerator for simple ASCII names
7744 */
7745 in = ctxt->cur;
7746 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7747 ((*in >= 0x41) && (*in <= 0x5A)) ||
7748 (*in == '_')) {
7749 in++;
7750 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7751 ((*in >= 0x41) && (*in <= 0x5A)) ||
7752 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007753 (*in == '_') || (*in == '.') ||
7754 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007755 in++;
7756 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7757 (*in == '[') || (*in == ']') || (*in == ':') ||
7758 (*in == '@') || (*in == '*')) {
7759 count = in - ctxt->cur;
7760 if (count == 0)
7761 return(NULL);
7762 ret = xmlStrndup(ctxt->cur, count);
7763 ctxt->cur = in;
7764 return(ret);
7765 }
7766 }
7767 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007768}
7769
Daniel Veillard2156a562001-04-28 12:24:34 +00007770
Owen Taylor3473f882001-02-23 17:55:21 +00007771/**
7772 * xmlXPathParseQName:
7773 * @ctxt: the XPath Parser context
7774 * @prefix: a xmlChar **
7775 *
7776 * parse an XML qualified name
7777 *
7778 * [NS 5] QName ::= (Prefix ':')? LocalPart
7779 *
7780 * [NS 6] Prefix ::= NCName
7781 *
7782 * [NS 7] LocalPart ::= NCName
7783 *
7784 * Returns the function returns the local part, and prefix is updated
7785 * to get the Prefix if any.
7786 */
7787
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007788static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007789xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7790 xmlChar *ret = NULL;
7791
7792 *prefix = NULL;
7793 ret = xmlXPathParseNCName(ctxt);
7794 if (CUR == ':') {
7795 *prefix = ret;
7796 NEXT;
7797 ret = xmlXPathParseNCName(ctxt);
7798 }
7799 return(ret);
7800}
7801
7802/**
7803 * xmlXPathParseName:
7804 * @ctxt: the XPath Parser context
7805 *
7806 * parse an XML name
7807 *
7808 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7809 * CombiningChar | Extender
7810 *
7811 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7812 *
7813 * Returns the namespace name or NULL
7814 */
7815
7816xmlChar *
7817xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007818 const xmlChar *in;
7819 xmlChar *ret;
7820 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007821
Daniel Veillarda82b1822004-11-08 16:24:57 +00007822 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007823 /*
7824 * Accelerator for simple ASCII names
7825 */
7826 in = ctxt->cur;
7827 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7828 ((*in >= 0x41) && (*in <= 0x5A)) ||
7829 (*in == '_') || (*in == ':')) {
7830 in++;
7831 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7832 ((*in >= 0x41) && (*in <= 0x5A)) ||
7833 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007834 (*in == '_') || (*in == '-') ||
7835 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007836 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007837 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007838 count = in - ctxt->cur;
7839 ret = xmlStrndup(ctxt->cur, count);
7840 ctxt->cur = in;
7841 return(ret);
7842 }
7843 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007844 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007845}
7846
Daniel Veillard61d80a22001-04-27 17:13:01 +00007847static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007848xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007849 xmlChar buf[XML_MAX_NAMELEN + 5];
7850 int len = 0, l;
7851 int c;
7852
7853 /*
7854 * Handler for more complex cases
7855 */
7856 c = CUR_CHAR(l);
7857 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007858 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7859 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007860 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007861 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007862 return(NULL);
7863 }
7864
7865 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7866 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7867 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007868 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007869 (IS_COMBINING(c)) ||
7870 (IS_EXTENDER(c)))) {
7871 COPY_BUF(l,buf,len,c);
7872 NEXTL(l);
7873 c = CUR_CHAR(l);
7874 if (len >= XML_MAX_NAMELEN) {
7875 /*
7876 * Okay someone managed to make a huge name, so he's ready to pay
7877 * for the processing speed.
7878 */
7879 xmlChar *buffer;
7880 int max = len * 2;
7881
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007882 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007883 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007884 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007885 }
7886 memcpy(buffer, buf, len);
7887 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7888 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007889 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007890 (IS_COMBINING(c)) ||
7891 (IS_EXTENDER(c))) {
7892 if (len + 10 > max) {
7893 max *= 2;
7894 buffer = (xmlChar *) xmlRealloc(buffer,
7895 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007896 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007897 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007898 }
7899 }
7900 COPY_BUF(l,buffer,len,c);
7901 NEXTL(l);
7902 c = CUR_CHAR(l);
7903 }
7904 buffer[len] = 0;
7905 return(buffer);
7906 }
7907 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007908 if (len == 0)
7909 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007910 return(xmlStrndup(buf, len));
7911}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007912
7913#define MAX_FRAC 20
7914
William M. Brack372a4452004-02-17 13:09:23 +00007915/*
7916 * These are used as divisors for the fractional part of a number.
7917 * Since the table includes 1.0 (representing '0' fractional digits),
7918 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7919 */
7920static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007921 1.0, 10.0, 100.0, 1000.0, 10000.0,
7922 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7923 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7924 100000000000000.0,
7925 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007926 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007927};
7928
Owen Taylor3473f882001-02-23 17:55:21 +00007929/**
7930 * xmlXPathStringEvalNumber:
7931 * @str: A string to scan
7932 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007933 * [30a] Float ::= Number ('e' Digits?)?
7934 *
Owen Taylor3473f882001-02-23 17:55:21 +00007935 * [30] Number ::= Digits ('.' Digits?)?
7936 * | '.' Digits
7937 * [31] Digits ::= [0-9]+
7938 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007939 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007940 * In complement of the Number expression, this function also handles
7941 * negative values : '-' Number.
7942 *
7943 * Returns the double value.
7944 */
7945double
7946xmlXPathStringEvalNumber(const xmlChar *str) {
7947 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007948 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007949 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007950 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007951 int exponent = 0;
7952 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007953#ifdef __GNUC__
7954 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007955 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007956#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007957 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007958 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007959 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7960 return(xmlXPathNAN);
7961 }
7962 if (*cur == '-') {
7963 isneg = 1;
7964 cur++;
7965 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007966
7967#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007968 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007969 * tmp/temp is a workaround against a gcc compiler bug
7970 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007971 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007972 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007973 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007974 ret = ret * 10;
7975 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007976 ok = 1;
7977 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007978 temp = (double) tmp;
7979 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007980 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007981#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007982 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007983 while ((*cur >= '0') && (*cur <= '9')) {
7984 ret = ret * 10 + (*cur - '0');
7985 ok = 1;
7986 cur++;
7987 }
7988#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007989
Owen Taylor3473f882001-02-23 17:55:21 +00007990 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007991 int v, frac = 0;
7992 double fraction = 0;
7993
Owen Taylor3473f882001-02-23 17:55:21 +00007994 cur++;
7995 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7996 return(xmlXPathNAN);
7997 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007998 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7999 v = (*cur - '0');
8000 fraction = fraction * 10 + v;
8001 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008002 cur++;
8003 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00008004 fraction /= my_pow10[frac];
8005 ret = ret + fraction;
8006 while ((*cur >= '0') && (*cur <= '9'))
8007 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008008 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00008009 if ((*cur == 'e') || (*cur == 'E')) {
8010 cur++;
8011 if (*cur == '-') {
8012 is_exponent_negative = 1;
8013 cur++;
William M. Brack99127052004-05-24 02:52:28 +00008014 } else if (*cur == '+') {
8015 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008016 }
8017 while ((*cur >= '0') && (*cur <= '9')) {
8018 exponent = exponent * 10 + (*cur - '0');
8019 cur++;
8020 }
8021 }
William M. Brack76e95df2003-10-18 16:20:14 +00008022 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008023 if (*cur != 0) return(xmlXPathNAN);
8024 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008025 if (is_exponent_negative) exponent = -exponent;
8026 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00008027 return(ret);
8028}
8029
8030/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008031 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00008032 * @ctxt: the XPath Parser context
8033 *
8034 * [30] Number ::= Digits ('.' Digits?)?
8035 * | '.' Digits
8036 * [31] Digits ::= [0-9]+
8037 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008038 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00008039 *
8040 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008042xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8043{
Owen Taylor3473f882001-02-23 17:55:21 +00008044 double ret = 0.0;
8045 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00008046 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008047 int exponent = 0;
8048 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00008049#ifdef __GNUC__
8050 unsigned long tmp = 0;
8051 double temp;
8052#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008053
8054 CHECK_ERROR;
8055 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8056 XP_ERROR(XPATH_NUMBER_ERROR);
8057 }
Daniel Veillard7b416132002-03-07 08:36:03 +00008058#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008059 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00008060 * tmp/temp is a workaround against a gcc compiler bug
8061 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008062 */
Daniel Veillard7b416132002-03-07 08:36:03 +00008063 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008064 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00008065 ret = ret * 10;
8066 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008067 ok = 1;
8068 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00008069 temp = (double) tmp;
8070 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00008071 }
Daniel Veillard7b416132002-03-07 08:36:03 +00008072#else
8073 ret = 0;
8074 while ((CUR >= '0') && (CUR <= '9')) {
8075 ret = ret * 10 + (CUR - '0');
8076 ok = 1;
8077 NEXT;
8078 }
8079#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008080 if (CUR == '.') {
8081 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008082 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8083 XP_ERROR(XPATH_NUMBER_ERROR);
8084 }
8085 while ((CUR >= '0') && (CUR <= '9')) {
8086 mult /= 10;
8087 ret = ret + (CUR - '0') * mult;
8088 NEXT;
8089 }
Owen Taylor3473f882001-02-23 17:55:21 +00008090 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00008091 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008092 NEXT;
8093 if (CUR == '-') {
8094 is_exponent_negative = 1;
8095 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00008096 } else if (CUR == '+') {
8097 NEXT;
8098 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008099 while ((CUR >= '0') && (CUR <= '9')) {
8100 exponent = exponent * 10 + (CUR - '0');
8101 NEXT;
8102 }
8103 if (is_exponent_negative)
8104 exponent = -exponent;
8105 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00008106 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008107 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008108 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008109}
8110
8111/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008112 * xmlXPathParseLiteral:
8113 * @ctxt: the XPath Parser context
8114 *
8115 * Parse a Literal
8116 *
8117 * [29] Literal ::= '"' [^"]* '"'
8118 * | "'" [^']* "'"
8119 *
8120 * Returns the value found or NULL in case of error
8121 */
8122static xmlChar *
8123xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8124 const xmlChar *q;
8125 xmlChar *ret = NULL;
8126
8127 if (CUR == '"') {
8128 NEXT;
8129 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008130 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008131 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008132 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008133 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008134 } else {
8135 ret = xmlStrndup(q, CUR_PTR - q);
8136 NEXT;
8137 }
8138 } else if (CUR == '\'') {
8139 NEXT;
8140 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008141 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008142 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008143 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008144 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008145 } else {
8146 ret = xmlStrndup(q, CUR_PTR - q);
8147 NEXT;
8148 }
8149 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00008150 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008151 }
8152 return(ret);
8153}
8154
8155/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008156 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00008157 * @ctxt: the XPath Parser context
8158 *
8159 * Parse a Literal and push it on the stack.
8160 *
8161 * [29] Literal ::= '"' [^"]* '"'
8162 * | "'" [^']* "'"
8163 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008164 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00008165 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008166static void
8167xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008168 const xmlChar *q;
8169 xmlChar *ret = NULL;
8170
8171 if (CUR == '"') {
8172 NEXT;
8173 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008174 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00008175 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008176 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00008177 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
8178 } else {
8179 ret = xmlStrndup(q, CUR_PTR - q);
8180 NEXT;
8181 }
8182 } else if (CUR == '\'') {
8183 NEXT;
8184 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008185 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00008186 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008187 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00008188 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
8189 } else {
8190 ret = xmlStrndup(q, CUR_PTR - q);
8191 NEXT;
8192 }
8193 } else {
8194 XP_ERROR(XPATH_START_LITERAL_ERROR);
8195 }
8196 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008197 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
8198 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008199 xmlFree(ret);
8200}
8201
8202/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008203 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00008204 * @ctxt: the XPath Parser context
8205 *
8206 * Parse a VariableReference, evaluate it and push it on the stack.
8207 *
8208 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00008209 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00008210 * of any of the types that are possible for the value of an expression,
8211 * and may also be of additional types not specified here.
8212 *
8213 * Early evaluation is possible since:
8214 * The variable bindings [...] used to evaluate a subexpression are
8215 * always the same as those used to evaluate the containing expression.
8216 *
8217 * [36] VariableReference ::= '$' QName
8218 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008219static void
8220xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008221 xmlChar *name;
8222 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00008223
8224 SKIP_BLANKS;
8225 if (CUR != '$') {
8226 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8227 }
8228 NEXT;
8229 name = xmlXPathParseQName(ctxt, &prefix);
8230 if (name == NULL) {
8231 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8232 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008233 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008234 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
8235 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008236 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00008237 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8238 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
8239 }
Owen Taylor3473f882001-02-23 17:55:21 +00008240}
8241
8242/**
8243 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00008244 * @name: a name string
8245 *
8246 * Is the name given a NodeType one.
8247 *
8248 * [38] NodeType ::= 'comment'
8249 * | 'text'
8250 * | 'processing-instruction'
8251 * | 'node'
8252 *
8253 * Returns 1 if true 0 otherwise
8254 */
8255int
8256xmlXPathIsNodeType(const xmlChar *name) {
8257 if (name == NULL)
8258 return(0);
8259
Daniel Veillard1971ee22002-01-31 20:29:19 +00008260 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00008261 return(1);
8262 if (xmlStrEqual(name, BAD_CAST "text"))
8263 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00008264 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00008265 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00008266 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00008267 return(1);
8268 return(0);
8269}
8270
8271/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008272 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00008273 * @ctxt: the XPath Parser context
8274 *
8275 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8276 * [17] Argument ::= Expr
8277 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00008279 * pushed on the stack
8280 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008281static void
8282xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008283 xmlChar *name;
8284 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00008285 int nbargs = 0;
8286
8287 name = xmlXPathParseQName(ctxt, &prefix);
8288 if (name == NULL) {
8289 XP_ERROR(XPATH_EXPR_ERROR);
8290 }
8291 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008292#ifdef DEBUG_EXPR
8293 if (prefix == NULL)
8294 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
8295 name);
8296 else
8297 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
8298 prefix, name);
8299#endif
8300
Owen Taylor3473f882001-02-23 17:55:21 +00008301 if (CUR != '(') {
8302 XP_ERROR(XPATH_EXPR_ERROR);
8303 }
8304 NEXT;
8305 SKIP_BLANKS;
8306
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008307 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00008308 if (CUR != ')') {
8309 while (CUR != 0) {
8310 int op1 = ctxt->comp->last;
8311 ctxt->comp->last = -1;
8312 xmlXPathCompileExpr(ctxt);
8313 CHECK_ERROR;
8314 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8315 nbargs++;
8316 if (CUR == ')') break;
8317 if (CUR != ',') {
8318 XP_ERROR(XPATH_EXPR_ERROR);
8319 }
8320 NEXT;
8321 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008322 }
Owen Taylor3473f882001-02-23 17:55:21 +00008323 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008324 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8325 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008326 NEXT;
8327 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008328}
8329
8330/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008331 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008332 * @ctxt: the XPath Parser context
8333 *
8334 * [15] PrimaryExpr ::= VariableReference
8335 * | '(' Expr ')'
8336 * | Literal
8337 * | Number
8338 * | FunctionCall
8339 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008340 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008341 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008342static void
8343xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008344 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008345 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008346 else if (CUR == '(') {
8347 NEXT;
8348 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008349 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008350 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008351 if (CUR != ')') {
8352 XP_ERROR(XPATH_EXPR_ERROR);
8353 }
8354 NEXT;
8355 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008356 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008357 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008358 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008359 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008360 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008361 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008362 }
8363 SKIP_BLANKS;
8364}
8365
8366/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008367 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008368 * @ctxt: the XPath Parser context
8369 *
8370 * [20] FilterExpr ::= PrimaryExpr
8371 * | FilterExpr Predicate
8372 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008373 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008374 * Square brackets are used to filter expressions in the same way that
8375 * they are used in location paths. It is an error if the expression to
8376 * be filtered does not evaluate to a node-set. The context node list
8377 * used for evaluating the expression in square brackets is the node-set
8378 * to be filtered listed in document order.
8379 */
8380
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008381static void
8382xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8383 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008384 CHECK_ERROR;
8385 SKIP_BLANKS;
8386
8387 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008388 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008389 SKIP_BLANKS;
8390 }
8391
8392
8393}
8394
8395/**
8396 * xmlXPathScanName:
8397 * @ctxt: the XPath Parser context
8398 *
8399 * Trickery: parse an XML name but without consuming the input flow
8400 * Needed to avoid insanity in the parser state.
8401 *
8402 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8403 * CombiningChar | Extender
8404 *
8405 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8406 *
8407 * [6] Names ::= Name (S Name)*
8408 *
8409 * Returns the Name parsed or NULL
8410 */
8411
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008412static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008413xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008414 int len = 0, l;
8415 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008416 const xmlChar *cur;
8417 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008418
Daniel Veillard03226812004-11-01 14:55:21 +00008419 cur = ctxt->cur;
8420
8421 c = CUR_CHAR(l);
8422 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8423 (!IS_LETTER(c) && (c != '_') &&
8424 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008425 return(NULL);
8426 }
8427
Daniel Veillard03226812004-11-01 14:55:21 +00008428 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8429 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8430 (c == '.') || (c == '-') ||
8431 (c == '_') || (c == ':') ||
8432 (IS_COMBINING(c)) ||
8433 (IS_EXTENDER(c)))) {
8434 len += l;
8435 NEXTL(l);
8436 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008437 }
Daniel Veillard03226812004-11-01 14:55:21 +00008438 ret = xmlStrndup(cur, ctxt->cur - cur);
8439 ctxt->cur = cur;
8440 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008441}
8442
8443/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008444 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008445 * @ctxt: the XPath Parser context
8446 *
8447 * [19] PathExpr ::= LocationPath
8448 * | FilterExpr
8449 * | FilterExpr '/' RelativeLocationPath
8450 * | FilterExpr '//' RelativeLocationPath
8451 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008453 * The / operator and // operators combine an arbitrary expression
8454 * and a relative location path. It is an error if the expression
8455 * does not evaluate to a node-set.
8456 * The / operator does composition in the same way as when / is
8457 * used in a location path. As in location paths, // is short for
8458 * /descendant-or-self::node()/.
8459 */
8460
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008461static void
8462xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008463 int lc = 1; /* Should we branch to LocationPath ? */
8464 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8465
8466 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008467 if ((CUR == '$') || (CUR == '(') ||
8468 (IS_ASCII_DIGIT(CUR)) ||
8469 (CUR == '\'') || (CUR == '"') ||
8470 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008471 lc = 0;
8472 } else if (CUR == '*') {
8473 /* relative or absolute location path */
8474 lc = 1;
8475 } else if (CUR == '/') {
8476 /* relative or absolute location path */
8477 lc = 1;
8478 } else if (CUR == '@') {
8479 /* relative abbreviated attribute location path */
8480 lc = 1;
8481 } else if (CUR == '.') {
8482 /* relative abbreviated attribute location path */
8483 lc = 1;
8484 } else {
8485 /*
8486 * Problem is finding if we have a name here whether it's:
8487 * - a nodetype
8488 * - a function call in which case it's followed by '('
8489 * - an axis in which case it's followed by ':'
8490 * - a element name
8491 * We do an a priori analysis here rather than having to
8492 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008493 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008494 * read/write/debug.
8495 */
8496 SKIP_BLANKS;
8497 name = xmlXPathScanName(ctxt);
8498 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8499#ifdef DEBUG_STEP
8500 xmlGenericError(xmlGenericErrorContext,
8501 "PathExpr: Axis\n");
8502#endif
8503 lc = 1;
8504 xmlFree(name);
8505 } else if (name != NULL) {
8506 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008507
8508
8509 while (NXT(len) != 0) {
8510 if (NXT(len) == '/') {
8511 /* element name */
8512#ifdef DEBUG_STEP
8513 xmlGenericError(xmlGenericErrorContext,
8514 "PathExpr: AbbrRelLocation\n");
8515#endif
8516 lc = 1;
8517 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008518 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008519 /* ignore blanks */
8520 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008521 } else if (NXT(len) == ':') {
8522#ifdef DEBUG_STEP
8523 xmlGenericError(xmlGenericErrorContext,
8524 "PathExpr: AbbrRelLocation\n");
8525#endif
8526 lc = 1;
8527 break;
8528 } else if ((NXT(len) == '(')) {
8529 /* Note Type or Function */
8530 if (xmlXPathIsNodeType(name)) {
8531#ifdef DEBUG_STEP
8532 xmlGenericError(xmlGenericErrorContext,
8533 "PathExpr: Type search\n");
8534#endif
8535 lc = 1;
8536 } else {
8537#ifdef DEBUG_STEP
8538 xmlGenericError(xmlGenericErrorContext,
8539 "PathExpr: function call\n");
8540#endif
8541 lc = 0;
8542 }
8543 break;
8544 } else if ((NXT(len) == '[')) {
8545 /* element name */
8546#ifdef DEBUG_STEP
8547 xmlGenericError(xmlGenericErrorContext,
8548 "PathExpr: AbbrRelLocation\n");
8549#endif
8550 lc = 1;
8551 break;
8552 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8553 (NXT(len) == '=')) {
8554 lc = 1;
8555 break;
8556 } else {
8557 lc = 1;
8558 break;
8559 }
8560 len++;
8561 }
8562 if (NXT(len) == 0) {
8563#ifdef DEBUG_STEP
8564 xmlGenericError(xmlGenericErrorContext,
8565 "PathExpr: AbbrRelLocation\n");
8566#endif
8567 /* element name */
8568 lc = 1;
8569 }
8570 xmlFree(name);
8571 } else {
William M. Brack08171912003-12-29 02:52:11 +00008572 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008573 XP_ERROR(XPATH_EXPR_ERROR);
8574 }
8575 }
8576
8577 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008578 if (CUR == '/') {
8579 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8580 } else {
8581 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008582 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008583 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008584 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008585 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008586 CHECK_ERROR;
8587 if ((CUR == '/') && (NXT(1) == '/')) {
8588 SKIP(2);
8589 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008590
8591 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8592 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8593 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8594
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008595 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008596 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008597 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008598 }
8599 }
8600 SKIP_BLANKS;
8601}
8602
8603/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008604 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008605 * @ctxt: the XPath Parser context
8606 *
8607 * [18] UnionExpr ::= PathExpr
8608 * | UnionExpr '|' PathExpr
8609 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008610 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008611 */
8612
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008613static void
8614xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8615 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008616 CHECK_ERROR;
8617 SKIP_BLANKS;
8618 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008619 int op1 = ctxt->comp->last;
8620 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008621
8622 NEXT;
8623 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008624 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008625
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008626 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8627
Owen Taylor3473f882001-02-23 17:55:21 +00008628 SKIP_BLANKS;
8629 }
Owen Taylor3473f882001-02-23 17:55:21 +00008630}
8631
8632/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008633 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008634 * @ctxt: the XPath Parser context
8635 *
8636 * [27] UnaryExpr ::= UnionExpr
8637 * | '-' UnaryExpr
8638 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008639 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008640 */
8641
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008642static void
8643xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008644 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008645 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008646
8647 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008648 while (CUR == '-') {
8649 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008650 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008651 NEXT;
8652 SKIP_BLANKS;
8653 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008654
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008655 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008656 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008657 if (found) {
8658 if (minus)
8659 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8660 else
8661 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008662 }
8663}
8664
8665/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008666 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008667 * @ctxt: the XPath Parser context
8668 *
8669 * [26] MultiplicativeExpr ::= UnaryExpr
8670 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8671 * | MultiplicativeExpr 'div' UnaryExpr
8672 * | MultiplicativeExpr 'mod' UnaryExpr
8673 * [34] MultiplyOperator ::= '*'
8674 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008675 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008676 */
8677
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008678static void
8679xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8680 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008681 CHECK_ERROR;
8682 SKIP_BLANKS;
8683 while ((CUR == '*') ||
8684 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8685 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8686 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008687 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008688
8689 if (CUR == '*') {
8690 op = 0;
8691 NEXT;
8692 } else if (CUR == 'd') {
8693 op = 1;
8694 SKIP(3);
8695 } else if (CUR == 'm') {
8696 op = 2;
8697 SKIP(3);
8698 }
8699 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008700 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008701 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008702 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008703 SKIP_BLANKS;
8704 }
8705}
8706
8707/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008708 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008709 * @ctxt: the XPath Parser context
8710 *
8711 * [25] AdditiveExpr ::= MultiplicativeExpr
8712 * | AdditiveExpr '+' MultiplicativeExpr
8713 * | AdditiveExpr '-' MultiplicativeExpr
8714 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008715 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008716 */
8717
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008718static void
8719xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008720
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008721 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008722 CHECK_ERROR;
8723 SKIP_BLANKS;
8724 while ((CUR == '+') || (CUR == '-')) {
8725 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008726 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008727
8728 if (CUR == '+') plus = 1;
8729 else plus = 0;
8730 NEXT;
8731 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008732 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008733 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008734 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008735 SKIP_BLANKS;
8736 }
8737}
8738
8739/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008740 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008741 * @ctxt: the XPath Parser context
8742 *
8743 * [24] RelationalExpr ::= AdditiveExpr
8744 * | RelationalExpr '<' AdditiveExpr
8745 * | RelationalExpr '>' AdditiveExpr
8746 * | RelationalExpr '<=' AdditiveExpr
8747 * | RelationalExpr '>=' AdditiveExpr
8748 *
8749 * A <= B > C is allowed ? Answer from James, yes with
8750 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8751 * which is basically what got implemented.
8752 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008753 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008754 * on the stack
8755 */
8756
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008757static void
8758xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8759 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008760 CHECK_ERROR;
8761 SKIP_BLANKS;
8762 while ((CUR == '<') ||
8763 (CUR == '>') ||
8764 ((CUR == '<') && (NXT(1) == '=')) ||
8765 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008766 int inf, strict;
8767 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008768
8769 if (CUR == '<') inf = 1;
8770 else inf = 0;
8771 if (NXT(1) == '=') strict = 0;
8772 else strict = 1;
8773 NEXT;
8774 if (!strict) NEXT;
8775 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008776 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008777 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008778 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008779 SKIP_BLANKS;
8780 }
8781}
8782
8783/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008784 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008785 * @ctxt: the XPath Parser context
8786 *
8787 * [23] EqualityExpr ::= RelationalExpr
8788 * | EqualityExpr '=' RelationalExpr
8789 * | EqualityExpr '!=' RelationalExpr
8790 *
8791 * A != B != C is allowed ? Answer from James, yes with
8792 * (RelationalExpr = RelationalExpr) = RelationalExpr
8793 * (RelationalExpr != RelationalExpr) != RelationalExpr
8794 * which is basically what got implemented.
8795 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008796 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008797 *
8798 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008799static void
8800xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8801 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008802 CHECK_ERROR;
8803 SKIP_BLANKS;
8804 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008805 int eq;
8806 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008807
8808 if (CUR == '=') eq = 1;
8809 else eq = 0;
8810 NEXT;
8811 if (!eq) NEXT;
8812 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008813 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008814 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008815 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008816 SKIP_BLANKS;
8817 }
8818}
8819
8820/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008821 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008822 * @ctxt: the XPath Parser context
8823 *
8824 * [22] AndExpr ::= EqualityExpr
8825 * | AndExpr 'and' EqualityExpr
8826 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008828 *
8829 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008830static void
8831xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8832 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008833 CHECK_ERROR;
8834 SKIP_BLANKS;
8835 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008836 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008837 SKIP(3);
8838 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008839 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008840 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008841 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008842 SKIP_BLANKS;
8843 }
8844}
8845
8846/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008847 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008848 * @ctxt: the XPath Parser context
8849 *
8850 * [14] Expr ::= OrExpr
8851 * [21] OrExpr ::= AndExpr
8852 * | OrExpr 'or' AndExpr
8853 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008854 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008855 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008856static void
8857xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8858 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008859 CHECK_ERROR;
8860 SKIP_BLANKS;
8861 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008862 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008863 SKIP(2);
8864 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008865 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008866 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008867 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8868 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008869 SKIP_BLANKS;
8870 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008871 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8872 /* more ops could be optimized too */
8873 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8874 }
Owen Taylor3473f882001-02-23 17:55:21 +00008875}
8876
8877/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008878 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008879 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008880 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008881 *
8882 * [8] Predicate ::= '[' PredicateExpr ']'
8883 * [9] PredicateExpr ::= Expr
8884 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008885 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008886 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008887static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008888xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008889 int op1 = ctxt->comp->last;
8890
8891 SKIP_BLANKS;
8892 if (CUR != '[') {
8893 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8894 }
8895 NEXT;
8896 SKIP_BLANKS;
8897
8898 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008899 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008900 CHECK_ERROR;
8901
8902 if (CUR != ']') {
8903 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8904 }
8905
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008906 if (filter)
8907 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8908 else
8909 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008910
8911 NEXT;
8912 SKIP_BLANKS;
8913}
8914
8915/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008916 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008917 * @ctxt: the XPath Parser context
8918 * @test: pointer to a xmlXPathTestVal
8919 * @type: pointer to a xmlXPathTypeVal
8920 * @prefix: placeholder for a possible name prefix
8921 *
8922 * [7] NodeTest ::= NameTest
8923 * | NodeType '(' ')'
8924 * | 'processing-instruction' '(' Literal ')'
8925 *
8926 * [37] NameTest ::= '*'
8927 * | NCName ':' '*'
8928 * | QName
8929 * [38] NodeType ::= 'comment'
8930 * | 'text'
8931 * | 'processing-instruction'
8932 * | 'node'
8933 *
William M. Brack08171912003-12-29 02:52:11 +00008934 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008935 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008936static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008937xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8938 xmlXPathTypeVal *type, const xmlChar **prefix,
8939 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008940 int blanks;
8941
8942 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8943 STRANGE;
8944 return(NULL);
8945 }
William M. Brack78637da2003-07-31 14:47:38 +00008946 *type = (xmlXPathTypeVal) 0;
8947 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008948 *prefix = NULL;
8949 SKIP_BLANKS;
8950
8951 if ((name == NULL) && (CUR == '*')) {
8952 /*
8953 * All elements
8954 */
8955 NEXT;
8956 *test = NODE_TEST_ALL;
8957 return(NULL);
8958 }
8959
8960 if (name == NULL)
8961 name = xmlXPathParseNCName(ctxt);
8962 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008963 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008964 }
8965
William M. Brack76e95df2003-10-18 16:20:14 +00008966 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008967 SKIP_BLANKS;
8968 if (CUR == '(') {
8969 NEXT;
8970 /*
8971 * NodeType or PI search
8972 */
8973 if (xmlStrEqual(name, BAD_CAST "comment"))
8974 *type = NODE_TYPE_COMMENT;
8975 else if (xmlStrEqual(name, BAD_CAST "node"))
8976 *type = NODE_TYPE_NODE;
8977 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8978 *type = NODE_TYPE_PI;
8979 else if (xmlStrEqual(name, BAD_CAST "text"))
8980 *type = NODE_TYPE_TEXT;
8981 else {
8982 if (name != NULL)
8983 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00008984 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008985 }
8986
8987 *test = NODE_TEST_TYPE;
8988
8989 SKIP_BLANKS;
8990 if (*type == NODE_TYPE_PI) {
8991 /*
8992 * Specific case: search a PI by name.
8993 */
Owen Taylor3473f882001-02-23 17:55:21 +00008994 if (name != NULL)
8995 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008996 name = NULL;
8997 if (CUR != ')') {
8998 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +00008999 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00009000 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00009001 SKIP_BLANKS;
9002 }
Owen Taylor3473f882001-02-23 17:55:21 +00009003 }
9004 if (CUR != ')') {
9005 if (name != NULL)
9006 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00009007 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009008 }
9009 NEXT;
9010 return(name);
9011 }
9012 *test = NODE_TEST_NAME;
9013 if ((!blanks) && (CUR == ':')) {
9014 NEXT;
9015
9016 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009017 * Since currently the parser context don't have a
9018 * namespace list associated:
9019 * The namespace name for this prefix can be computed
9020 * only at evaluation time. The compilation is done
9021 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00009022 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009023#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00009024 *prefix = xmlXPathNsLookup(ctxt->context, name);
9025 if (name != NULL)
9026 xmlFree(name);
9027 if (*prefix == NULL) {
9028 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9029 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009030#else
9031 *prefix = name;
9032#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009033
9034 if (CUR == '*') {
9035 /*
9036 * All elements
9037 */
9038 NEXT;
9039 *test = NODE_TEST_ALL;
9040 return(NULL);
9041 }
9042
9043 name = xmlXPathParseNCName(ctxt);
9044 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009045 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009046 }
9047 }
9048 return(name);
9049}
9050
9051/**
9052 * xmlXPathIsAxisName:
9053 * @name: a preparsed name token
9054 *
9055 * [6] AxisName ::= 'ancestor'
9056 * | 'ancestor-or-self'
9057 * | 'attribute'
9058 * | 'child'
9059 * | 'descendant'
9060 * | 'descendant-or-self'
9061 * | 'following'
9062 * | 'following-sibling'
9063 * | 'namespace'
9064 * | 'parent'
9065 * | 'preceding'
9066 * | 'preceding-sibling'
9067 * | 'self'
9068 *
9069 * Returns the axis or 0
9070 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009071static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00009072xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00009073 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009074 switch (name[0]) {
9075 case 'a':
9076 if (xmlStrEqual(name, BAD_CAST "ancestor"))
9077 ret = AXIS_ANCESTOR;
9078 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9079 ret = AXIS_ANCESTOR_OR_SELF;
9080 if (xmlStrEqual(name, BAD_CAST "attribute"))
9081 ret = AXIS_ATTRIBUTE;
9082 break;
9083 case 'c':
9084 if (xmlStrEqual(name, BAD_CAST "child"))
9085 ret = AXIS_CHILD;
9086 break;
9087 case 'd':
9088 if (xmlStrEqual(name, BAD_CAST "descendant"))
9089 ret = AXIS_DESCENDANT;
9090 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9091 ret = AXIS_DESCENDANT_OR_SELF;
9092 break;
9093 case 'f':
9094 if (xmlStrEqual(name, BAD_CAST "following"))
9095 ret = AXIS_FOLLOWING;
9096 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9097 ret = AXIS_FOLLOWING_SIBLING;
9098 break;
9099 case 'n':
9100 if (xmlStrEqual(name, BAD_CAST "namespace"))
9101 ret = AXIS_NAMESPACE;
9102 break;
9103 case 'p':
9104 if (xmlStrEqual(name, BAD_CAST "parent"))
9105 ret = AXIS_PARENT;
9106 if (xmlStrEqual(name, BAD_CAST "preceding"))
9107 ret = AXIS_PRECEDING;
9108 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9109 ret = AXIS_PRECEDING_SIBLING;
9110 break;
9111 case 's':
9112 if (xmlStrEqual(name, BAD_CAST "self"))
9113 ret = AXIS_SELF;
9114 break;
9115 }
9116 return(ret);
9117}
9118
9119/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009120 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00009121 * @ctxt: the XPath Parser context
9122 *
9123 * [4] Step ::= AxisSpecifier NodeTest Predicate*
9124 * | AbbreviatedStep
9125 *
9126 * [12] AbbreviatedStep ::= '.' | '..'
9127 *
9128 * [5] AxisSpecifier ::= AxisName '::'
9129 * | AbbreviatedAxisSpecifier
9130 *
9131 * [13] AbbreviatedAxisSpecifier ::= '@'?
9132 *
9133 * Modified for XPtr range support as:
9134 *
9135 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9136 * | AbbreviatedStep
9137 * | 'range-to' '(' Expr ')' Predicate*
9138 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009139 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00009140 * A location step of . is short for self::node(). This is
9141 * particularly useful in conjunction with //. For example, the
9142 * location path .//para is short for
9143 * self::node()/descendant-or-self::node()/child::para
9144 * and so will select all para descendant elements of the context
9145 * node.
9146 * Similarly, a location step of .. is short for parent::node().
9147 * For example, ../title is short for parent::node()/child::title
9148 * and so will select the title children of the parent of the context
9149 * node.
9150 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009151static void
9152xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009153#ifdef LIBXML_XPTR_ENABLED
9154 int rangeto = 0;
9155 int op2 = -1;
9156#endif
9157
Owen Taylor3473f882001-02-23 17:55:21 +00009158 SKIP_BLANKS;
9159 if ((CUR == '.') && (NXT(1) == '.')) {
9160 SKIP(2);
9161 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009162 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9163 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009164 } else if (CUR == '.') {
9165 NEXT;
9166 SKIP_BLANKS;
9167 } else {
9168 xmlChar *name = NULL;
9169 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +00009170 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +00009171 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +00009172 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009173 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00009174
9175 /*
9176 * The modification needed for XPointer change to the production
9177 */
9178#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009179 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00009180 name = xmlXPathParseNCName(ctxt);
9181 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009182 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00009183 xmlFree(name);
9184 SKIP_BLANKS;
9185 if (CUR != '(') {
9186 XP_ERROR(XPATH_EXPR_ERROR);
9187 }
9188 NEXT;
9189 SKIP_BLANKS;
9190
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009191 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009192 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00009193 CHECK_ERROR;
9194
9195 SKIP_BLANKS;
9196 if (CUR != ')') {
9197 XP_ERROR(XPATH_EXPR_ERROR);
9198 }
9199 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009200 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009201 goto eval_predicates;
9202 }
9203 }
9204#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00009205 if (CUR == '*') {
9206 axis = AXIS_CHILD;
9207 } else {
9208 if (name == NULL)
9209 name = xmlXPathParseNCName(ctxt);
9210 if (name != NULL) {
9211 axis = xmlXPathIsAxisName(name);
9212 if (axis != 0) {
9213 SKIP_BLANKS;
9214 if ((CUR == ':') && (NXT(1) == ':')) {
9215 SKIP(2);
9216 xmlFree(name);
9217 name = NULL;
9218 } else {
9219 /* an element name can conflict with an axis one :-\ */
9220 axis = AXIS_CHILD;
9221 }
Owen Taylor3473f882001-02-23 17:55:21 +00009222 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00009223 axis = AXIS_CHILD;
9224 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009225 } else if (CUR == '@') {
9226 NEXT;
9227 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00009228 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00009229 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00009230 }
Owen Taylor3473f882001-02-23 17:55:21 +00009231 }
9232
9233 CHECK_ERROR;
9234
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009235 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00009236 if (test == 0)
9237 return;
9238
Daniel Veillarded6c5492005-07-23 15:00:22 +00009239 if ((prefix != NULL) && (ctxt->context != NULL) &&
9240 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9241 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9242 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
9243 }
9244 }
Owen Taylor3473f882001-02-23 17:55:21 +00009245#ifdef DEBUG_STEP
9246 xmlGenericError(xmlGenericErrorContext,
9247 "Basis : computing new set\n");
9248#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009249
Owen Taylor3473f882001-02-23 17:55:21 +00009250#ifdef DEBUG_STEP
9251 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009252 if (ctxt->value == NULL)
9253 xmlGenericError(xmlGenericErrorContext, "no value\n");
9254 else if (ctxt->value->nodesetval == NULL)
9255 xmlGenericError(xmlGenericErrorContext, "Empty\n");
9256 else
9257 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00009258#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009259
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00009260#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00009261eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00009262#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009263 op1 = ctxt->comp->last;
9264 ctxt->comp->last = -1;
9265
Owen Taylor3473f882001-02-23 17:55:21 +00009266 SKIP_BLANKS;
9267 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009268 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00009269 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009270
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009271#ifdef LIBXML_XPTR_ENABLED
9272 if (rangeto) {
9273 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
9274 } else
9275#endif
9276 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9277 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009278
Owen Taylor3473f882001-02-23 17:55:21 +00009279 }
9280#ifdef DEBUG_STEP
9281 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009282 if (ctxt->value == NULL)
9283 xmlGenericError(xmlGenericErrorContext, "no value\n");
9284 else if (ctxt->value->nodesetval == NULL)
9285 xmlGenericError(xmlGenericErrorContext, "Empty\n");
9286 else
9287 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
9288 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00009289#endif
9290}
9291
9292/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009293 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009294 * @ctxt: the XPath Parser context
9295 *
9296 * [3] RelativeLocationPath ::= Step
9297 * | RelativeLocationPath '/' Step
9298 * | AbbreviatedRelativeLocationPath
9299 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
9300 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009301 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00009302 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009303static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009304xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00009305(xmlXPathParserContextPtr ctxt) {
9306 SKIP_BLANKS;
9307 if ((CUR == '/') && (NXT(1) == '/')) {
9308 SKIP(2);
9309 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009310 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9311 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009312 } else if (CUR == '/') {
9313 NEXT;
9314 SKIP_BLANKS;
9315 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009316 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009317 SKIP_BLANKS;
9318 while (CUR == '/') {
9319 if ((CUR == '/') && (NXT(1) == '/')) {
9320 SKIP(2);
9321 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009322 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009323 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009324 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009325 } else if (CUR == '/') {
9326 NEXT;
9327 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009328 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009329 }
9330 SKIP_BLANKS;
9331 }
9332}
9333
9334/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009335 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009336 * @ctxt: the XPath Parser context
9337 *
9338 * [1] LocationPath ::= RelativeLocationPath
9339 * | AbsoluteLocationPath
9340 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9341 * | AbbreviatedAbsoluteLocationPath
9342 * [10] AbbreviatedAbsoluteLocationPath ::=
9343 * '//' RelativeLocationPath
9344 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009345 * Compile a location path
9346 *
Owen Taylor3473f882001-02-23 17:55:21 +00009347 * // is short for /descendant-or-self::node()/. For example,
9348 * //para is short for /descendant-or-self::node()/child::para and
9349 * so will select any para element in the document (even a para element
9350 * that is a document element will be selected by //para since the
9351 * document element node is a child of the root node); div//para is
9352 * short for div/descendant-or-self::node()/child::para and so will
9353 * select all para descendants of div children.
9354 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009355static void
9356xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009357 SKIP_BLANKS;
9358 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009359 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009360 } else {
9361 while (CUR == '/') {
9362 if ((CUR == '/') && (NXT(1) == '/')) {
9363 SKIP(2);
9364 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009365 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9366 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009367 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009368 } else if (CUR == '/') {
9369 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009370 SKIP_BLANKS;
9371 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009372 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009373 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009374 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009375 }
9376 }
9377 }
9378}
9379
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009380/************************************************************************
9381 * *
9382 * XPath precompiled expression evaluation *
9383 * *
9384 ************************************************************************/
9385
Daniel Veillardf06307e2001-07-03 10:35:50 +00009386static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009387xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9388
9389/**
9390 * xmlXPathNodeCollectAndTest:
9391 * @ctxt: the XPath Parser context
9392 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009393 * @first: pointer to the first element in document order
9394 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009395 *
9396 * This is the function implementing a step: based on the current list
9397 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009398 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009399 *
9400 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009401 *
William M. Brack08171912003-12-29 02:52:11 +00009402 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009403 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009404static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009405xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 xmlXPathStepOpPtr op,
9407 xmlNodePtr * first, xmlNodePtr * last)
9408{
William M. Brack78637da2003-07-31 14:47:38 +00009409 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9410 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9411 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009412 const xmlChar *prefix = op->value4;
9413 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009414 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009415
9416#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009417 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009418#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009419 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009420 xmlNodeSetPtr ret, list;
9421 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009422 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009423 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009424 xmlNodePtr cur = NULL;
9425 xmlXPathObjectPtr obj;
9426 xmlNodeSetPtr nodelist;
9427 xmlNodePtr tmp;
9428
Daniel Veillardf06307e2001-07-03 10:35:50 +00009429 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009430 obj = valuePop(ctxt);
9431 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009432 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009433 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009434 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009435 if (URI == NULL) {
9436 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009437 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009438 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009439 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009440#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009441 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009442#endif
9443 switch (axis) {
9444 case AXIS_ANCESTOR:
9445#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009446 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009447#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009448 first = NULL;
9449 next = xmlXPathNextAncestor;
9450 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009451 case AXIS_ANCESTOR_OR_SELF:
9452#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009453 xmlGenericError(xmlGenericErrorContext,
9454 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009455#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009456 first = NULL;
9457 next = xmlXPathNextAncestorOrSelf;
9458 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009459 case AXIS_ATTRIBUTE:
9460#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009461 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009462#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009463 first = NULL;
9464 last = NULL;
9465 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009466 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009467 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009468 case AXIS_CHILD:
9469#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009470 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009471#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009472 last = NULL;
9473 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009474 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009476 case AXIS_DESCENDANT:
9477#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009478 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009479#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009480 last = NULL;
9481 next = xmlXPathNextDescendant;
9482 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009483 case AXIS_DESCENDANT_OR_SELF:
9484#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009485 xmlGenericError(xmlGenericErrorContext,
9486 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009487#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009488 last = NULL;
9489 next = xmlXPathNextDescendantOrSelf;
9490 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009491 case AXIS_FOLLOWING:
9492#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009494#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009495 last = NULL;
9496 next = xmlXPathNextFollowing;
9497 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009498 case AXIS_FOLLOWING_SIBLING:
9499#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009500 xmlGenericError(xmlGenericErrorContext,
9501 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009502#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009503 last = NULL;
9504 next = xmlXPathNextFollowingSibling;
9505 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009506 case AXIS_NAMESPACE:
9507#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009508 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009509#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009510 first = NULL;
9511 last = NULL;
9512 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009513 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009514 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009515 case AXIS_PARENT:
9516#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009517 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009518#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009519 first = NULL;
9520 next = xmlXPathNextParent;
9521 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009522 case AXIS_PRECEDING:
9523#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009524 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009525#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009526 first = NULL;
9527 next = xmlXPathNextPrecedingInternal;
9528 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009529 case AXIS_PRECEDING_SIBLING:
9530#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009531 xmlGenericError(xmlGenericErrorContext,
9532 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009533#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009534 first = NULL;
9535 next = xmlXPathNextPrecedingSibling;
9536 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009537 case AXIS_SELF:
9538#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009539 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009540#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009541 first = NULL;
9542 last = NULL;
9543 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009544 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009545 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009546 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009547 if (next == NULL) {
9548 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009549 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009550 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009551
9552 nodelist = obj->nodesetval;
9553 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009554 xmlXPathFreeObject(obj);
9555 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9556 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009557 }
9558 addNode = xmlXPathNodeSetAddUnique;
9559 ret = NULL;
9560#ifdef DEBUG_STEP
9561 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009562 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009563 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009564 case NODE_TEST_NONE:
9565 xmlGenericError(xmlGenericErrorContext,
9566 " searching for none !!!\n");
9567 break;
9568 case NODE_TEST_TYPE:
9569 xmlGenericError(xmlGenericErrorContext,
9570 " searching for type %d\n", type);
9571 break;
9572 case NODE_TEST_PI:
9573 xmlGenericError(xmlGenericErrorContext,
9574 " searching for PI !!!\n");
9575 break;
9576 case NODE_TEST_ALL:
9577 xmlGenericError(xmlGenericErrorContext,
9578 " searching for *\n");
9579 break;
9580 case NODE_TEST_NS:
9581 xmlGenericError(xmlGenericErrorContext,
9582 " searching for namespace %s\n",
9583 prefix);
9584 break;
9585 case NODE_TEST_NAME:
9586 xmlGenericError(xmlGenericErrorContext,
9587 " searching for name %s\n", name);
9588 if (prefix != NULL)
9589 xmlGenericError(xmlGenericErrorContext,
9590 " with namespace %s\n", prefix);
9591 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009592 }
9593 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9594#endif
9595 /*
9596 * 2.3 Node Tests
9597 * - For the attribute axis, the principal node type is attribute.
9598 * - For the namespace axis, the principal node type is namespace.
9599 * - For other axes, the principal node type is element.
9600 *
9601 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009602 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009603 * select all element children of the context node
9604 */
9605 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009606 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009607 ctxt->context->node = nodelist->nodeTab[i];
9608
Daniel Veillardf06307e2001-07-03 10:35:50 +00009609 cur = NULL;
9610 list = xmlXPathNodeSetCreate(NULL);
9611 do {
9612 cur = next(ctxt, cur);
9613 if (cur == NULL)
9614 break;
9615 if ((first != NULL) && (*first == cur))
9616 break;
9617 if (((t % 256) == 0) &&
9618 (first != NULL) && (*first != NULL) &&
9619 (xmlXPathCmpNodes(*first, cur) >= 0))
9620 break;
9621 if ((last != NULL) && (*last == cur))
9622 break;
9623 if (((t % 256) == 0) &&
9624 (last != NULL) && (*last != NULL) &&
9625 (xmlXPathCmpNodes(cur, *last) >= 0))
9626 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009627 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009628#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009629 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9630#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009631 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009632 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009633 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009634 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009635 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009636 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009637 if ((cur->type == type) ||
9638 ((type == NODE_TYPE_NODE) &&
9639 ((cur->type == XML_DOCUMENT_NODE) ||
9640 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9641 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009642 (cur->type == XML_NAMESPACE_DECL) ||
9643 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009644 (cur->type == XML_PI_NODE) ||
9645 (cur->type == XML_COMMENT_NODE) ||
9646 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009647 (cur->type == XML_TEXT_NODE))) ||
9648 ((type == NODE_TYPE_TEXT) &&
9649 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009650#ifdef DEBUG_STEP
9651 n++;
9652#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 addNode(list, cur);
9654 }
9655 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009656 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009657 if (cur->type == XML_PI_NODE) {
9658 if ((name != NULL) &&
9659 (!xmlStrEqual(name, cur->name)))
9660 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009661#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009662 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009663#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 addNode(list, cur);
9665 }
9666 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009667 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009668 if (axis == AXIS_ATTRIBUTE) {
9669 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009670#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009671 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009672#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009673 addNode(list, cur);
9674 }
9675 } else if (axis == AXIS_NAMESPACE) {
9676 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009677#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009678 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009679#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009680 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9681 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009682 }
9683 } else {
9684 if (cur->type == XML_ELEMENT_NODE) {
9685 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009686#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009688#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009689 addNode(list, cur);
9690 } else if ((cur->ns != NULL) &&
9691 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009692#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009693 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009694#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009695 addNode(list, cur);
9696 }
9697 }
9698 }
9699 break;
9700 case NODE_TEST_NS:{
9701 TODO;
9702 break;
9703 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009704 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009705 switch (cur->type) {
9706 case XML_ELEMENT_NODE:
9707 if (xmlStrEqual(name, cur->name)) {
9708 if (prefix == NULL) {
9709 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009710#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009711 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009712#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009713 addNode(list, cur);
9714 }
9715 } else {
9716 if ((cur->ns != NULL) &&
9717 (xmlStrEqual(URI,
9718 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009719#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009720 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009721#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009722 addNode(list, cur);
9723 }
9724 }
9725 }
9726 break;
9727 case XML_ATTRIBUTE_NODE:{
9728 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009729
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 if (xmlStrEqual(name, attr->name)) {
9731 if (prefix == NULL) {
9732 if ((attr->ns == NULL) ||
9733 (attr->ns->prefix == NULL)) {
9734#ifdef DEBUG_STEP
9735 n++;
9736#endif
9737 addNode(list,
9738 (xmlNodePtr) attr);
9739 }
9740 } else {
9741 if ((attr->ns != NULL) &&
9742 (xmlStrEqual(URI,
9743 attr->ns->
9744 href))) {
9745#ifdef DEBUG_STEP
9746 n++;
9747#endif
9748 addNode(list,
9749 (xmlNodePtr) attr);
9750 }
9751 }
9752 }
9753 break;
9754 }
9755 case XML_NAMESPACE_DECL:
9756 if (cur->type == XML_NAMESPACE_DECL) {
9757 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009758
Daniel Veillardf06307e2001-07-03 10:35:50 +00009759 if ((ns->prefix != NULL) && (name != NULL)
9760 && (xmlStrEqual(ns->prefix, name))) {
9761#ifdef DEBUG_STEP
9762 n++;
9763#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009764 xmlXPathNodeSetAddNs(list,
9765 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009766 }
9767 }
9768 break;
9769 default:
9770 break;
9771 }
9772 break;
9773 break;
9774 }
9775 } while (cur != NULL);
9776
9777 /*
9778 * If there is some predicate filtering do it now
9779 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009780 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009781 xmlXPathObjectPtr obj2;
9782
9783 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9784 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9785 CHECK_TYPE0(XPATH_NODESET);
9786 obj2 = valuePop(ctxt);
9787 list = obj2->nodesetval;
9788 obj2->nodesetval = NULL;
9789 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009790 if (ctxt->error != XPATH_EXPRESSION_OK) {
9791 xmlXPathFreeObject(obj);
9792 xmlXPathFreeNodeSet(list);
9793 return(0);
9794 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009795 }
9796 if (ret == NULL) {
9797 ret = list;
9798 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009799 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009800 xmlXPathFreeNodeSet(list);
9801 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009802 }
9803 ctxt->context->node = tmp;
9804#ifdef DEBUG_STEP
9805 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009806 "\nExamined %d nodes, found %d nodes at that step\n",
9807 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009808#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009809 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009810 if ((obj->boolval) && (obj->user != NULL)) {
9811 ctxt->value->boolval = 1;
9812 ctxt->value->user = obj->user;
9813 obj->user = NULL;
9814 obj->boolval = 0;
9815 }
9816 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 return(t);
9818}
9819
9820/**
9821 * xmlXPathNodeCollectAndTestNth:
9822 * @ctxt: the XPath Parser context
9823 * @op: the XPath precompiled step operation
9824 * @indx: the index to collect
9825 * @first: pointer to the first element in document order
9826 * @last: pointer to the last element in document order
9827 *
9828 * This is the function implementing a step: based on the current list
9829 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009830 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009831 *
9832 * Pushes the new NodeSet resulting from the search.
9833 * Returns the number of node traversed
9834 */
9835static int
9836xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9837 xmlXPathStepOpPtr op, int indx,
9838 xmlNodePtr * first, xmlNodePtr * last)
9839{
William M. Brack78637da2003-07-31 14:47:38 +00009840 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9841 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9842 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009843 const xmlChar *prefix = op->value4;
9844 const xmlChar *name = op->value5;
9845 const xmlChar *URI = NULL;
9846 int n = 0, t = 0;
9847
9848 int i;
9849 xmlNodeSetPtr list;
9850 xmlXPathTraversalFunction next = NULL;
9851 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9852 xmlNodePtr cur = NULL;
9853 xmlXPathObjectPtr obj;
9854 xmlNodeSetPtr nodelist;
9855 xmlNodePtr tmp;
9856
9857 CHECK_TYPE0(XPATH_NODESET);
9858 obj = valuePop(ctxt);
9859 addNode = xmlXPathNodeSetAdd;
9860 if (prefix != NULL) {
9861 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009862 if (URI == NULL) {
9863 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009864 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009865 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009866 }
9867#ifdef DEBUG_STEP_NTH
9868 xmlGenericError(xmlGenericErrorContext, "new step : ");
9869 if (first != NULL) {
9870 if (*first != NULL)
9871 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9872 (*first)->name);
9873 else
9874 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9875 }
9876 if (last != NULL) {
9877 if (*last != NULL)
9878 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9879 (*last)->name);
9880 else
9881 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9882 }
9883#endif
9884 switch (axis) {
9885 case AXIS_ANCESTOR:
9886#ifdef DEBUG_STEP_NTH
9887 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9888#endif
9889 first = NULL;
9890 next = xmlXPathNextAncestor;
9891 break;
9892 case AXIS_ANCESTOR_OR_SELF:
9893#ifdef DEBUG_STEP_NTH
9894 xmlGenericError(xmlGenericErrorContext,
9895 "axis 'ancestors-or-self' ");
9896#endif
9897 first = NULL;
9898 next = xmlXPathNextAncestorOrSelf;
9899 break;
9900 case AXIS_ATTRIBUTE:
9901#ifdef DEBUG_STEP_NTH
9902 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9903#endif
9904 first = NULL;
9905 last = NULL;
9906 next = xmlXPathNextAttribute;
9907 break;
9908 case AXIS_CHILD:
9909#ifdef DEBUG_STEP_NTH
9910 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9911#endif
9912 last = NULL;
9913 next = xmlXPathNextChild;
9914 break;
9915 case AXIS_DESCENDANT:
9916#ifdef DEBUG_STEP_NTH
9917 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9918#endif
9919 last = NULL;
9920 next = xmlXPathNextDescendant;
9921 break;
9922 case AXIS_DESCENDANT_OR_SELF:
9923#ifdef DEBUG_STEP_NTH
9924 xmlGenericError(xmlGenericErrorContext,
9925 "axis 'descendant-or-self' ");
9926#endif
9927 last = NULL;
9928 next = xmlXPathNextDescendantOrSelf;
9929 break;
9930 case AXIS_FOLLOWING:
9931#ifdef DEBUG_STEP_NTH
9932 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9933#endif
9934 last = NULL;
9935 next = xmlXPathNextFollowing;
9936 break;
9937 case AXIS_FOLLOWING_SIBLING:
9938#ifdef DEBUG_STEP_NTH
9939 xmlGenericError(xmlGenericErrorContext,
9940 "axis 'following-siblings' ");
9941#endif
9942 last = NULL;
9943 next = xmlXPathNextFollowingSibling;
9944 break;
9945 case AXIS_NAMESPACE:
9946#ifdef DEBUG_STEP_NTH
9947 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9948#endif
9949 last = NULL;
9950 first = NULL;
9951 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9952 break;
9953 case AXIS_PARENT:
9954#ifdef DEBUG_STEP_NTH
9955 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9956#endif
9957 first = NULL;
9958 next = xmlXPathNextParent;
9959 break;
9960 case AXIS_PRECEDING:
9961#ifdef DEBUG_STEP_NTH
9962 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9963#endif
9964 first = NULL;
9965 next = xmlXPathNextPrecedingInternal;
9966 break;
9967 case AXIS_PRECEDING_SIBLING:
9968#ifdef DEBUG_STEP_NTH
9969 xmlGenericError(xmlGenericErrorContext,
9970 "axis 'preceding-sibling' ");
9971#endif
9972 first = NULL;
9973 next = xmlXPathNextPrecedingSibling;
9974 break;
9975 case AXIS_SELF:
9976#ifdef DEBUG_STEP_NTH
9977 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9978#endif
9979 first = NULL;
9980 last = NULL;
9981 next = xmlXPathNextSelf;
9982 break;
9983 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009984 if (next == NULL) {
9985 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009987 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009988
9989 nodelist = obj->nodesetval;
9990 if (nodelist == NULL) {
9991 xmlXPathFreeObject(obj);
9992 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9993 return(0);
9994 }
9995 addNode = xmlXPathNodeSetAddUnique;
9996#ifdef DEBUG_STEP_NTH
9997 xmlGenericError(xmlGenericErrorContext,
9998 " context contains %d nodes\n", nodelist->nodeNr);
9999 switch (test) {
10000 case NODE_TEST_NONE:
10001 xmlGenericError(xmlGenericErrorContext,
10002 " searching for none !!!\n");
10003 break;
10004 case NODE_TEST_TYPE:
10005 xmlGenericError(xmlGenericErrorContext,
10006 " searching for type %d\n", type);
10007 break;
10008 case NODE_TEST_PI:
10009 xmlGenericError(xmlGenericErrorContext,
10010 " searching for PI !!!\n");
10011 break;
10012 case NODE_TEST_ALL:
10013 xmlGenericError(xmlGenericErrorContext,
10014 " searching for *\n");
10015 break;
10016 case NODE_TEST_NS:
10017 xmlGenericError(xmlGenericErrorContext,
10018 " searching for namespace %s\n",
10019 prefix);
10020 break;
10021 case NODE_TEST_NAME:
10022 xmlGenericError(xmlGenericErrorContext,
10023 " searching for name %s\n", name);
10024 if (prefix != NULL)
10025 xmlGenericError(xmlGenericErrorContext,
10026 " with namespace %s\n", prefix);
10027 break;
10028 }
10029 xmlGenericError(xmlGenericErrorContext, "Testing : ");
10030#endif
10031 /*
10032 * 2.3 Node Tests
10033 * - For the attribute axis, the principal node type is attribute.
10034 * - For the namespace axis, the principal node type is namespace.
10035 * - For other axes, the principal node type is element.
10036 *
10037 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010038 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +000010039 * select all element children of the context node
10040 */
10041 tmp = ctxt->context->node;
10042 list = xmlXPathNodeSetCreate(NULL);
10043 for (i = 0; i < nodelist->nodeNr; i++) {
10044 ctxt->context->node = nodelist->nodeTab[i];
10045
10046 cur = NULL;
10047 n = 0;
10048 do {
10049 cur = next(ctxt, cur);
10050 if (cur == NULL)
10051 break;
10052 if ((first != NULL) && (*first == cur))
10053 break;
10054 if (((t % 256) == 0) &&
10055 (first != NULL) && (*first != NULL) &&
10056 (xmlXPathCmpNodes(*first, cur) >= 0))
10057 break;
10058 if ((last != NULL) && (*last == cur))
10059 break;
10060 if (((t % 256) == 0) &&
10061 (last != NULL) && (*last != NULL) &&
10062 (xmlXPathCmpNodes(cur, *last) >= 0))
10063 break;
10064 t++;
10065 switch (test) {
10066 case NODE_TEST_NONE:
10067 ctxt->context->node = tmp;
10068 STRANGE return(0);
10069 case NODE_TEST_TYPE:
10070 if ((cur->type == type) ||
10071 ((type == NODE_TYPE_NODE) &&
10072 ((cur->type == XML_DOCUMENT_NODE) ||
10073 (cur->type == XML_HTML_DOCUMENT_NODE) ||
10074 (cur->type == XML_ELEMENT_NODE) ||
10075 (cur->type == XML_PI_NODE) ||
10076 (cur->type == XML_COMMENT_NODE) ||
10077 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +000010078 (cur->type == XML_TEXT_NODE))) ||
10079 ((type == NODE_TYPE_TEXT) &&
10080 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010081 n++;
10082 if (n == indx)
10083 addNode(list, cur);
10084 }
10085 break;
10086 case NODE_TEST_PI:
10087 if (cur->type == XML_PI_NODE) {
10088 if ((name != NULL) &&
10089 (!xmlStrEqual(name, cur->name)))
10090 break;
10091 n++;
10092 if (n == indx)
10093 addNode(list, cur);
10094 }
10095 break;
10096 case NODE_TEST_ALL:
10097 if (axis == AXIS_ATTRIBUTE) {
10098 if (cur->type == XML_ATTRIBUTE_NODE) {
10099 n++;
10100 if (n == indx)
10101 addNode(list, cur);
10102 }
10103 } else if (axis == AXIS_NAMESPACE) {
10104 if (cur->type == XML_NAMESPACE_DECL) {
10105 n++;
10106 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000010107 xmlXPathNodeSetAddNs(list, ctxt->context->node,
10108 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010109 }
10110 } else {
10111 if (cur->type == XML_ELEMENT_NODE) {
10112 if (prefix == NULL) {
10113 n++;
10114 if (n == indx)
10115 addNode(list, cur);
10116 } else if ((cur->ns != NULL) &&
10117 (xmlStrEqual(URI, cur->ns->href))) {
10118 n++;
10119 if (n == indx)
10120 addNode(list, cur);
10121 }
10122 }
10123 }
10124 break;
10125 case NODE_TEST_NS:{
10126 TODO;
10127 break;
10128 }
10129 case NODE_TEST_NAME:
10130 switch (cur->type) {
10131 case XML_ELEMENT_NODE:
10132 if (xmlStrEqual(name, cur->name)) {
10133 if (prefix == NULL) {
10134 if (cur->ns == NULL) {
10135 n++;
10136 if (n == indx)
10137 addNode(list, cur);
10138 }
10139 } else {
10140 if ((cur->ns != NULL) &&
10141 (xmlStrEqual(URI,
10142 cur->ns->href))) {
10143 n++;
10144 if (n == indx)
10145 addNode(list, cur);
10146 }
10147 }
10148 }
10149 break;
10150 case XML_ATTRIBUTE_NODE:{
10151 xmlAttrPtr attr = (xmlAttrPtr) cur;
10152
10153 if (xmlStrEqual(name, attr->name)) {
10154 if (prefix == NULL) {
10155 if ((attr->ns == NULL) ||
10156 (attr->ns->prefix == NULL)) {
10157 n++;
10158 if (n == indx)
10159 addNode(list, cur);
10160 }
10161 } else {
10162 if ((attr->ns != NULL) &&
10163 (xmlStrEqual(URI,
10164 attr->ns->
10165 href))) {
10166 n++;
10167 if (n == indx)
10168 addNode(list, cur);
10169 }
10170 }
10171 }
10172 break;
10173 }
10174 case XML_NAMESPACE_DECL:
10175 if (cur->type == XML_NAMESPACE_DECL) {
10176 xmlNsPtr ns = (xmlNsPtr) cur;
10177
10178 if ((ns->prefix != NULL) && (name != NULL)
10179 && (xmlStrEqual(ns->prefix, name))) {
10180 n++;
10181 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000010182 xmlXPathNodeSetAddNs(list,
10183 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010184 }
10185 }
10186 break;
10187 default:
10188 break;
10189 }
10190 break;
10191 break;
10192 }
10193 } while (n < indx);
10194 }
10195 ctxt->context->node = tmp;
10196#ifdef DEBUG_STEP_NTH
10197 xmlGenericError(xmlGenericErrorContext,
10198 "\nExamined %d nodes, found %d nodes at that step\n",
10199 t, list->nodeNr);
10200#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000010202 if ((obj->boolval) && (obj->user != NULL)) {
10203 ctxt->value->boolval = 1;
10204 ctxt->value->user = obj->user;
10205 obj->user = NULL;
10206 obj->boolval = 0;
10207 }
10208 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 return(t);
10210}
10211
10212/**
10213 * xmlXPathCompOpEvalFirst:
10214 * @ctxt: the XPath parser context with the compiled expression
10215 * @op: an XPath compiled operation
10216 * @first: the first elem found so far
10217 *
10218 * Evaluate the Precompiled XPath operation searching only the first
10219 * element in document order
10220 *
10221 * Returns the number of examined objects.
10222 */
10223static int
10224xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10225 xmlXPathStepOpPtr op, xmlNodePtr * first)
10226{
10227 int total = 0, cur;
10228 xmlXPathCompExprPtr comp;
10229 xmlXPathObjectPtr arg1, arg2;
10230
Daniel Veillard556c6682001-10-06 09:59:51 +000010231 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010232 comp = ctxt->comp;
10233 switch (op->op) {
10234 case XPATH_OP_END:
10235 return (0);
10236 case XPATH_OP_UNION:
10237 total =
10238 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10239 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010240 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010241 if ((ctxt->value != NULL)
10242 && (ctxt->value->type == XPATH_NODESET)
10243 && (ctxt->value->nodesetval != NULL)
10244 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10245 /*
10246 * limit tree traversing to first node in the result
10247 */
10248 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10249 *first = ctxt->value->nodesetval->nodeTab[0];
10250 }
10251 cur =
10252 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10253 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010254 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 CHECK_TYPE0(XPATH_NODESET);
10256 arg2 = valuePop(ctxt);
10257
10258 CHECK_TYPE0(XPATH_NODESET);
10259 arg1 = valuePop(ctxt);
10260
10261 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10262 arg2->nodesetval);
10263 valuePush(ctxt, arg1);
10264 xmlXPathFreeObject(arg2);
10265 /* optimizer */
10266 if (total > cur)
10267 xmlXPathCompSwap(op);
10268 return (total + cur);
10269 case XPATH_OP_ROOT:
10270 xmlXPathRoot(ctxt);
10271 return (0);
10272 case XPATH_OP_NODE:
10273 if (op->ch1 != -1)
10274 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010275 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 if (op->ch2 != -1)
10277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010278 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010279 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10280 return (total);
10281 case XPATH_OP_RESET:
10282 if (op->ch1 != -1)
10283 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010284 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 if (op->ch2 != -1)
10286 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010287 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010288 ctxt->context->node = NULL;
10289 return (total);
10290 case XPATH_OP_COLLECT:{
10291 if (op->ch1 == -1)
10292 return (total);
10293
10294 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010295 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296
10297 /*
10298 * Optimization for [n] selection where n is a number
10299 */
10300 if ((op->ch2 != -1) &&
10301 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10302 (comp->steps[op->ch2].ch1 == -1) &&
10303 (comp->steps[op->ch2].ch2 != -1) &&
10304 (comp->steps[comp->steps[op->ch2].ch2].op ==
10305 XPATH_OP_VALUE)) {
10306 xmlXPathObjectPtr val;
10307
10308 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10309 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10310 int indx = (int) val->floatval;
10311
10312 if (val->floatval == (float) indx) {
10313 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
10314 first, NULL);
10315 return (total);
10316 }
10317 }
10318 }
10319 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10320 return (total);
10321 }
10322 case XPATH_OP_VALUE:
10323 valuePush(ctxt,
10324 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10325 return (0);
10326 case XPATH_OP_SORT:
10327 if (op->ch1 != -1)
10328 total +=
10329 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10330 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010331 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010332 if ((ctxt->value != NULL)
10333 && (ctxt->value->type == XPATH_NODESET)
10334 && (ctxt->value->nodesetval != NULL))
10335 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10336 return (total);
10337 default:
10338 return (xmlXPathCompOpEval(ctxt, op));
10339 }
10340}
10341
10342/**
10343 * xmlXPathCompOpEvalLast:
10344 * @ctxt: the XPath parser context with the compiled expression
10345 * @op: an XPath compiled operation
10346 * @last: the last elem found so far
10347 *
10348 * Evaluate the Precompiled XPath operation searching only the last
10349 * element in document order
10350 *
William M. Brack08171912003-12-29 02:52:11 +000010351 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010352 */
10353static int
10354xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10355 xmlNodePtr * last)
10356{
10357 int total = 0, cur;
10358 xmlXPathCompExprPtr comp;
10359 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010360 xmlNodePtr bak;
10361 xmlDocPtr bakd;
10362 int pp;
10363 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364
Daniel Veillard556c6682001-10-06 09:59:51 +000010365 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010366 comp = ctxt->comp;
10367 switch (op->op) {
10368 case XPATH_OP_END:
10369 return (0);
10370 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010371 bakd = ctxt->context->doc;
10372 bak = ctxt->context->node;
10373 pp = ctxt->context->proximityPosition;
10374 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 total =
10376 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010377 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010378 if ((ctxt->value != NULL)
10379 && (ctxt->value->type == XPATH_NODESET)
10380 && (ctxt->value->nodesetval != NULL)
10381 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10382 /*
10383 * limit tree traversing to first node in the result
10384 */
10385 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10386 *last =
10387 ctxt->value->nodesetval->nodeTab[ctxt->value->
10388 nodesetval->nodeNr -
10389 1];
10390 }
William M. Brackce4fc562004-01-22 02:47:18 +000010391 ctxt->context->doc = bakd;
10392 ctxt->context->node = bak;
10393 ctxt->context->proximityPosition = pp;
10394 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395 cur =
10396 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010397 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 if ((ctxt->value != NULL)
10399 && (ctxt->value->type == XPATH_NODESET)
10400 && (ctxt->value->nodesetval != NULL)
10401 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10402 }
10403 CHECK_TYPE0(XPATH_NODESET);
10404 arg2 = valuePop(ctxt);
10405
10406 CHECK_TYPE0(XPATH_NODESET);
10407 arg1 = valuePop(ctxt);
10408
10409 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10410 arg2->nodesetval);
10411 valuePush(ctxt, arg1);
10412 xmlXPathFreeObject(arg2);
10413 /* optimizer */
10414 if (total > cur)
10415 xmlXPathCompSwap(op);
10416 return (total + cur);
10417 case XPATH_OP_ROOT:
10418 xmlXPathRoot(ctxt);
10419 return (0);
10420 case XPATH_OP_NODE:
10421 if (op->ch1 != -1)
10422 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010423 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010424 if (op->ch2 != -1)
10425 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010426 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010427 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10428 return (total);
10429 case XPATH_OP_RESET:
10430 if (op->ch1 != -1)
10431 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010432 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010433 if (op->ch2 != -1)
10434 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010435 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010436 ctxt->context->node = NULL;
10437 return (total);
10438 case XPATH_OP_COLLECT:{
10439 if (op->ch1 == -1)
10440 return (0);
10441
10442 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010443 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010444
10445 /*
10446 * Optimization for [n] selection where n is a number
10447 */
10448 if ((op->ch2 != -1) &&
10449 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10450 (comp->steps[op->ch2].ch1 == -1) &&
10451 (comp->steps[op->ch2].ch2 != -1) &&
10452 (comp->steps[comp->steps[op->ch2].ch2].op ==
10453 XPATH_OP_VALUE)) {
10454 xmlXPathObjectPtr val;
10455
10456 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10457 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10458 int indx = (int) val->floatval;
10459
10460 if (val->floatval == (float) indx) {
10461 total +=
10462 xmlXPathNodeCollectAndTestNth(ctxt, op,
10463 indx, NULL,
10464 last);
10465 return (total);
10466 }
10467 }
10468 }
10469 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10470 return (total);
10471 }
10472 case XPATH_OP_VALUE:
10473 valuePush(ctxt,
10474 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10475 return (0);
10476 case XPATH_OP_SORT:
10477 if (op->ch1 != -1)
10478 total +=
10479 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10480 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010481 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010482 if ((ctxt->value != NULL)
10483 && (ctxt->value->type == XPATH_NODESET)
10484 && (ctxt->value->nodesetval != NULL))
10485 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10486 return (total);
10487 default:
10488 return (xmlXPathCompOpEval(ctxt, op));
10489 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010490}
10491
Owen Taylor3473f882001-02-23 17:55:21 +000010492/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010493 * xmlXPathCompOpEval:
10494 * @ctxt: the XPath parser context with the compiled expression
10495 * @op: an XPath compiled operation
10496 *
10497 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010498 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010499 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010500static int
10501xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10502{
10503 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010504 int equal, ret;
10505 xmlXPathCompExprPtr comp;
10506 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010507 xmlNodePtr bak;
10508 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010509 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010510 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010511
Daniel Veillard556c6682001-10-06 09:59:51 +000010512 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010513 comp = ctxt->comp;
10514 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010515 case XPATH_OP_END:
10516 return (0);
10517 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010518 bakd = ctxt->context->doc;
10519 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010520 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010521 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010522 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010523 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010524 xmlXPathBooleanFunction(ctxt, 1);
10525 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10526 return (total);
10527 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010528 ctxt->context->doc = bakd;
10529 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010530 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010531 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010532 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010533 if (ctxt->error) {
10534 xmlXPathFreeObject(arg2);
10535 return(0);
10536 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010537 xmlXPathBooleanFunction(ctxt, 1);
10538 arg1 = valuePop(ctxt);
10539 arg1->boolval &= arg2->boolval;
10540 valuePush(ctxt, arg1);
10541 xmlXPathFreeObject(arg2);
10542 return (total);
10543 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010544 bakd = ctxt->context->doc;
10545 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010546 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010547 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010548 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010549 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010550 xmlXPathBooleanFunction(ctxt, 1);
10551 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10552 return (total);
10553 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010554 ctxt->context->doc = bakd;
10555 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010556 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010557 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010558 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010559 if (ctxt->error) {
10560 xmlXPathFreeObject(arg2);
10561 return(0);
10562 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010563 xmlXPathBooleanFunction(ctxt, 1);
10564 arg1 = valuePop(ctxt);
10565 arg1->boolval |= arg2->boolval;
10566 valuePush(ctxt, arg1);
10567 xmlXPathFreeObject(arg2);
10568 return (total);
10569 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010570 bakd = ctxt->context->doc;
10571 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010572 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010573 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010574 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010575 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010576 ctxt->context->doc = bakd;
10577 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010578 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010579 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010580 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010581 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010582 if (op->value)
10583 equal = xmlXPathEqualValues(ctxt);
10584 else
10585 equal = xmlXPathNotEqualValues(ctxt);
10586 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010587 return (total);
10588 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010589 bakd = ctxt->context->doc;
10590 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010591 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010592 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010593 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010594 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010595 ctxt->context->doc = bakd;
10596 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010597 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010598 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010599 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010600 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010601 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10602 valuePush(ctxt, xmlXPathNewBoolean(ret));
10603 return (total);
10604 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010605 bakd = ctxt->context->doc;
10606 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010607 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010608 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010609 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010610 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010611 if (op->ch2 != -1) {
10612 ctxt->context->doc = bakd;
10613 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010614 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010615 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010616 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010617 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010618 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010619 if (op->value == 0)
10620 xmlXPathSubValues(ctxt);
10621 else if (op->value == 1)
10622 xmlXPathAddValues(ctxt);
10623 else if (op->value == 2)
10624 xmlXPathValueFlipSign(ctxt);
10625 else if (op->value == 3) {
10626 CAST_TO_NUMBER;
10627 CHECK_TYPE0(XPATH_NUMBER);
10628 }
10629 return (total);
10630 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010631 bakd = ctxt->context->doc;
10632 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010633 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010634 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010635 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010636 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010637 ctxt->context->doc = bakd;
10638 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010639 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010640 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010641 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010642 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010643 if (op->value == 0)
10644 xmlXPathMultValues(ctxt);
10645 else if (op->value == 1)
10646 xmlXPathDivValues(ctxt);
10647 else if (op->value == 2)
10648 xmlXPathModValues(ctxt);
10649 return (total);
10650 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010651 bakd = ctxt->context->doc;
10652 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010653 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010654 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010655 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010656 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010657 ctxt->context->doc = bakd;
10658 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010659 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010660 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010661 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010662 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010663 CHECK_TYPE0(XPATH_NODESET);
10664 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010665
Daniel Veillardf06307e2001-07-03 10:35:50 +000010666 CHECK_TYPE0(XPATH_NODESET);
10667 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010668
Daniel Veillardf06307e2001-07-03 10:35:50 +000010669 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10670 arg2->nodesetval);
10671 valuePush(ctxt, arg1);
10672 xmlXPathFreeObject(arg2);
10673 return (total);
10674 case XPATH_OP_ROOT:
10675 xmlXPathRoot(ctxt);
10676 return (total);
10677 case XPATH_OP_NODE:
10678 if (op->ch1 != -1)
10679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010680 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681 if (op->ch2 != -1)
10682 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010683 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10685 return (total);
10686 case XPATH_OP_RESET:
10687 if (op->ch1 != -1)
10688 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010689 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010690 if (op->ch2 != -1)
10691 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010693 ctxt->context->node = NULL;
10694 return (total);
10695 case XPATH_OP_COLLECT:{
10696 if (op->ch1 == -1)
10697 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010698
Daniel Veillardf06307e2001-07-03 10:35:50 +000010699 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010700 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010701
Daniel Veillardf06307e2001-07-03 10:35:50 +000010702 /*
10703 * Optimization for [n] selection where n is a number
10704 */
10705 if ((op->ch2 != -1) &&
10706 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10707 (comp->steps[op->ch2].ch1 == -1) &&
10708 (comp->steps[op->ch2].ch2 != -1) &&
10709 (comp->steps[comp->steps[op->ch2].ch2].op ==
10710 XPATH_OP_VALUE)) {
10711 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010712
Daniel Veillardf06307e2001-07-03 10:35:50 +000010713 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10714 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10715 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010716
Daniel Veillardf06307e2001-07-03 10:35:50 +000010717 if (val->floatval == (float) indx) {
10718 total +=
10719 xmlXPathNodeCollectAndTestNth(ctxt, op,
10720 indx, NULL,
10721 NULL);
10722 return (total);
10723 }
10724 }
10725 }
10726 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10727 return (total);
10728 }
10729 case XPATH_OP_VALUE:
10730 valuePush(ctxt,
10731 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10732 return (total);
10733 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010734 xmlXPathObjectPtr val;
10735
Daniel Veillardf06307e2001-07-03 10:35:50 +000010736 if (op->ch1 != -1)
10737 total +=
10738 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010739 if (op->value5 == NULL) {
10740 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10741 if (val == NULL) {
10742 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10743 return(0);
10744 }
10745 valuePush(ctxt, val);
10746 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010748
Daniel Veillardf06307e2001-07-03 10:35:50 +000010749 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10750 if (URI == NULL) {
10751 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010752 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010753 op->value4, op->value5);
10754 return (total);
10755 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010756 val = xmlXPathVariableLookupNS(ctxt->context,
10757 op->value4, URI);
10758 if (val == NULL) {
10759 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10760 return(0);
10761 }
10762 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010763 }
10764 return (total);
10765 }
10766 case XPATH_OP_FUNCTION:{
10767 xmlXPathFunction func;
10768 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010769 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010770
10771 if (op->ch1 != -1)
10772 total +=
10773 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010774 if (ctxt->valueNr < op->value) {
10775 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010776 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010777 ctxt->error = XPATH_INVALID_OPERAND;
10778 return (total);
10779 }
10780 for (i = 0; i < op->value; i++)
10781 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10782 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010783 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010784 ctxt->error = XPATH_INVALID_OPERAND;
10785 return (total);
10786 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010787 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010788 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010789 else {
10790 const xmlChar *URI = NULL;
10791
10792 if (op->value5 == NULL)
10793 func =
10794 xmlXPathFunctionLookup(ctxt->context,
10795 op->value4);
10796 else {
10797 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10798 if (URI == NULL) {
10799 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010800 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010801 op->value4, op->value5);
10802 return (total);
10803 }
10804 func = xmlXPathFunctionLookupNS(ctxt->context,
10805 op->value4, URI);
10806 }
10807 if (func == NULL) {
10808 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010809 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010810 op->value4);
10811 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010812 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010813 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010814 op->cacheURI = (void *) URI;
10815 }
10816 oldFunc = ctxt->context->function;
10817 oldFuncURI = ctxt->context->functionURI;
10818 ctxt->context->function = op->value4;
10819 ctxt->context->functionURI = op->cacheURI;
10820 func(ctxt, op->value);
10821 ctxt->context->function = oldFunc;
10822 ctxt->context->functionURI = oldFuncURI;
10823 return (total);
10824 }
10825 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010826 bakd = ctxt->context->doc;
10827 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010828 pp = ctxt->context->proximityPosition;
10829 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010830 if (op->ch1 != -1)
10831 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010832 ctxt->context->contextSize = cs;
10833 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010834 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010835 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010836 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010837 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010838 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010839 ctxt->context->doc = bakd;
10840 ctxt->context->node = bak;
10841 CHECK_ERROR0;
10842 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010843 return (total);
10844 case XPATH_OP_PREDICATE:
10845 case XPATH_OP_FILTER:{
10846 xmlXPathObjectPtr res;
10847 xmlXPathObjectPtr obj, tmp;
10848 xmlNodeSetPtr newset = NULL;
10849 xmlNodeSetPtr oldset;
10850 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010851 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010852 int i;
10853
10854 /*
10855 * Optimization for ()[1] selection i.e. the first elem
10856 */
10857 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10858 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10859 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10860 xmlXPathObjectPtr val;
10861
10862 val = comp->steps[op->ch2].value4;
10863 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10864 (val->floatval == 1.0)) {
10865 xmlNodePtr first = NULL;
10866
10867 total +=
10868 xmlXPathCompOpEvalFirst(ctxt,
10869 &comp->steps[op->ch1],
10870 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010871 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010872 /*
10873 * The nodeset should be in document order,
10874 * Keep only the first value
10875 */
10876 if ((ctxt->value != NULL) &&
10877 (ctxt->value->type == XPATH_NODESET) &&
10878 (ctxt->value->nodesetval != NULL) &&
10879 (ctxt->value->nodesetval->nodeNr > 1))
10880 ctxt->value->nodesetval->nodeNr = 1;
10881 return (total);
10882 }
10883 }
10884 /*
10885 * Optimization for ()[last()] selection i.e. the last elem
10886 */
10887 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10888 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10889 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10890 int f = comp->steps[op->ch2].ch1;
10891
10892 if ((f != -1) &&
10893 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10894 (comp->steps[f].value5 == NULL) &&
10895 (comp->steps[f].value == 0) &&
10896 (comp->steps[f].value4 != NULL) &&
10897 (xmlStrEqual
10898 (comp->steps[f].value4, BAD_CAST "last"))) {
10899 xmlNodePtr last = NULL;
10900
10901 total +=
10902 xmlXPathCompOpEvalLast(ctxt,
10903 &comp->steps[op->ch1],
10904 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010905 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010906 /*
10907 * The nodeset should be in document order,
10908 * Keep only the last value
10909 */
10910 if ((ctxt->value != NULL) &&
10911 (ctxt->value->type == XPATH_NODESET) &&
10912 (ctxt->value->nodesetval != NULL) &&
10913 (ctxt->value->nodesetval->nodeTab != NULL) &&
10914 (ctxt->value->nodesetval->nodeNr > 1)) {
10915 ctxt->value->nodesetval->nodeTab[0] =
10916 ctxt->value->nodesetval->nodeTab[ctxt->
10917 value->
10918 nodesetval->
10919 nodeNr -
10920 1];
10921 ctxt->value->nodesetval->nodeNr = 1;
10922 }
10923 return (total);
10924 }
10925 }
10926
10927 if (op->ch1 != -1)
10928 total +=
10929 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010930 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010931 if (op->ch2 == -1)
10932 return (total);
10933 if (ctxt->value == NULL)
10934 return (total);
10935
10936 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010937
10938#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010939 /*
10940 * Hum are we filtering the result of an XPointer expression
10941 */
10942 if (ctxt->value->type == XPATH_LOCATIONSET) {
10943 xmlLocationSetPtr newlocset = NULL;
10944 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010945
Daniel Veillardf06307e2001-07-03 10:35:50 +000010946 /*
10947 * Extract the old locset, and then evaluate the result of the
10948 * expression for all the element in the locset. use it to grow
10949 * up a new locset.
10950 */
10951 CHECK_TYPE0(XPATH_LOCATIONSET);
10952 obj = valuePop(ctxt);
10953 oldlocset = obj->user;
10954 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010955
Daniel Veillardf06307e2001-07-03 10:35:50 +000010956 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10957 ctxt->context->contextSize = 0;
10958 ctxt->context->proximityPosition = 0;
10959 if (op->ch2 != -1)
10960 total +=
10961 xmlXPathCompOpEval(ctxt,
10962 &comp->steps[op->ch2]);
10963 res = valuePop(ctxt);
10964 if (res != NULL)
10965 xmlXPathFreeObject(res);
10966 valuePush(ctxt, obj);
10967 CHECK_ERROR0;
10968 return (total);
10969 }
10970 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010971
Daniel Veillardf06307e2001-07-03 10:35:50 +000010972 for (i = 0; i < oldlocset->locNr; i++) {
10973 /*
10974 * Run the evaluation with a node list made of a
10975 * single item in the nodelocset.
10976 */
10977 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010978 ctxt->context->contextSize = oldlocset->locNr;
10979 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010980 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10981 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010982
Daniel Veillardf06307e2001-07-03 10:35:50 +000010983 if (op->ch2 != -1)
10984 total +=
10985 xmlXPathCompOpEval(ctxt,
10986 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010987 if (ctxt->error != XPATH_EXPRESSION_OK) {
10988 xmlXPathFreeObject(obj);
10989 return(0);
10990 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010991
Daniel Veillardf06307e2001-07-03 10:35:50 +000010992 /*
10993 * The result of the evaluation need to be tested to
10994 * decided whether the filter succeeded or not
10995 */
10996 res = valuePop(ctxt);
10997 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10998 xmlXPtrLocationSetAdd(newlocset,
10999 xmlXPathObjectCopy
11000 (oldlocset->locTab[i]));
11001 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011002
Daniel Veillardf06307e2001-07-03 10:35:50 +000011003 /*
11004 * Cleanup
11005 */
11006 if (res != NULL)
11007 xmlXPathFreeObject(res);
11008 if (ctxt->value == tmp) {
11009 res = valuePop(ctxt);
11010 xmlXPathFreeObject(res);
11011 }
11012
11013 ctxt->context->node = NULL;
11014 }
11015
11016 /*
11017 * The result is used as the new evaluation locset.
11018 */
11019 xmlXPathFreeObject(obj);
11020 ctxt->context->node = NULL;
11021 ctxt->context->contextSize = -1;
11022 ctxt->context->proximityPosition = -1;
11023 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
11024 ctxt->context->node = oldnode;
11025 return (total);
11026 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011027#endif /* LIBXML_XPTR_ENABLED */
11028
Daniel Veillardf06307e2001-07-03 10:35:50 +000011029 /*
11030 * Extract the old set, and then evaluate the result of the
11031 * expression for all the element in the set. use it to grow
11032 * up a new set.
11033 */
11034 CHECK_TYPE0(XPATH_NODESET);
11035 obj = valuePop(ctxt);
11036 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000011037
Daniel Veillardf06307e2001-07-03 10:35:50 +000011038 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000011039 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011040 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011041
Daniel Veillardf06307e2001-07-03 10:35:50 +000011042 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
11043 ctxt->context->contextSize = 0;
11044 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000011045/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000011046 if (op->ch2 != -1)
11047 total +=
11048 xmlXPathCompOpEval(ctxt,
11049 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011050 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011051 res = valuePop(ctxt);
11052 if (res != NULL)
11053 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000011054*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000011055 valuePush(ctxt, obj);
11056 ctxt->context->node = oldnode;
11057 CHECK_ERROR0;
11058 } else {
11059 /*
11060 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000011061 * Also set the xpath document in case things like
11062 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000011063 */
11064 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011065
Daniel Veillardf06307e2001-07-03 10:35:50 +000011066 for (i = 0; i < oldset->nodeNr; i++) {
11067 /*
11068 * Run the evaluation with a node list made of
11069 * a single item in the nodeset.
11070 */
11071 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000011072 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
11073 (oldset->nodeTab[i]->doc != NULL))
11074 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011075 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11076 valuePush(ctxt, tmp);
11077 ctxt->context->contextSize = oldset->nodeNr;
11078 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011079
Daniel Veillardf06307e2001-07-03 10:35:50 +000011080 if (op->ch2 != -1)
11081 total +=
11082 xmlXPathCompOpEval(ctxt,
11083 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011084 if (ctxt->error != XPATH_EXPRESSION_OK) {
11085 xmlXPathFreeNodeSet(newset);
11086 xmlXPathFreeObject(obj);
11087 return(0);
11088 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011089
Daniel Veillardf06307e2001-07-03 10:35:50 +000011090 /*
William M. Brack08171912003-12-29 02:52:11 +000011091 * The result of the evaluation needs to be tested to
11092 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000011093 */
11094 res = valuePop(ctxt);
11095 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
11096 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
11097 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011098
Daniel Veillardf06307e2001-07-03 10:35:50 +000011099 /*
11100 * Cleanup
11101 */
11102 if (res != NULL)
11103 xmlXPathFreeObject(res);
11104 if (ctxt->value == tmp) {
11105 res = valuePop(ctxt);
11106 xmlXPathFreeObject(res);
11107 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011108
Daniel Veillardf06307e2001-07-03 10:35:50 +000011109 ctxt->context->node = NULL;
11110 }
11111
11112 /*
11113 * The result is used as the new evaluation set.
11114 */
11115 xmlXPathFreeObject(obj);
11116 ctxt->context->node = NULL;
11117 ctxt->context->contextSize = -1;
11118 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000011119 /* may want to move this past the '}' later */
11120 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011121 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
11122 }
11123 ctxt->context->node = oldnode;
11124 return (total);
11125 }
11126 case XPATH_OP_SORT:
11127 if (op->ch1 != -1)
11128 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011129 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011130 if ((ctxt->value != NULL) &&
11131 (ctxt->value->type == XPATH_NODESET) &&
11132 (ctxt->value->nodesetval != NULL))
11133 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11134 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011135#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000011136 case XPATH_OP_RANGETO:{
11137 xmlXPathObjectPtr range;
11138 xmlXPathObjectPtr res, obj;
11139 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000011140 xmlLocationSetPtr newlocset = NULL;
11141 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011142 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000011143 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011144
Daniel Veillardf06307e2001-07-03 10:35:50 +000011145 if (op->ch1 != -1)
11146 total +=
11147 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11148 if (op->ch2 == -1)
11149 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011150
William M. Brack08171912003-12-29 02:52:11 +000011151 if (ctxt->value->type == XPATH_LOCATIONSET) {
11152 /*
11153 * Extract the old locset, and then evaluate the result of the
11154 * expression for all the element in the locset. use it to grow
11155 * up a new locset.
11156 */
11157 CHECK_TYPE0(XPATH_LOCATIONSET);
11158 obj = valuePop(ctxt);
11159 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011160
William M. Brack08171912003-12-29 02:52:11 +000011161 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000011162 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000011163 ctxt->context->contextSize = 0;
11164 ctxt->context->proximityPosition = 0;
11165 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
11166 res = valuePop(ctxt);
11167 if (res != NULL)
11168 xmlXPathFreeObject(res);
11169 valuePush(ctxt, obj);
11170 CHECK_ERROR0;
11171 return (total);
11172 }
11173 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011174
William M. Brack08171912003-12-29 02:52:11 +000011175 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011176 /*
William M. Brack08171912003-12-29 02:52:11 +000011177 * Run the evaluation with a node list made of a
11178 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000011179 */
William M. Brackf7eb7942003-12-31 07:59:17 +000011180 ctxt->context->node = oldlocset->locTab[i]->user;
11181 ctxt->context->contextSize = oldlocset->locNr;
11182 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011183 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11184 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011185
Daniel Veillardf06307e2001-07-03 10:35:50 +000011186 if (op->ch2 != -1)
11187 total +=
11188 xmlXPathCompOpEval(ctxt,
11189 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011190 if (ctxt->error != XPATH_EXPRESSION_OK) {
11191 xmlXPathFreeObject(obj);
11192 return(0);
11193 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011194
Daniel Veillardf06307e2001-07-03 10:35:50 +000011195 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000011196 if (res->type == XPATH_LOCATIONSET) {
11197 xmlLocationSetPtr rloc =
11198 (xmlLocationSetPtr)res->user;
11199 for (j=0; j<rloc->locNr; j++) {
11200 range = xmlXPtrNewRange(
11201 oldlocset->locTab[i]->user,
11202 oldlocset->locTab[i]->index,
11203 rloc->locTab[j]->user2,
11204 rloc->locTab[j]->index2);
11205 if (range != NULL) {
11206 xmlXPtrLocationSetAdd(newlocset, range);
11207 }
11208 }
11209 } else {
11210 range = xmlXPtrNewRangeNodeObject(
11211 (xmlNodePtr)oldlocset->locTab[i]->user, res);
11212 if (range != NULL) {
11213 xmlXPtrLocationSetAdd(newlocset,range);
11214 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011215 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011216
Daniel Veillardf06307e2001-07-03 10:35:50 +000011217 /*
11218 * Cleanup
11219 */
11220 if (res != NULL)
11221 xmlXPathFreeObject(res);
11222 if (ctxt->value == tmp) {
11223 res = valuePop(ctxt);
11224 xmlXPathFreeObject(res);
11225 }
11226
11227 ctxt->context->node = NULL;
11228 }
William M. Brack72ee48d2003-12-30 08:30:19 +000011229 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000011230 CHECK_TYPE0(XPATH_NODESET);
11231 obj = valuePop(ctxt);
11232 oldset = obj->nodesetval;
11233 ctxt->context->node = NULL;
11234
11235 newlocset = xmlXPtrLocationSetCreate(NULL);
11236
11237 if (oldset != NULL) {
11238 for (i = 0; i < oldset->nodeNr; i++) {
11239 /*
11240 * Run the evaluation with a node list made of a single item
11241 * in the nodeset.
11242 */
11243 ctxt->context->node = oldset->nodeTab[i];
11244 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11245 valuePush(ctxt, tmp);
11246
11247 if (op->ch2 != -1)
11248 total +=
11249 xmlXPathCompOpEval(ctxt,
11250 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011251 if (ctxt->error != XPATH_EXPRESSION_OK) {
11252 xmlXPathFreeObject(obj);
11253 return(0);
11254 }
William M. Brack08171912003-12-29 02:52:11 +000011255
William M. Brack08171912003-12-29 02:52:11 +000011256 res = valuePop(ctxt);
11257 range =
11258 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
11259 res);
11260 if (range != NULL) {
11261 xmlXPtrLocationSetAdd(newlocset, range);
11262 }
11263
11264 /*
11265 * Cleanup
11266 */
11267 if (res != NULL)
11268 xmlXPathFreeObject(res);
11269 if (ctxt->value == tmp) {
11270 res = valuePop(ctxt);
11271 xmlXPathFreeObject(res);
11272 }
11273
11274 ctxt->context->node = NULL;
11275 }
11276 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011277 }
11278
11279 /*
11280 * The result is used as the new evaluation set.
11281 */
11282 xmlXPathFreeObject(obj);
11283 ctxt->context->node = NULL;
11284 ctxt->context->contextSize = -1;
11285 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000011286 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011287 return (total);
11288 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011289#endif /* LIBXML_XPTR_ENABLED */
11290 }
11291 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011292 "XPath: unknown precompiled operation %d\n", op->op);
11293 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011294}
11295
Daniel Veillard56de87e2005-02-16 00:22:29 +000011296#ifdef XPATH_STREAMING
11297/**
11298 * xmlXPathRunStreamEval:
11299 * @ctxt: the XPath parser context with the compiled expression
11300 *
11301 * Evaluate the Precompiled Streamable XPath expression in the given context.
11302 */
11303static xmlXPathObjectPtr
11304xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011305 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011306 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011307 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011308#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11309 int eval_all_nodes;
11310#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000011311 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011312 xmlXPathObjectPtr retval;
11313 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011314
11315 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011316
11317 if ((ctxt == NULL) || (comp == NULL))
11318 return(NULL);
11319 max_depth = xmlPatternMaxDepth(comp);
11320 if (max_depth == -1)
11321 return(NULL);
11322 if (max_depth == -2)
11323 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011324 min_depth = xmlPatternMinDepth(comp);
11325 if (min_depth == -1)
11326 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011327 from_root = xmlPatternFromRoot(comp);
11328 if (from_root < 0)
11329 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011330#if 0
11331 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11332#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011333
11334 retval = xmlXPathNewNodeSet(NULL);
11335 if (retval == NULL)
11336 return(NULL);
11337
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011338 /*
11339 * handle the special cases of / amd . being matched
11340 */
11341 if (min_depth == 0) {
11342 if (from_root) {
11343 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11344 } else {
11345 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11346 }
11347 }
11348 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011349 return(retval);
11350 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011351
Daniel Veillard56de87e2005-02-16 00:22:29 +000011352 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011353 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011354 } else if (ctxt->node != NULL) {
11355 switch (ctxt->node->type) {
11356 case XML_ELEMENT_NODE:
11357 case XML_DOCUMENT_NODE:
11358 case XML_DOCUMENT_FRAG_NODE:
11359 case XML_HTML_DOCUMENT_NODE:
11360#ifdef LIBXML_DOCB_ENABLED
11361 case XML_DOCB_DOCUMENT_NODE:
11362#endif
11363 cur = ctxt->node;
11364 break;
11365 case XML_ATTRIBUTE_NODE:
11366 case XML_TEXT_NODE:
11367 case XML_CDATA_SECTION_NODE:
11368 case XML_ENTITY_REF_NODE:
11369 case XML_ENTITY_NODE:
11370 case XML_PI_NODE:
11371 case XML_COMMENT_NODE:
11372 case XML_NOTATION_NODE:
11373 case XML_DTD_NODE:
11374 case XML_DOCUMENT_TYPE_NODE:
11375 case XML_ELEMENT_DECL:
11376 case XML_ATTRIBUTE_DECL:
11377 case XML_ENTITY_DECL:
11378 case XML_NAMESPACE_DECL:
11379 case XML_XINCLUDE_START:
11380 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011381 break;
11382 }
11383 limit = cur;
11384 }
11385 if (cur == NULL)
11386 return(retval);
11387
11388 patstream = xmlPatternGetStreamCtxt(comp);
11389 if (patstream == NULL) {
11390 return(retval);
11391 }
11392
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011393#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11394 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11395#endif
11396
Daniel Veillard56de87e2005-02-16 00:22:29 +000011397 if (from_root) {
11398 ret = xmlStreamPush(patstream, NULL, NULL);
11399 if (ret < 0) {
11400 } else if (ret == 1) {
11401 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11402 }
11403 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011404 depth = 0;
11405 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011406next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000011407 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011408 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011409
11410 switch (cur->type) {
11411 case XML_ELEMENT_NODE:
11412#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11413 case XML_TEXT_NODE:
11414 case XML_CDATA_SECTION_NODE:
11415 case XML_COMMENT_NODE:
11416 case XML_PI_NODE:
11417#endif
11418 if (cur->type == XML_ELEMENT_NODE) {
11419 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000011420 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000011421 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011422#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11423 else if (eval_all_nodes)
11424 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11425 else
11426 break;
11427#endif
11428
11429 if (ret < 0) {
11430 /* NOP. */
11431 } else if (ret == 1) {
11432 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11433 }
11434 if ((cur->children == NULL) || (depth >= max_depth)) {
11435 ret = xmlStreamPop(patstream);
11436 while (cur->next != NULL) {
11437 cur = cur->next;
11438 if ((cur->type != XML_ENTITY_DECL) &&
11439 (cur->type != XML_DTD_NODE))
11440 goto next_node;
11441 }
11442 }
11443 default:
11444 break;
11445 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011446
11447scan_children:
11448 if ((cur->children != NULL) && (depth < max_depth)) {
11449 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011450 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000011451 */
11452 if (cur->children->type != XML_ENTITY_DECL) {
11453 cur = cur->children;
11454 depth++;
11455 /*
11456 * Skip DTDs
11457 */
11458 if (cur->type != XML_DTD_NODE)
11459 continue;
11460 }
11461 }
11462
11463 if (cur == limit)
11464 break;
11465
11466 while (cur->next != NULL) {
11467 cur = cur->next;
11468 if ((cur->type != XML_ENTITY_DECL) &&
11469 (cur->type != XML_DTD_NODE))
11470 goto next_node;
11471 }
11472
11473 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011474 cur = cur->parent;
11475 depth--;
11476 if ((cur == NULL) || (cur == limit))
11477 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011478 if (cur->type == XML_ELEMENT_NODE) {
11479 ret = xmlStreamPop(patstream);
11480 }
11481#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11482 else if ((eval_all_nodes) &&
11483 ((cur->type == XML_TEXT_NODE) ||
11484 (cur->type == XML_CDATA_SECTION_NODE) ||
11485 (cur->type == XML_COMMENT_NODE) ||
11486 (cur->type == XML_PI_NODE)))
11487 {
11488 ret = xmlStreamPop(patstream);
11489 }
11490#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011491 if (cur->next != NULL) {
11492 cur = cur->next;
11493 break;
11494 }
11495 } while (cur != NULL);
11496
11497 } while ((cur != NULL) && (depth >= 0));
11498done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011499#if 0
11500 printf("stream eval: checked %d nodes selected %d\n",
11501 nb_nodes, retval->nodesetval->nodeNr);
11502#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011503 xmlFreeStreamCtxt(patstream);
11504 return(retval);
11505}
11506#endif /* XPATH_STREAMING */
11507
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011508/**
11509 * xmlXPathRunEval:
11510 * @ctxt: the XPath parser context with the compiled expression
11511 *
11512 * Evaluate the Precompiled XPath expression in the given context.
11513 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011514static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011515xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11516 xmlXPathCompExprPtr comp;
11517
11518 if ((ctxt == NULL) || (ctxt->comp == NULL))
11519 return;
11520
11521 if (ctxt->valueTab == NULL) {
11522 /* Allocate the value stack */
11523 ctxt->valueTab = (xmlXPathObjectPtr *)
11524 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11525 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011526 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011527 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011528 }
11529 ctxt->valueNr = 0;
11530 ctxt->valueMax = 10;
11531 ctxt->value = NULL;
11532 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011533#ifdef XPATH_STREAMING
11534 if (ctxt->comp->stream) {
11535 xmlXPathObjectPtr ret;
11536 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11537 if (ret != NULL) {
11538 valuePush(ctxt, ret);
11539 return;
11540 }
11541 }
11542#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011543 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011544 if(comp->last < 0) {
11545 xmlGenericError(xmlGenericErrorContext,
11546 "xmlXPathRunEval: last is less than zero\n");
11547 return;
11548 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011549 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11550}
11551
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011552/************************************************************************
11553 * *
11554 * Public interfaces *
11555 * *
11556 ************************************************************************/
11557
11558/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011559 * xmlXPathEvalPredicate:
11560 * @ctxt: the XPath context
11561 * @res: the Predicate Expression evaluation result
11562 *
11563 * Evaluate a predicate result for the current node.
11564 * A PredicateExpr is evaluated by evaluating the Expr and converting
11565 * the result to a boolean. If the result is a number, the result will
11566 * be converted to true if the number is equal to the position of the
11567 * context node in the context node list (as returned by the position
11568 * function) and will be converted to false otherwise; if the result
11569 * is not a number, then the result will be converted as if by a call
11570 * to the boolean function.
11571 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011572 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011573 */
11574int
11575xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011576 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011577 switch (res->type) {
11578 case XPATH_BOOLEAN:
11579 return(res->boolval);
11580 case XPATH_NUMBER:
11581 return(res->floatval == ctxt->proximityPosition);
11582 case XPATH_NODESET:
11583 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011584 if (res->nodesetval == NULL)
11585 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011586 return(res->nodesetval->nodeNr != 0);
11587 case XPATH_STRING:
11588 return((res->stringval != NULL) &&
11589 (xmlStrlen(res->stringval) != 0));
11590 default:
11591 STRANGE
11592 }
11593 return(0);
11594}
11595
11596/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011597 * xmlXPathEvaluatePredicateResult:
11598 * @ctxt: the XPath Parser context
11599 * @res: the Predicate Expression evaluation result
11600 *
11601 * Evaluate a predicate result for the current node.
11602 * A PredicateExpr is evaluated by evaluating the Expr and converting
11603 * the result to a boolean. If the result is a number, the result will
11604 * be converted to true if the number is equal to the position of the
11605 * context node in the context node list (as returned by the position
11606 * function) and will be converted to false otherwise; if the result
11607 * is not a number, then the result will be converted as if by a call
11608 * to the boolean function.
11609 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011610 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011611 */
11612int
11613xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11614 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011615 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011616 switch (res->type) {
11617 case XPATH_BOOLEAN:
11618 return(res->boolval);
11619 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011620#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011621 return((res->floatval == ctxt->context->proximityPosition) &&
11622 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011623#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011624 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011625#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011626 case XPATH_NODESET:
11627 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011628 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011629 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011630 return(res->nodesetval->nodeNr != 0);
11631 case XPATH_STRING:
11632 return((res->stringval != NULL) &&
11633 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011634#ifdef LIBXML_XPTR_ENABLED
11635 case XPATH_LOCATIONSET:{
11636 xmlLocationSetPtr ptr = res->user;
11637 if (ptr == NULL)
11638 return(0);
11639 return (ptr->locNr != 0);
11640 }
11641#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011642 default:
11643 STRANGE
11644 }
11645 return(0);
11646}
11647
Daniel Veillard56de87e2005-02-16 00:22:29 +000011648#ifdef XPATH_STREAMING
11649/**
11650 * xmlXPathTryStreamCompile:
11651 * @ctxt: an XPath context
11652 * @str: the XPath expression
11653 *
11654 * Try to compile the XPath expression as a streamable subset.
11655 *
11656 * Returns the compiled expression or NULL if failed to compile.
11657 */
11658static xmlXPathCompExprPtr
11659xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11660 /*
11661 * Optimization: use streaming patterns when the XPath expression can
11662 * be compiled to a stream lookup
11663 */
11664 xmlPatternPtr stream;
11665 xmlXPathCompExprPtr comp;
11666 xmlDictPtr dict = NULL;
11667 const xmlChar **namespaces = NULL;
11668 xmlNsPtr ns;
11669 int i, j;
11670
11671 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11672 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011673 const xmlChar *tmp;
11674
11675 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000011676 * We don't try to handle expressions using the verbose axis
11677 * specifiers ("::"), just the simplied form at this point.
11678 * Additionally, if there is no list of namespaces available and
11679 * there's a ":" in the expression, indicating a prefixed QName,
11680 * then we won't try to compile either. xmlPatterncompile() needs
11681 * to have a list of namespaces at compilation time in order to
11682 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011683 */
11684 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000011685 if ((tmp != NULL) &&
11686 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
11687 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011688
Daniel Veillard56de87e2005-02-16 00:22:29 +000011689 if (ctxt != NULL) {
11690 dict = ctxt->dict;
11691 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000011692 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000011693 if (namespaces == NULL) {
11694 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11695 return(NULL);
11696 }
11697 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11698 ns = ctxt->namespaces[j];
11699 namespaces[i++] = ns->href;
11700 namespaces[i++] = ns->prefix;
11701 }
11702 namespaces[i++] = NULL;
11703 namespaces[i++] = NULL;
11704 }
11705 }
11706
William M. Brackea152c02005-06-09 18:12:28 +000011707 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
11708 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000011709 if (namespaces != NULL) {
11710 xmlFree((xmlChar **)namespaces);
11711 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011712 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11713 comp = xmlXPathNewCompExpr();
11714 if (comp == NULL) {
11715 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11716 return(NULL);
11717 }
11718 comp->stream = stream;
11719 comp->dict = dict;
11720 if (comp->dict)
11721 xmlDictReference(comp->dict);
11722 return(comp);
11723 }
11724 xmlFreePattern(stream);
11725 }
11726 return(NULL);
11727}
11728#endif /* XPATH_STREAMING */
11729
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011730/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011731 * xmlXPathCtxtCompile:
11732 * @ctxt: an XPath context
11733 * @str: the XPath expression
11734 *
11735 * Compile an XPath expression
11736 *
11737 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11738 * the caller has to free the object.
11739 */
11740xmlXPathCompExprPtr
11741xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11742 xmlXPathParserContextPtr pctxt;
11743 xmlXPathCompExprPtr comp;
11744
Daniel Veillard56de87e2005-02-16 00:22:29 +000011745#ifdef XPATH_STREAMING
11746 comp = xmlXPathTryStreamCompile(ctxt, str);
11747 if (comp != NULL)
11748 return(comp);
11749#endif
11750
Daniel Veillard4773df22004-01-23 13:15:13 +000011751 xmlXPathInit();
11752
11753 pctxt = xmlXPathNewParserContext(str, ctxt);
11754 xmlXPathCompileExpr(pctxt);
11755
11756 if( pctxt->error != XPATH_EXPRESSION_OK )
11757 {
11758 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011759 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000011760 }
11761
11762 if (*pctxt->cur != 0) {
11763 /*
11764 * aleksey: in some cases this line prints *second* error message
11765 * (see bug #78858) and probably this should be fixed.
11766 * However, we are not sure that all error messages are printed
11767 * out in other places. It's not critical so we leave it as-is for now
11768 */
11769 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11770 comp = NULL;
11771 } else {
11772 comp = pctxt->comp;
11773 pctxt->comp = NULL;
11774 }
11775 xmlXPathFreeParserContext(pctxt);
11776 if (comp != NULL) {
11777 comp->expr = xmlStrdup(str);
11778#ifdef DEBUG_EVAL_COUNTS
11779 comp->string = xmlStrdup(str);
11780 comp->nb = 0;
11781#endif
11782 }
11783 return(comp);
11784}
11785
11786/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011787 * xmlXPathCompile:
11788 * @str: the XPath expression
11789 *
11790 * Compile an XPath expression
11791 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011792 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011793 * the caller has to free the object.
11794 */
11795xmlXPathCompExprPtr
11796xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011797 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011798}
11799
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011800/**
11801 * xmlXPathCompiledEval:
11802 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011803 * @ctx: the XPath context
11804 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011805 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011806 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011807 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011808 * the caller has to free the object.
11809 */
11810xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011811xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011812 xmlXPathParserContextPtr ctxt;
11813 xmlXPathObjectPtr res, tmp, init = NULL;
11814 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011815#ifndef LIBXML_THREAD_ENABLED
11816 static int reentance = 0;
11817#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011818
William M. Brackf13f77f2004-11-12 16:03:48 +000011819 CHECK_CTXT(ctx)
11820
11821 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011822 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011823 xmlXPathInit();
11824
Daniel Veillard81463942001-10-16 12:34:39 +000011825#ifndef LIBXML_THREAD_ENABLED
11826 reentance++;
11827 if (reentance > 1)
11828 xmlXPathDisableOptimizer = 1;
11829#endif
11830
Daniel Veillardf06307e2001-07-03 10:35:50 +000011831#ifdef DEBUG_EVAL_COUNTS
11832 comp->nb++;
11833 if ((comp->string != NULL) && (comp->nb > 100)) {
11834 fprintf(stderr, "100 x %s\n", comp->string);
11835 comp->nb = 0;
11836 }
11837#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011838 ctxt = xmlXPathCompParserContext(comp, ctx);
11839 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011840
11841 if (ctxt->value == NULL) {
11842 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011843 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011844 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011845 } else {
11846 res = valuePop(ctxt);
11847 }
11848
Daniel Veillardf06307e2001-07-03 10:35:50 +000011849
Owen Taylor3473f882001-02-23 17:55:21 +000011850 do {
11851 tmp = valuePop(ctxt);
11852 if (tmp != NULL) {
11853 if (tmp != init)
11854 stack++;
11855 xmlXPathFreeObject(tmp);
11856 }
11857 } while (tmp != NULL);
11858 if ((stack != 0) && (res != NULL)) {
11859 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011860 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011861 stack);
11862 }
11863 if (ctxt->error != XPATH_EXPRESSION_OK) {
11864 xmlXPathFreeObject(res);
11865 res = NULL;
11866 }
11867
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011868
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011869 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011870 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011871#ifndef LIBXML_THREAD_ENABLED
11872 reentance--;
11873#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011874 return(res);
11875}
11876
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011877/**
11878 * xmlXPathEvalExpr:
11879 * @ctxt: the XPath Parser context
11880 *
11881 * Parse and evaluate an XPath expression in the given context,
11882 * then push the result on the context stack
11883 */
11884void
11885xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011886#ifdef XPATH_STREAMING
11887 xmlXPathCompExprPtr comp;
11888#endif
11889
Daniel Veillarda82b1822004-11-08 16:24:57 +000011890 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011891
11892#ifdef XPATH_STREAMING
11893 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11894 if (comp != NULL) {
11895 if (ctxt->comp != NULL)
11896 xmlXPathFreeCompExpr(ctxt->comp);
11897 ctxt->comp = comp;
11898 if (ctxt->cur != NULL)
11899 while (*ctxt->cur != 0) ctxt->cur++;
11900 } else
11901#endif
11902 {
11903 xmlXPathCompileExpr(ctxt);
11904 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011905 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011906 xmlXPathRunEval(ctxt);
11907}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011908
11909/**
11910 * xmlXPathEval:
11911 * @str: the XPath expression
11912 * @ctx: the XPath context
11913 *
11914 * Evaluate the XPath Location Path in the given context.
11915 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011916 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011917 * the caller has to free the object.
11918 */
11919xmlXPathObjectPtr
11920xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11921 xmlXPathParserContextPtr ctxt;
11922 xmlXPathObjectPtr res, tmp, init = NULL;
11923 int stack = 0;
11924
William M. Brackf13f77f2004-11-12 16:03:48 +000011925 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011926
William M. Brackf13f77f2004-11-12 16:03:48 +000011927 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011928
11929 ctxt = xmlXPathNewParserContext(str, ctx);
11930 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011931
11932 if (ctxt->value == NULL) {
11933 xmlGenericError(xmlGenericErrorContext,
11934 "xmlXPathEval: evaluation failed\n");
11935 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011936 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11937#ifdef XPATH_STREAMING
11938 && (ctxt->comp->stream == NULL)
11939#endif
11940 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011941 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11942 res = NULL;
11943 } else {
11944 res = valuePop(ctxt);
11945 }
11946
11947 do {
11948 tmp = valuePop(ctxt);
11949 if (tmp != NULL) {
11950 if (tmp != init)
11951 stack++;
11952 xmlXPathFreeObject(tmp);
11953 }
11954 } while (tmp != NULL);
11955 if ((stack != 0) && (res != NULL)) {
11956 xmlGenericError(xmlGenericErrorContext,
11957 "xmlXPathEval: %d object left on the stack\n",
11958 stack);
11959 }
11960 if (ctxt->error != XPATH_EXPRESSION_OK) {
11961 xmlXPathFreeObject(res);
11962 res = NULL;
11963 }
11964
Owen Taylor3473f882001-02-23 17:55:21 +000011965 xmlXPathFreeParserContext(ctxt);
11966 return(res);
11967}
11968
11969/**
11970 * xmlXPathEvalExpression:
11971 * @str: the XPath expression
11972 * @ctxt: the XPath context
11973 *
11974 * Evaluate the XPath expression in the given context.
11975 *
11976 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11977 * the caller has to free the object.
11978 */
11979xmlXPathObjectPtr
11980xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11981 xmlXPathParserContextPtr pctxt;
11982 xmlXPathObjectPtr res, tmp;
11983 int stack = 0;
11984
William M. Brackf13f77f2004-11-12 16:03:48 +000011985 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011986
William M. Brackf13f77f2004-11-12 16:03:48 +000011987 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011988
11989 pctxt = xmlXPathNewParserContext(str, ctxt);
11990 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011991
11992 if (*pctxt->cur != 0) {
11993 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11994 res = NULL;
11995 } else {
11996 res = valuePop(pctxt);
11997 }
11998 do {
11999 tmp = valuePop(pctxt);
12000 if (tmp != NULL) {
12001 xmlXPathFreeObject(tmp);
12002 stack++;
12003 }
12004 } while (tmp != NULL);
12005 if ((stack != 0) && (res != NULL)) {
12006 xmlGenericError(xmlGenericErrorContext,
12007 "xmlXPathEvalExpression: %d object left on the stack\n",
12008 stack);
12009 }
12010 xmlXPathFreeParserContext(pctxt);
12011 return(res);
12012}
12013
Daniel Veillard42766c02002-08-22 20:52:17 +000012014/************************************************************************
12015 * *
12016 * Extra functions not pertaining to the XPath spec *
12017 * *
12018 ************************************************************************/
12019/**
12020 * xmlXPathEscapeUriFunction:
12021 * @ctxt: the XPath Parser context
12022 * @nargs: the number of arguments
12023 *
12024 * Implement the escape-uri() XPath function
12025 * string escape-uri(string $str, bool $escape-reserved)
12026 *
12027 * This function applies the URI escaping rules defined in section 2 of [RFC
12028 * 2396] to the string supplied as $uri-part, which typically represents all
12029 * or part of a URI. The effect of the function is to replace any special
12030 * character in the string by an escape sequence of the form %xx%yy...,
12031 * where xxyy... is the hexadecimal representation of the octets used to
12032 * represent the character in UTF-8.
12033 *
12034 * The set of characters that are escaped depends on the setting of the
12035 * boolean argument $escape-reserved.
12036 *
12037 * If $escape-reserved is true, all characters are escaped other than lower
12038 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12039 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12040 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12041 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12042 * A-F).
12043 *
12044 * If $escape-reserved is false, the behavior differs in that characters
12045 * referred to in [RFC 2396] as reserved characters are not escaped. These
12046 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12047 *
12048 * [RFC 2396] does not define whether escaped URIs should use lower case or
12049 * upper case for hexadecimal digits. To ensure that escaped URIs can be
12050 * compared using string comparison functions, this function must always use
12051 * the upper-case letters A-F.
12052 *
12053 * Generally, $escape-reserved should be set to true when escaping a string
12054 * that is to form a single part of a URI, and to false when escaping an
12055 * entire URI or URI reference.
12056 *
12057 * In the case of non-ascii characters, the string is encoded according to
12058 * utf-8 and then converted according to RFC 2396.
12059 *
12060 * Examples
12061 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12062 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12063 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12064 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12065 *
12066 */
Daniel Veillard118aed72002-09-24 14:13:13 +000012067static void
Daniel Veillard42766c02002-08-22 20:52:17 +000012068xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12069 xmlXPathObjectPtr str;
12070 int escape_reserved;
12071 xmlBufferPtr target;
12072 xmlChar *cptr;
12073 xmlChar escape[4];
12074
12075 CHECK_ARITY(2);
12076
12077 escape_reserved = xmlXPathPopBoolean(ctxt);
12078
12079 CAST_TO_STRING;
12080 str = valuePop(ctxt);
12081
12082 target = xmlBufferCreate();
12083
12084 escape[0] = '%';
12085 escape[3] = 0;
12086
12087 if (target) {
12088 for (cptr = str->stringval; *cptr; cptr++) {
12089 if ((*cptr >= 'A' && *cptr <= 'Z') ||
12090 (*cptr >= 'a' && *cptr <= 'z') ||
12091 (*cptr >= '0' && *cptr <= '9') ||
12092 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
12093 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
12094 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12095 (*cptr == '%' &&
12096 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12097 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12098 (cptr[1] >= '0' && cptr[1] <= '9')) &&
12099 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12100 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12101 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12102 (!escape_reserved &&
12103 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12104 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12105 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12106 *cptr == ','))) {
12107 xmlBufferAdd(target, cptr, 1);
12108 } else {
12109 if ((*cptr >> 4) < 10)
12110 escape[1] = '0' + (*cptr >> 4);
12111 else
12112 escape[1] = 'A' - 10 + (*cptr >> 4);
12113 if ((*cptr & 0xF) < 10)
12114 escape[2] = '0' + (*cptr & 0xF);
12115 else
12116 escape[2] = 'A' - 10 + (*cptr & 0xF);
12117
12118 xmlBufferAdd(target, &escape[0], 3);
12119 }
12120 }
12121 }
12122 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
12123 xmlBufferFree(target);
12124 xmlXPathFreeObject(str);
12125}
12126
Owen Taylor3473f882001-02-23 17:55:21 +000012127/**
12128 * xmlXPathRegisterAllFunctions:
12129 * @ctxt: the XPath context
12130 *
12131 * Registers all default XPath functions in this context
12132 */
12133void
12134xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12135{
12136 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12137 xmlXPathBooleanFunction);
12138 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12139 xmlXPathCeilingFunction);
12140 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12141 xmlXPathCountFunction);
12142 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12143 xmlXPathConcatFunction);
12144 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12145 xmlXPathContainsFunction);
12146 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12147 xmlXPathIdFunction);
12148 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12149 xmlXPathFalseFunction);
12150 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12151 xmlXPathFloorFunction);
12152 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12153 xmlXPathLastFunction);
12154 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12155 xmlXPathLangFunction);
12156 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12157 xmlXPathLocalNameFunction);
12158 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12159 xmlXPathNotFunction);
12160 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12161 xmlXPathNameFunction);
12162 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12163 xmlXPathNamespaceURIFunction);
12164 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12165 xmlXPathNormalizeFunction);
12166 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12167 xmlXPathNumberFunction);
12168 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
12169 xmlXPathPositionFunction);
12170 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
12171 xmlXPathRoundFunction);
12172 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
12173 xmlXPathStringFunction);
12174 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
12175 xmlXPathStringLengthFunction);
12176 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
12177 xmlXPathStartsWithFunction);
12178 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
12179 xmlXPathSubstringFunction);
12180 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
12181 xmlXPathSubstringBeforeFunction);
12182 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
12183 xmlXPathSubstringAfterFunction);
12184 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
12185 xmlXPathSumFunction);
12186 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
12187 xmlXPathTrueFunction);
12188 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
12189 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000012190
12191 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
12192 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
12193 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000012194}
12195
12196#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000012197#define bottom_xpath
12198#include "elfgcchack.h"