blob: 9c0ff6f439e13bb91ddd5290537bd48c952d5ea1 [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/*
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000080* XP_OPTIMIZED_NON_ELEM_COMPARISON:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +000081* If defined, this will use xmlXPathCmpNodesExt() instead of
82* xmlXPathCmpNodes(). The new function is optimized comparison of
83* non-element nodes; actually it will speed up comparison only if
84* xmlXPathOrderDocElems() was called in order to index the elements of
85* a tree in document order; Libxslt does such an indexing, thus it will
86* benefit from this optimization.
87*/
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000088#define XP_OPTIMIZED_NON_ELEM_COMPARISON
89
90/*
91* XP_OPTIMIZED_FILTER_FIRST:
92* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
93* in a way, that it stop evaluation at the first node.
94*/
95#define XP_OPTIMIZED_FILTER_FIRST
96
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000097/*
William M. Brackd1757ab2004-10-02 22:07:48 +000098 * TODO:
99 * There are a few spots where some tests are done which depend upon ascii
100 * data. These should be enhanced for full UTF8 support (see particularly
101 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
102 */
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000103
William M. Brack21e4ef22005-01-02 09:53:13 +0000104#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000105/************************************************************************
106 * *
107 * Floating point stuff *
108 * *
109 ************************************************************************/
110
Daniel Veillardc0631a62001-09-20 13:56:06 +0000111#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +0000112#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +0000113#endif
Daniel Veillardcda96922001-08-21 10:56:31 +0000114#include "trionan.c"
115
Owen Taylor3473f882001-02-23 17:55:21 +0000116/*
Owen Taylor3473f882001-02-23 17:55:21 +0000117 * The lack of portability of this section of the libc is annoying !
118 */
119double xmlXPathNAN = 0;
120double xmlXPathPINF = 1;
121double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +0000122static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000123static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000124
Owen Taylor3473f882001-02-23 17:55:21 +0000125/**
126 * xmlXPathInit:
127 *
128 * Initialize the XPath environment
129 */
130void
131xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000132 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000133
Bjorn Reese45029602001-08-21 09:23:53 +0000134 xmlXPathPINF = trio_pinf();
135 xmlXPathNINF = trio_ninf();
136 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000137 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000138
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000139 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000140}
141
Daniel Veillardcda96922001-08-21 10:56:31 +0000142/**
143 * xmlXPathIsNaN:
144 * @val: a double value
145 *
146 * Provides a portable isnan() function to detect whether a double
147 * is a NotaNumber. Based on trio code
148 * http://sourceforge.net/projects/ctrio/
149 *
150 * Returns 1 if the value is a NaN, 0 otherwise
151 */
152int
153xmlXPathIsNaN(double val) {
154 return(trio_isnan(val));
155}
156
157/**
158 * xmlXPathIsInf:
159 * @val: a double value
160 *
161 * Provides a portable isinf() function to detect whether a double
162 * is a +Infinite or -Infinite. Based on trio code
163 * http://sourceforge.net/projects/ctrio/
164 *
165 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
166 */
167int
168xmlXPathIsInf(double val) {
169 return(trio_isinf(val));
170}
171
Daniel Veillard4432df22003-09-28 18:58:27 +0000172#endif /* SCHEMAS or XPATH */
173#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000174/**
175 * xmlXPathGetSign:
176 * @val: a double value
177 *
178 * Provides a portable function to detect the sign of a double
179 * Modified from trio code
180 * http://sourceforge.net/projects/ctrio/
181 *
182 * Returns 1 if the value is Negative, 0 if positive
183 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000184static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000185xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000186 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000187}
188
189
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000190/*
191 * TODO: when compatibility allows remove all "fake node libxslt" strings
192 * the test should just be name[0] = ' '
193 */
194/* #define DEBUG */
195/* #define DEBUG_STEP */
196/* #define DEBUG_STEP_NTH */
197/* #define DEBUG_EXPR */
198/* #define DEBUG_EVAL_COUNTS */
199
200static xmlNs xmlXPathXMLNamespaceStruct = {
201 NULL,
202 XML_NAMESPACE_DECL,
203 XML_XML_NAMESPACE,
204 BAD_CAST "xml",
205 NULL
206};
207static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
208#ifndef LIBXML_THREAD_ENABLED
209/*
210 * Optimizer is disabled only when threaded apps are detected while
211 * the library ain't compiled for thread safety.
212 */
213static int xmlXPathDisableOptimizer = 0;
214#endif
215
Owen Taylor3473f882001-02-23 17:55:21 +0000216/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000217 * *
218 * Error handling routines *
219 * *
220 ************************************************************************/
221
Daniel Veillard24505b02005-07-28 23:49:35 +0000222/**
223 * XP_ERRORNULL:
224 * @X: the error code
225 *
226 * Macro to raise an XPath error and return NULL.
227 */
228#define XP_ERRORNULL(X) \
229 { xmlXPathErr(ctxt, X); return(NULL); }
230
William M. Brack08171912003-12-29 02:52:11 +0000231/*
232 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
233 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000234static const char *xmlXPathErrorMessages[] = {
235 "Ok\n",
236 "Number encoding\n",
237 "Unfinished literal\n",
238 "Start of literal\n",
239 "Expected $ for variable reference\n",
240 "Undefined variable\n",
241 "Invalid predicate\n",
242 "Invalid expression\n",
243 "Missing closing curly brace\n",
244 "Unregistered function\n",
245 "Invalid operand\n",
246 "Invalid type\n",
247 "Invalid number of arguments\n",
248 "Invalid context size\n",
249 "Invalid context position\n",
250 "Memory allocation error\n",
251 "Syntax error\n",
252 "Resource error\n",
253 "Sub resource error\n",
254 "Undefined namespace prefix\n",
255 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000256 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000257 "Invalid or incomplete context\n",
258 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000259};
William M. Brackcd65bc92005-01-06 09:39:18 +0000260#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
261 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000262/**
263 * xmlXPathErrMemory:
264 * @ctxt: an XPath context
265 * @extra: extra informations
266 *
267 * Handle a redefinition of attribute error
268 */
269static void
270xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
271{
272 if (ctxt != NULL) {
273 if (extra) {
274 xmlChar buf[200];
275
276 xmlStrPrintf(buf, 200,
277 BAD_CAST "Memory allocation failed : %s\n",
278 extra);
279 ctxt->lastError.message = (char *) xmlStrdup(buf);
280 } else {
281 ctxt->lastError.message = (char *)
282 xmlStrdup(BAD_CAST "Memory allocation failed\n");
283 }
284 ctxt->lastError.domain = XML_FROM_XPATH;
285 ctxt->lastError.code = XML_ERR_NO_MEMORY;
286 if (ctxt->error != NULL)
287 ctxt->error(ctxt->userData, &ctxt->lastError);
288 } else {
289 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000290 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000291 NULL, NULL, XML_FROM_XPATH,
292 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
293 extra, NULL, NULL, 0, 0,
294 "Memory allocation failed : %s\n", extra);
295 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000296 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000297 NULL, NULL, XML_FROM_XPATH,
298 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
299 NULL, NULL, NULL, 0, 0,
300 "Memory allocation failed\n");
301 }
302}
303
304/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000305 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000306 * @ctxt: an XPath parser context
307 * @extra: extra informations
308 *
309 * Handle a redefinition of attribute error
310 */
311static void
312xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
313{
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 if (ctxt == NULL)
315 xmlXPathErrMemory(NULL, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000316 else {
317 ctxt->error = XPATH_MEMORY_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000318 xmlXPathErrMemory(ctxt->context, extra);
Daniel Veillard11ce4002006-03-10 00:36:23 +0000319 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000320}
321
322/**
323 * xmlXPathErr:
324 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000325 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000326 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000327 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000328 */
329void
330xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
331{
William M. Brackcd65bc92005-01-06 09:39:18 +0000332 if ((error < 0) || (error > MAXERRNO))
333 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000334 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000335 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000336 NULL, NULL, XML_FROM_XPATH,
337 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
338 XML_ERR_ERROR, NULL, 0,
339 NULL, NULL, NULL, 0, 0,
340 xmlXPathErrorMessages[error]);
341 return;
342 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000343 ctxt->error = error;
344 if (ctxt->context == NULL) {
345 __xmlRaiseError(NULL, NULL, NULL,
346 NULL, NULL, XML_FROM_XPATH,
347 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
348 XML_ERR_ERROR, NULL, 0,
349 (const char *) ctxt->base, NULL, NULL,
350 ctxt->cur - ctxt->base, 0,
351 xmlXPathErrorMessages[error]);
352 return;
353 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000354 ctxt->context->lastError.domain = XML_FROM_XPATH;
355 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
356 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000357 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000358 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
359 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
360 ctxt->context->lastError.node = ctxt->context->debugNode;
361 if (ctxt->context->error != NULL) {
362 ctxt->context->error(ctxt->context->userData,
363 &ctxt->context->lastError);
364 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000365 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000366 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
367 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
368 XML_ERR_ERROR, NULL, 0,
369 (const char *) ctxt->base, NULL, NULL,
370 ctxt->cur - ctxt->base, 0,
371 xmlXPathErrorMessages[error]);
372 }
373
374}
375
376/**
377 * xmlXPatherror:
378 * @ctxt: the XPath Parser context
379 * @file: the file name
380 * @line: the line number
381 * @no: the error number
382 *
383 * Formats an error message.
384 */
385void
386xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
387 int line ATTRIBUTE_UNUSED, int no) {
388 xmlXPathErr(ctxt, no);
389}
390
391
392/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000393 * *
394 * Parser Types *
395 * *
396 ************************************************************************/
397
398/*
399 * Types are private:
400 */
401
402typedef enum {
403 XPATH_OP_END=0,
404 XPATH_OP_AND,
405 XPATH_OP_OR,
406 XPATH_OP_EQUAL,
407 XPATH_OP_CMP,
408 XPATH_OP_PLUS,
409 XPATH_OP_MULT,
410 XPATH_OP_UNION,
411 XPATH_OP_ROOT,
412 XPATH_OP_NODE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000413 XPATH_OP_RESET, /* 10 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000414 XPATH_OP_COLLECT,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000415 XPATH_OP_VALUE, /* 12 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000416 XPATH_OP_VARIABLE,
417 XPATH_OP_FUNCTION,
418 XPATH_OP_ARG,
419 XPATH_OP_PREDICATE,
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +0000420 XPATH_OP_FILTER, /* 17 */
421 XPATH_OP_SORT /* 18 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000422#ifdef LIBXML_XPTR_ENABLED
423 ,XPATH_OP_RANGETO
424#endif
425} xmlXPathOp;
426
427typedef enum {
428 AXIS_ANCESTOR = 1,
429 AXIS_ANCESTOR_OR_SELF,
430 AXIS_ATTRIBUTE,
431 AXIS_CHILD,
432 AXIS_DESCENDANT,
433 AXIS_DESCENDANT_OR_SELF,
434 AXIS_FOLLOWING,
435 AXIS_FOLLOWING_SIBLING,
436 AXIS_NAMESPACE,
437 AXIS_PARENT,
438 AXIS_PRECEDING,
439 AXIS_PRECEDING_SIBLING,
440 AXIS_SELF
441} xmlXPathAxisVal;
442
443typedef enum {
444 NODE_TEST_NONE = 0,
445 NODE_TEST_TYPE = 1,
446 NODE_TEST_PI = 2,
447 NODE_TEST_ALL = 3,
448 NODE_TEST_NS = 4,
449 NODE_TEST_NAME = 5
450} xmlXPathTestVal;
451
452typedef enum {
453 NODE_TYPE_NODE = 0,
454 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
455 NODE_TYPE_TEXT = XML_TEXT_NODE,
456 NODE_TYPE_PI = XML_PI_NODE
457} xmlXPathTypeVal;
458
459
460typedef struct _xmlXPathStepOp xmlXPathStepOp;
461typedef xmlXPathStepOp *xmlXPathStepOpPtr;
462struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000463 xmlXPathOp op; /* The identifier of the operation */
464 int ch1; /* First child */
465 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000466 int value;
467 int value2;
468 int value3;
469 void *value4;
470 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000471 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000472 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000473};
474
475struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000476 int nbStep; /* Number of steps in this expression */
477 int maxStep; /* Maximum number of steps allocated */
478 xmlXPathStepOp *steps; /* ops for computation of this expression */
479 int last; /* index of last step in expression */
480 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000481 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000482#ifdef DEBUG_EVAL_COUNTS
483 int nb;
484 xmlChar *string;
485#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000486#ifdef XPATH_STREAMING
487 xmlPatternPtr stream;
488#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489};
490
491/************************************************************************
492 * *
493 * Parser Type functions *
494 * *
495 ************************************************************************/
496
497/**
498 * xmlXPathNewCompExpr:
499 *
500 * Create a new Xpath component
501 *
502 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
503 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000504static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000505xmlXPathNewCompExpr(void) {
506 xmlXPathCompExprPtr cur;
507
508 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
509 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000510 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000511 return(NULL);
512 }
513 memset(cur, 0, sizeof(xmlXPathCompExpr));
514 cur->maxStep = 10;
515 cur->nbStep = 0;
516 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
517 sizeof(xmlXPathStepOp));
518 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000519 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000520 xmlFree(cur);
521 return(NULL);
522 }
523 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
524 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000525#ifdef DEBUG_EVAL_COUNTS
526 cur->nb = 0;
527#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000528 return(cur);
529}
530
531/**
532 * xmlXPathFreeCompExpr:
533 * @comp: an XPATH comp
534 *
535 * Free up the memory allocated by @comp
536 */
537void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000538xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
539{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000540 xmlXPathStepOpPtr op;
541 int i;
542
543 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000544 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000545 if (comp->dict == NULL) {
546 for (i = 0; i < comp->nbStep; i++) {
547 op = &comp->steps[i];
548 if (op->value4 != NULL) {
549 if (op->op == XPATH_OP_VALUE)
550 xmlXPathFreeObject(op->value4);
551 else
552 xmlFree(op->value4);
553 }
554 if (op->value5 != NULL)
555 xmlFree(op->value5);
556 }
557 } else {
558 for (i = 0; i < comp->nbStep; i++) {
559 op = &comp->steps[i];
560 if (op->value4 != NULL) {
561 if (op->op == XPATH_OP_VALUE)
562 xmlXPathFreeObject(op->value4);
563 }
564 }
565 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000566 }
567 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000568 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000569 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000570#ifdef DEBUG_EVAL_COUNTS
571 if (comp->string != NULL) {
572 xmlFree(comp->string);
573 }
574#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000575#ifdef XPATH_STREAMING
576 if (comp->stream != NULL) {
577 xmlFreePatternList(comp->stream);
578 }
579#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000580 if (comp->expr != NULL) {
581 xmlFree(comp->expr);
582 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000583
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000584 xmlFree(comp);
585}
586
587/**
588 * xmlXPathCompExprAdd:
589 * @comp: the compiled expression
590 * @ch1: first child index
591 * @ch2: second child index
592 * @op: an op
593 * @value: the first int value
594 * @value2: the second int value
595 * @value3: the third int value
596 * @value4: the first string value
597 * @value5: the second string value
598 *
William M. Brack08171912003-12-29 02:52:11 +0000599 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000600 *
601 * Returns -1 in case of failure, the index otherwise
602 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000603static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000604xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
605 xmlXPathOp op, int value,
606 int value2, int value3, void *value4, void *value5) {
607 if (comp->nbStep >= comp->maxStep) {
608 xmlXPathStepOp *real;
609
610 comp->maxStep *= 2;
611 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
612 comp->maxStep * sizeof(xmlXPathStepOp));
613 if (real == NULL) {
614 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000615 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000616 return(-1);
617 }
618 comp->steps = real;
619 }
620 comp->last = comp->nbStep;
621 comp->steps[comp->nbStep].ch1 = ch1;
622 comp->steps[comp->nbStep].ch2 = ch2;
623 comp->steps[comp->nbStep].op = op;
624 comp->steps[comp->nbStep].value = value;
625 comp->steps[comp->nbStep].value2 = value2;
626 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000627 if ((comp->dict != NULL) &&
628 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
629 (op == XPATH_OP_COLLECT))) {
630 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000631 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000632 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000633 xmlFree(value4);
634 } else
635 comp->steps[comp->nbStep].value4 = NULL;
636 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000637 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000638 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000639 xmlFree(value5);
640 } else
641 comp->steps[comp->nbStep].value5 = NULL;
642 } else {
643 comp->steps[comp->nbStep].value4 = value4;
644 comp->steps[comp->nbStep].value5 = value5;
645 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000646 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000647 return(comp->nbStep++);
648}
649
Daniel Veillardf06307e2001-07-03 10:35:50 +0000650/**
651 * xmlXPathCompSwap:
652 * @comp: the compiled expression
653 * @op: operation index
654 *
655 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000656 */
657static void
658xmlXPathCompSwap(xmlXPathStepOpPtr op) {
659 int tmp;
660
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000661#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000662 /*
663 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000664 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000665 * application
666 */
667 if (xmlXPathDisableOptimizer)
668 return;
669#endif
670
Daniel Veillardf06307e2001-07-03 10:35:50 +0000671 tmp = op->ch1;
672 op->ch1 = op->ch2;
673 op->ch2 = tmp;
674}
675
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000676#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
677 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
678 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000679#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
680 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
681 (op), (val), (val2), (val3), (val4), (val5))
682
683#define PUSH_LEAVE_EXPR(op, val, val2) \
684xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
685
686#define PUSH_UNARY_EXPR(op, ch, val, val2) \
687xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
688
689#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000690xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
691 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000692
693/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000694 * *
695 * Debugging related functions *
696 * *
697 ************************************************************************/
698
Owen Taylor3473f882001-02-23 17:55:21 +0000699#define STRANGE \
700 xmlGenericError(xmlGenericErrorContext, \
701 "Internal error at %s:%d\n", \
702 __FILE__, __LINE__);
703
704#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000705static void
706xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000707 int i;
708 char shift[100];
709
710 for (i = 0;((i < depth) && (i < 25));i++)
711 shift[2 * i] = shift[2 * i + 1] = ' ';
712 shift[2 * i] = shift[2 * i + 1] = 0;
713 if (cur == NULL) {
714 fprintf(output, shift);
715 fprintf(output, "Node is NULL !\n");
716 return;
717
718 }
719
720 if ((cur->type == XML_DOCUMENT_NODE) ||
721 (cur->type == XML_HTML_DOCUMENT_NODE)) {
722 fprintf(output, shift);
723 fprintf(output, " /\n");
724 } else if (cur->type == XML_ATTRIBUTE_NODE)
725 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
726 else
727 xmlDebugDumpOneNode(output, cur, depth);
728}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000729static void
730xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000731 xmlNodePtr tmp;
732 int i;
733 char shift[100];
734
735 for (i = 0;((i < depth) && (i < 25));i++)
736 shift[2 * i] = shift[2 * i + 1] = ' ';
737 shift[2 * i] = shift[2 * i + 1] = 0;
738 if (cur == NULL) {
739 fprintf(output, shift);
740 fprintf(output, "Node is NULL !\n");
741 return;
742
743 }
744
745 while (cur != NULL) {
746 tmp = cur;
747 cur = cur->next;
748 xmlDebugDumpOneNode(output, tmp, depth);
749 }
750}
Owen Taylor3473f882001-02-23 17:55:21 +0000751
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000752static void
753xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000754 int i;
755 char shift[100];
756
757 for (i = 0;((i < depth) && (i < 25));i++)
758 shift[2 * i] = shift[2 * i + 1] = ' ';
759 shift[2 * i] = shift[2 * i + 1] = 0;
760
761 if (cur == NULL) {
762 fprintf(output, shift);
763 fprintf(output, "NodeSet is NULL !\n");
764 return;
765
766 }
767
Daniel Veillard911f49a2001-04-07 15:39:35 +0000768 if (cur != NULL) {
769 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
770 for (i = 0;i < cur->nodeNr;i++) {
771 fprintf(output, shift);
772 fprintf(output, "%d", i + 1);
773 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
774 }
Owen Taylor3473f882001-02-23 17:55:21 +0000775 }
776}
777
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000778static void
779xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000780 int i;
781 char shift[100];
782
783 for (i = 0;((i < depth) && (i < 25));i++)
784 shift[2 * i] = shift[2 * i + 1] = ' ';
785 shift[2 * i] = shift[2 * i + 1] = 0;
786
787 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
788 fprintf(output, shift);
789 fprintf(output, "Value Tree is NULL !\n");
790 return;
791
792 }
793
794 fprintf(output, shift);
795 fprintf(output, "%d", i + 1);
796 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
797}
Owen Taylor3473f882001-02-23 17:55:21 +0000798#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000799static void
800xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000801 int i;
802 char shift[100];
803
804 for (i = 0;((i < depth) && (i < 25));i++)
805 shift[2 * i] = shift[2 * i + 1] = ' ';
806 shift[2 * i] = shift[2 * i + 1] = 0;
807
808 if (cur == NULL) {
809 fprintf(output, shift);
810 fprintf(output, "LocationSet is NULL !\n");
811 return;
812
813 }
814
815 for (i = 0;i < cur->locNr;i++) {
816 fprintf(output, shift);
817 fprintf(output, "%d : ", i + 1);
818 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
819 }
820}
Daniel Veillard017b1082001-06-21 11:20:21 +0000821#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000822
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000823/**
824 * xmlXPathDebugDumpObject:
825 * @output: the FILE * to dump the output
826 * @cur: the object to inspect
827 * @depth: indentation level
828 *
829 * Dump the content of the object for debugging purposes
830 */
831void
832xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000833 int i;
834 char shift[100];
835
Daniel Veillarda82b1822004-11-08 16:24:57 +0000836 if (output == NULL) return;
837
Owen Taylor3473f882001-02-23 17:55:21 +0000838 for (i = 0;((i < depth) && (i < 25));i++)
839 shift[2 * i] = shift[2 * i + 1] = ' ';
840 shift[2 * i] = shift[2 * i + 1] = 0;
841
Kasimier T. Buchcik97258712006-01-05 12:30:43 +0000842
843 fprintf(output, shift);
Owen Taylor3473f882001-02-23 17:55:21 +0000844
845 if (cur == NULL) {
846 fprintf(output, "Object is empty (NULL)\n");
847 return;
848 }
849 switch(cur->type) {
850 case XPATH_UNDEFINED:
851 fprintf(output, "Object is uninitialized\n");
852 break;
853 case XPATH_NODESET:
854 fprintf(output, "Object is a Node Set :\n");
855 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
856 break;
857 case XPATH_XSLT_TREE:
858 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000859 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000860 break;
861 case XPATH_BOOLEAN:
862 fprintf(output, "Object is a Boolean : ");
863 if (cur->boolval) fprintf(output, "true\n");
864 else fprintf(output, "false\n");
865 break;
866 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000867 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000868 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000869 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000870 break;
871 case -1:
872 fprintf(output, "Object is a number : -Infinity\n");
873 break;
874 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000875 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000876 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000877 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
878 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000879 } else {
880 fprintf(output, "Object is a number : %0g\n", cur->floatval);
881 }
882 }
Owen Taylor3473f882001-02-23 17:55:21 +0000883 break;
884 case XPATH_STRING:
885 fprintf(output, "Object is a string : ");
886 xmlDebugDumpString(output, cur->stringval);
887 fprintf(output, "\n");
888 break;
889 case XPATH_POINT:
890 fprintf(output, "Object is a point : index %d in node", cur->index);
891 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
892 fprintf(output, "\n");
893 break;
894 case XPATH_RANGE:
895 if ((cur->user2 == NULL) ||
896 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
897 fprintf(output, "Object is a collapsed range :\n");
898 fprintf(output, shift);
899 if (cur->index >= 0)
900 fprintf(output, "index %d in ", cur->index);
901 fprintf(output, "node\n");
902 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
903 depth + 1);
904 } else {
905 fprintf(output, "Object is a range :\n");
906 fprintf(output, shift);
907 fprintf(output, "From ");
908 if (cur->index >= 0)
909 fprintf(output, "index %d in ", cur->index);
910 fprintf(output, "node\n");
911 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
912 depth + 1);
913 fprintf(output, shift);
914 fprintf(output, "To ");
915 if (cur->index2 >= 0)
916 fprintf(output, "index %d in ", cur->index2);
917 fprintf(output, "node\n");
918 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
919 depth + 1);
920 fprintf(output, "\n");
921 }
922 break;
923 case XPATH_LOCATIONSET:
924#if defined(LIBXML_XPTR_ENABLED)
925 fprintf(output, "Object is a Location Set:\n");
926 xmlXPathDebugDumpLocationSet(output,
927 (xmlLocationSetPtr) cur->user, depth);
928#endif
929 break;
930 case XPATH_USERS:
931 fprintf(output, "Object is user defined\n");
932 break;
933 }
934}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000935
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000936static void
937xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000938 xmlXPathStepOpPtr op, int depth) {
939 int i;
940 char shift[100];
941
942 for (i = 0;((i < depth) && (i < 25));i++)
943 shift[2 * i] = shift[2 * i + 1] = ' ';
944 shift[2 * i] = shift[2 * i + 1] = 0;
945
946 fprintf(output, shift);
947 if (op == NULL) {
948 fprintf(output, "Step is NULL\n");
949 return;
950 }
951 switch (op->op) {
952 case XPATH_OP_END:
953 fprintf(output, "END"); break;
954 case XPATH_OP_AND:
955 fprintf(output, "AND"); break;
956 case XPATH_OP_OR:
957 fprintf(output, "OR"); break;
958 case XPATH_OP_EQUAL:
959 if (op->value)
960 fprintf(output, "EQUAL =");
961 else
962 fprintf(output, "EQUAL !=");
963 break;
964 case XPATH_OP_CMP:
965 if (op->value)
966 fprintf(output, "CMP <");
967 else
968 fprintf(output, "CMP >");
969 if (!op->value2)
970 fprintf(output, "=");
971 break;
972 case XPATH_OP_PLUS:
973 if (op->value == 0)
974 fprintf(output, "PLUS -");
975 else if (op->value == 1)
976 fprintf(output, "PLUS +");
977 else if (op->value == 2)
978 fprintf(output, "PLUS unary -");
979 else if (op->value == 3)
980 fprintf(output, "PLUS unary - -");
981 break;
982 case XPATH_OP_MULT:
983 if (op->value == 0)
984 fprintf(output, "MULT *");
985 else if (op->value == 1)
986 fprintf(output, "MULT div");
987 else
988 fprintf(output, "MULT mod");
989 break;
990 case XPATH_OP_UNION:
991 fprintf(output, "UNION"); break;
992 case XPATH_OP_ROOT:
993 fprintf(output, "ROOT"); break;
994 case XPATH_OP_NODE:
995 fprintf(output, "NODE"); break;
996 case XPATH_OP_RESET:
997 fprintf(output, "RESET"); break;
998 case XPATH_OP_SORT:
999 fprintf(output, "SORT"); break;
1000 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +00001001 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1002 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1003 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001004 const xmlChar *prefix = op->value4;
1005 const xmlChar *name = op->value5;
1006
1007 fprintf(output, "COLLECT ");
1008 switch (axis) {
1009 case AXIS_ANCESTOR:
1010 fprintf(output, " 'ancestors' "); break;
1011 case AXIS_ANCESTOR_OR_SELF:
1012 fprintf(output, " 'ancestors-or-self' "); break;
1013 case AXIS_ATTRIBUTE:
1014 fprintf(output, " 'attributes' "); break;
1015 case AXIS_CHILD:
1016 fprintf(output, " 'child' "); break;
1017 case AXIS_DESCENDANT:
1018 fprintf(output, " 'descendant' "); break;
1019 case AXIS_DESCENDANT_OR_SELF:
1020 fprintf(output, " 'descendant-or-self' "); break;
1021 case AXIS_FOLLOWING:
1022 fprintf(output, " 'following' "); break;
1023 case AXIS_FOLLOWING_SIBLING:
1024 fprintf(output, " 'following-siblings' "); break;
1025 case AXIS_NAMESPACE:
1026 fprintf(output, " 'namespace' "); break;
1027 case AXIS_PARENT:
1028 fprintf(output, " 'parent' "); break;
1029 case AXIS_PRECEDING:
1030 fprintf(output, " 'preceding' "); break;
1031 case AXIS_PRECEDING_SIBLING:
1032 fprintf(output, " 'preceding-sibling' "); break;
1033 case AXIS_SELF:
1034 fprintf(output, " 'self' "); break;
1035 }
1036 switch (test) {
1037 case NODE_TEST_NONE:
1038 fprintf(output, "'none' "); break;
1039 case NODE_TEST_TYPE:
1040 fprintf(output, "'type' "); break;
1041 case NODE_TEST_PI:
1042 fprintf(output, "'PI' "); break;
1043 case NODE_TEST_ALL:
1044 fprintf(output, "'all' "); break;
1045 case NODE_TEST_NS:
1046 fprintf(output, "'namespace' "); break;
1047 case NODE_TEST_NAME:
1048 fprintf(output, "'name' "); break;
1049 }
1050 switch (type) {
1051 case NODE_TYPE_NODE:
1052 fprintf(output, "'node' "); break;
1053 case NODE_TYPE_COMMENT:
1054 fprintf(output, "'comment' "); break;
1055 case NODE_TYPE_TEXT:
1056 fprintf(output, "'text' "); break;
1057 case NODE_TYPE_PI:
1058 fprintf(output, "'PI' "); break;
1059 }
1060 if (prefix != NULL)
1061 fprintf(output, "%s:", prefix);
1062 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001063 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001064 break;
1065
1066 }
1067 case XPATH_OP_VALUE: {
1068 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1069
1070 fprintf(output, "ELEM ");
1071 xmlXPathDebugDumpObject(output, object, 0);
1072 goto finish;
1073 }
1074 case XPATH_OP_VARIABLE: {
1075 const xmlChar *prefix = op->value5;
1076 const xmlChar *name = op->value4;
1077
1078 if (prefix != NULL)
1079 fprintf(output, "VARIABLE %s:%s", prefix, name);
1080 else
1081 fprintf(output, "VARIABLE %s", name);
1082 break;
1083 }
1084 case XPATH_OP_FUNCTION: {
1085 int nbargs = op->value;
1086 const xmlChar *prefix = op->value5;
1087 const xmlChar *name = op->value4;
1088
1089 if (prefix != NULL)
1090 fprintf(output, "FUNCTION %s:%s(%d args)",
1091 prefix, name, nbargs);
1092 else
1093 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1094 break;
1095 }
1096 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1097 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001098 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001099#ifdef LIBXML_XPTR_ENABLED
1100 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1101#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001102 default:
1103 fprintf(output, "UNKNOWN %d\n", op->op); return;
1104 }
1105 fprintf(output, "\n");
1106finish:
1107 if (op->ch1 >= 0)
1108 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1109 if (op->ch2 >= 0)
1110 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1111}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001112
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001113/**
1114 * xmlXPathDebugDumpCompExpr:
1115 * @output: the FILE * for the output
1116 * @comp: the precompiled XPath expression
1117 * @depth: the indentation level.
1118 *
1119 * Dumps the tree of the compiled XPath expression.
1120 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001121void
1122xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1123 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001124 int i;
1125 char shift[100];
1126
Daniel Veillarda82b1822004-11-08 16:24:57 +00001127 if ((output == NULL) || (comp == NULL)) return;
1128
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001129 for (i = 0;((i < depth) && (i < 25));i++)
1130 shift[2 * i] = shift[2 * i + 1] = ' ';
1131 shift[2 * i] = shift[2 * i + 1] = 0;
1132
1133 fprintf(output, shift);
1134
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001135 fprintf(output, "Compiled Expression : %d elements\n",
1136 comp->nbStep);
1137 i = comp->last;
1138 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1139}
Daniel Veillard017b1082001-06-21 11:20:21 +00001140#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001141
1142/************************************************************************
1143 * *
1144 * Parser stacks related functions and macros *
1145 * *
1146 ************************************************************************/
1147
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001148/**
1149 * valuePop:
1150 * @ctxt: an XPath evaluation context
1151 *
1152 * Pops the top XPath object from the value stack
1153 *
1154 * Returns the XPath object just removed
1155 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001156xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00001157valuePop(xmlXPathParserContextPtr ctxt)
1158{
1159 xmlXPathObjectPtr ret;
1160
Daniel Veillarda82b1822004-11-08 16:24:57 +00001161 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00001162 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001163 ctxt->valueNr--;
1164 if (ctxt->valueNr > 0)
1165 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1166 else
1167 ctxt->value = NULL;
1168 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001169 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001170 return (ret);
1171}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001172/**
1173 * valuePush:
1174 * @ctxt: an XPath evaluation context
1175 * @value: the XPath object
1176 *
1177 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001178 *
1179 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001180 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001181int
Daniel Veillard1c732d22002-11-30 11:22:59 +00001182valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1183{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001184 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001185 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001186 xmlXPathObjectPtr *tmp;
1187
1188 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1189 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001190 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001191 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001192 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1193 return (0);
1194 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001195 ctxt->valueMax *= 2;
1196 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001197 }
1198 ctxt->valueTab[ctxt->valueNr] = value;
1199 ctxt->value = value;
1200 return (ctxt->valueNr++);
1201}
Owen Taylor3473f882001-02-23 17:55:21 +00001202
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001203/**
1204 * xmlXPathPopBoolean:
1205 * @ctxt: an XPath parser context
1206 *
1207 * Pops a boolean from the stack, handling conversion if needed.
1208 * Check error with #xmlXPathCheckError.
1209 *
1210 * Returns the boolean
1211 */
1212int
1213xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1214 xmlXPathObjectPtr obj;
1215 int ret;
1216
1217 obj = valuePop(ctxt);
1218 if (obj == NULL) {
1219 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1220 return(0);
1221 }
William M. Brack08171912003-12-29 02:52:11 +00001222 if (obj->type != XPATH_BOOLEAN)
1223 ret = xmlXPathCastToBoolean(obj);
1224 else
1225 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001226 xmlXPathFreeObject(obj);
1227 return(ret);
1228}
1229
1230/**
1231 * xmlXPathPopNumber:
1232 * @ctxt: an XPath parser context
1233 *
1234 * Pops a number from the stack, handling conversion if needed.
1235 * Check error with #xmlXPathCheckError.
1236 *
1237 * Returns the number
1238 */
1239double
1240xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1241 xmlXPathObjectPtr obj;
1242 double ret;
1243
1244 obj = valuePop(ctxt);
1245 if (obj == NULL) {
1246 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1247 return(0);
1248 }
William M. Brack08171912003-12-29 02:52:11 +00001249 if (obj->type != XPATH_NUMBER)
1250 ret = xmlXPathCastToNumber(obj);
1251 else
1252 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001253 xmlXPathFreeObject(obj);
1254 return(ret);
1255}
1256
1257/**
1258 * xmlXPathPopString:
1259 * @ctxt: an XPath parser context
1260 *
1261 * Pops a string from the stack, handling conversion if needed.
1262 * Check error with #xmlXPathCheckError.
1263 *
1264 * Returns the string
1265 */
1266xmlChar *
1267xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1268 xmlXPathObjectPtr obj;
1269 xmlChar * ret;
1270
1271 obj = valuePop(ctxt);
1272 if (obj == NULL) {
1273 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1274 return(NULL);
1275 }
William M. Brack08171912003-12-29 02:52:11 +00001276 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001277 /* TODO: needs refactoring somewhere else */
1278 if (obj->stringval == ret)
1279 obj->stringval = NULL;
1280 xmlXPathFreeObject(obj);
1281 return(ret);
1282}
1283
1284/**
1285 * xmlXPathPopNodeSet:
1286 * @ctxt: an XPath parser context
1287 *
1288 * Pops a node-set from the stack, handling conversion if needed.
1289 * Check error with #xmlXPathCheckError.
1290 *
1291 * Returns the node-set
1292 */
1293xmlNodeSetPtr
1294xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1295 xmlXPathObjectPtr obj;
1296 xmlNodeSetPtr ret;
1297
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001298 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001299 if (ctxt->value == NULL) {
1300 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1301 return(NULL);
1302 }
1303 if (!xmlXPathStackIsNodeSet(ctxt)) {
1304 xmlXPathSetTypeError(ctxt);
1305 return(NULL);
1306 }
1307 obj = valuePop(ctxt);
1308 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001309#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001310 /* to fix memory leak of not clearing obj->user */
1311 if (obj->boolval && obj->user != NULL)
1312 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001313#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001314 xmlXPathFreeNodeSetList(obj);
1315 return(ret);
1316}
1317
1318/**
1319 * xmlXPathPopExternal:
1320 * @ctxt: an XPath parser context
1321 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001322 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001323 * Check error with #xmlXPathCheckError.
1324 *
1325 * Returns the object
1326 */
1327void *
1328xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1329 xmlXPathObjectPtr obj;
1330 void * ret;
1331
Daniel Veillarda82b1822004-11-08 16:24:57 +00001332 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001333 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1334 return(NULL);
1335 }
1336 if (ctxt->value->type != XPATH_USERS) {
1337 xmlXPathSetTypeError(ctxt);
1338 return(NULL);
1339 }
1340 obj = valuePop(ctxt);
1341 ret = obj->user;
1342 xmlXPathFreeObject(obj);
1343 return(ret);
1344}
1345
Owen Taylor3473f882001-02-23 17:55:21 +00001346/*
1347 * Macros for accessing the content. Those should be used only by the parser,
1348 * and not exported.
1349 *
1350 * Dirty macros, i.e. one need to make assumption on the context to use them
1351 *
1352 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1353 * CUR returns the current xmlChar value, i.e. a 8 bit value
1354 * in ISO-Latin or UTF-8.
1355 * This should be used internally by the parser
1356 * only to compare to ASCII values otherwise it would break when
1357 * running with UTF-8 encoding.
1358 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1359 * to compare on ASCII based substring.
1360 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1361 * strings within the parser.
1362 * CURRENT Returns the current char value, with the full decoding of
1363 * UTF-8 if we are using this mode. It returns an int.
1364 * NEXT Skip to the next character, this does the proper decoding
1365 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1366 * It returns the pointer to the current xmlChar.
1367 */
1368
1369#define CUR (*ctxt->cur)
1370#define SKIP(val) ctxt->cur += (val)
1371#define NXT(val) ctxt->cur[(val)]
1372#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001373#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1374
1375#define COPY_BUF(l,b,i,v) \
1376 if (l == 1) b[i++] = (xmlChar) v; \
1377 else i += xmlCopyChar(l,&b[i],v)
1378
1379#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001380
1381#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001382 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001383
1384#define CURRENT (*ctxt->cur)
1385#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1386
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001387
1388#ifndef DBL_DIG
1389#define DBL_DIG 16
1390#endif
1391#ifndef DBL_EPSILON
1392#define DBL_EPSILON 1E-9
1393#endif
1394
1395#define UPPER_DOUBLE 1E9
1396#define LOWER_DOUBLE 1E-5
1397
1398#define INTEGER_DIGITS DBL_DIG
1399#define FRACTION_DIGITS (DBL_DIG + 1)
1400#define EXPONENT_DIGITS (3 + 2)
1401
1402/**
1403 * xmlXPathFormatNumber:
1404 * @number: number to format
1405 * @buffer: output buffer
1406 * @buffersize: size of output buffer
1407 *
1408 * Convert the number into a string representation.
1409 */
1410static void
1411xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1412{
Daniel Veillardcda96922001-08-21 10:56:31 +00001413 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001414 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001415 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001416 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001417 break;
1418 case -1:
1419 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001420 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001421 break;
1422 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001423 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001424 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001425 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001426 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001427 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001428 } else if (number == ((int) number)) {
1429 char work[30];
1430 char *ptr, *cur;
Daniel Veillardb3d14912005-09-04 20:47:39 +00001431 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001432
1433 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001434 if (value == 0) {
1435 *ptr++ = '0';
1436 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00001437 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001438 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00001439 while ((*cur) && (ptr - buffer < buffersize)) {
1440 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001441 }
1442 }
1443 if (ptr - buffer < buffersize) {
1444 *ptr = 0;
1445 } else if (buffersize > 0) {
1446 ptr--;
1447 *ptr = 0;
1448 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001449 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001450 /* 3 is sign, decimal point, and terminating zero */
1451 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1452 int integer_place, fraction_place;
1453 char *ptr;
1454 char *after_fraction;
1455 double absolute_value;
1456 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001457
Bjorn Reese70a9da52001-04-21 16:57:29 +00001458 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001459
Bjorn Reese70a9da52001-04-21 16:57:29 +00001460 /*
1461 * First choose format - scientific or regular floating point.
1462 * In either case, result is in work, and after_fraction points
1463 * just past the fractional part.
1464 */
1465 if ( ((absolute_value > UPPER_DOUBLE) ||
1466 (absolute_value < LOWER_DOUBLE)) &&
1467 (absolute_value != 0.0) ) {
1468 /* Use scientific notation */
1469 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1470 fraction_place = DBL_DIG - 1;
Daniel Veillard11ce4002006-03-10 00:36:23 +00001471 size = snprintf(work, sizeof(work),"%*.*e",
Bjorn Reese70a9da52001-04-21 16:57:29 +00001472 integer_place, fraction_place, number);
Daniel Veillard11ce4002006-03-10 00:36:23 +00001473 while ((size > 0) && (work[size] != 'e')) size--;
1474 after_fraction = work + size;
1475
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001476 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001477 else {
1478 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001479 if (absolute_value > 0.0)
1480 integer_place = 1 + (int)log10(absolute_value);
1481 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001482 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001483 fraction_place = (integer_place > 0)
1484 ? DBL_DIG - integer_place
1485 : DBL_DIG;
1486 size = snprintf(work, sizeof(work), "%0.*f",
1487 fraction_place, number);
1488 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001489 }
1490
Bjorn Reese70a9da52001-04-21 16:57:29 +00001491 /* Remove fractional trailing zeroes */
1492 ptr = after_fraction;
1493 while (*(--ptr) == '0')
1494 ;
1495 if (*ptr != '.')
1496 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001497 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001498
1499 /* Finally copy result back to caller */
1500 size = strlen(work) + 1;
1501 if (size > buffersize) {
1502 work[buffersize - 1] = 0;
1503 size = buffersize;
1504 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001505 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001506 }
1507 break;
1508 }
1509}
1510
Owen Taylor3473f882001-02-23 17:55:21 +00001511
1512/************************************************************************
1513 * *
1514 * Routines to handle NodeSets *
1515 * *
1516 ************************************************************************/
1517
1518/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001519 * xmlXPathOrderDocElems:
1520 * @doc: an input document
1521 *
1522 * Call this routine to speed up XPath computation on static documents.
1523 * This stamps all the element nodes with the document order
1524 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001525 * field, the value stored is actually - the node number (starting at -1)
1526 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001527 *
William M. Brack08171912003-12-29 02:52:11 +00001528 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001529 * of error.
1530 */
1531long
1532xmlXPathOrderDocElems(xmlDocPtr doc) {
1533 long count = 0;
1534 xmlNodePtr cur;
1535
1536 if (doc == NULL)
1537 return(-1);
1538 cur = doc->children;
1539 while (cur != NULL) {
1540 if (cur->type == XML_ELEMENT_NODE) {
1541 cur->content = (void *) (-(++count));
1542 if (cur->children != NULL) {
1543 cur = cur->children;
1544 continue;
1545 }
1546 }
1547 if (cur->next != NULL) {
1548 cur = cur->next;
1549 continue;
1550 }
1551 do {
1552 cur = cur->parent;
1553 if (cur == NULL)
1554 break;
1555 if (cur == (xmlNodePtr) doc) {
1556 cur = NULL;
1557 break;
1558 }
1559 if (cur->next != NULL) {
1560 cur = cur->next;
1561 break;
1562 }
1563 } while (cur != NULL);
1564 }
1565 return(count);
1566}
1567
1568/**
Owen Taylor3473f882001-02-23 17:55:21 +00001569 * xmlXPathCmpNodes:
1570 * @node1: the first node
1571 * @node2: the second node
1572 *
1573 * Compare two nodes w.r.t document order
1574 *
1575 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001576 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001577 */
1578int
1579xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1580 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001581 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001582 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001583 xmlNodePtr cur, root;
1584
1585 if ((node1 == NULL) || (node2 == NULL))
1586 return(-2);
1587 /*
1588 * a couple of optimizations which will avoid computations in most cases
1589 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001590 if (node1->type == XML_ATTRIBUTE_NODE) {
1591 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001592 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001593 node1 = node1->parent;
1594 }
1595 if (node2->type == XML_ATTRIBUTE_NODE) {
1596 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001597 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001598 node2 = node2->parent;
1599 }
1600 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001601 if (attr1 == attr2) {
1602 /* not required, but we keep attributes in order */
1603 if (attr1 != 0) {
1604 cur = attrNode2->prev;
1605 while (cur != NULL) {
1606 if (cur == attrNode1)
1607 return (1);
1608 cur = cur->prev;
1609 }
1610 return (-1);
1611 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001612 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001613 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001614 if (attr2 == 1)
1615 return(1);
1616 return(-1);
1617 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001618 if ((node1->type == XML_NAMESPACE_DECL) ||
1619 (node2->type == XML_NAMESPACE_DECL))
1620 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001621 if (node1 == node2->prev)
1622 return(1);
1623 if (node1 == node2->next)
1624 return(-1);
1625
1626 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001627 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001628 */
1629 if ((node1->type == XML_ELEMENT_NODE) &&
1630 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001631 (0 > (long) node1->content) &&
1632 (0 > (long) node2->content) &&
1633 (node1->doc == node2->doc)) {
1634 long l1, l2;
1635
1636 l1 = -((long) node1->content);
1637 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001638 if (l1 < l2)
1639 return(1);
1640 if (l1 > l2)
1641 return(-1);
1642 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001643
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001644 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001645 * compute depth to root
1646 */
1647 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1648 if (cur == node1)
1649 return(1);
1650 depth2++;
1651 }
1652 root = cur;
1653 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1654 if (cur == node2)
1655 return(-1);
1656 depth1++;
1657 }
1658 /*
1659 * Distinct document (or distinct entities :-( ) case.
1660 */
1661 if (root != cur) {
1662 return(-2);
1663 }
1664 /*
1665 * get the nearest common ancestor.
1666 */
1667 while (depth1 > depth2) {
1668 depth1--;
1669 node1 = node1->parent;
1670 }
1671 while (depth2 > depth1) {
1672 depth2--;
1673 node2 = node2->parent;
1674 }
1675 while (node1->parent != node2->parent) {
1676 node1 = node1->parent;
1677 node2 = node2->parent;
1678 /* should not happen but just in case ... */
1679 if ((node1 == NULL) || (node2 == NULL))
1680 return(-2);
1681 }
1682 /*
1683 * Find who's first.
1684 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001685 if (node1 == node2->prev)
1686 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001687 if (node1 == node2->next)
1688 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001689 /*
1690 * Speedup using document order if availble.
1691 */
1692 if ((node1->type == XML_ELEMENT_NODE) &&
1693 (node2->type == XML_ELEMENT_NODE) &&
1694 (0 > (long) node1->content) &&
1695 (0 > (long) node2->content) &&
1696 (node1->doc == node2->doc)) {
1697 long l1, l2;
1698
1699 l1 = -((long) node1->content);
1700 l2 = -((long) node2->content);
1701 if (l1 < l2)
1702 return(1);
1703 if (l1 > l2)
1704 return(-1);
1705 }
1706
Owen Taylor3473f882001-02-23 17:55:21 +00001707 for (cur = node1->next;cur != NULL;cur = cur->next)
1708 if (cur == node2)
1709 return(1);
1710 return(-1); /* assume there is no sibling list corruption */
1711}
1712
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00001713#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001714/**
1715 * xmlXPathCmpNodesExt:
1716 * @node1: the first node
1717 * @node2: the second node
1718 *
1719 * Compare two nodes w.r.t document order.
1720 * This one is optimized for handling of non-element nodes.
1721 *
1722 * Returns -2 in case of error 1 if first point < second point, 0 if
1723 * it's the same node, -1 otherwise
1724 */
1725static int
1726xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
1727 int depth1, depth2;
1728 int misc = 0, precedence1 = 0, precedence2 = 0;
1729 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
1730 xmlNodePtr cur, root;
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001731 long l1, l2;
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001732
1733 if ((node1 == NULL) || (node2 == NULL))
1734 return(-2);
1735
1736 if (node1 == node2)
1737 return(0);
1738
1739 /*
1740 * a couple of optimizations which will avoid computations in most cases
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001741 */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001742 switch (node1->type) {
1743 case XML_ELEMENT_NODE:
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001744 if (node2->type == XML_ELEMENT_NODE) {
1745 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
1746 (0 > (long) node2->content) &&
1747 (node1->doc == node2->doc))
1748 {
1749 l1 = -((long) node1->content);
1750 l2 = -((long) node2->content);
1751 if (l1 < l2)
1752 return(1);
1753 if (l1 > l2)
1754 return(-1);
1755 } else
1756 goto turtle_comparison;
1757 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001758 break;
1759 case XML_ATTRIBUTE_NODE:
1760 precedence1 = 1; /* element is owner */
1761 miscNode1 = node1;
1762 node1 = node1->parent;
1763 misc = 1;
1764 break;
1765 case XML_TEXT_NODE:
1766 case XML_CDATA_SECTION_NODE:
1767 case XML_COMMENT_NODE:
1768 case XML_PI_NODE: {
1769 miscNode1 = node1;
1770 /*
1771 * Find nearest element node.
1772 */
1773 if (node1->prev != NULL) {
1774 do {
1775 node1 = node1->prev;
1776 if (node1->type == XML_ELEMENT_NODE) {
1777 precedence1 = 3; /* element in prev-sibl axis */
1778 break;
1779 }
1780 if (node1->prev == NULL) {
1781 precedence1 = 2; /* element is parent */
1782 /*
1783 * URGENT TODO: Are there any cases, where the
1784 * parent of such a node is not an element node?
1785 */
1786 node1 = node1->parent;
1787 break;
1788 }
1789 } while (1);
1790 } else {
1791 precedence1 = 2; /* element is parent */
1792 node1 = node1->parent;
1793 }
1794 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
1795 /*
1796 * Fallback for whatever case.
1797 */
1798 node1 = miscNode1;
1799 precedence1 = 0;
1800 } else
1801 misc = 1;
1802 }
1803 break;
1804 case XML_NAMESPACE_DECL:
1805 /*
1806 * TODO: why do we return 1 for namespace nodes?
1807 */
1808 return(1);
1809 default:
1810 break;
1811 }
1812 switch (node2->type) {
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001813 case XML_ELEMENT_NODE:
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001814 break;
1815 case XML_ATTRIBUTE_NODE:
1816 precedence2 = 1; /* element is owner */
1817 miscNode2 = node2;
1818 node2 = node2->parent;
1819 misc = 1;
1820 break;
1821 case XML_TEXT_NODE:
1822 case XML_CDATA_SECTION_NODE:
1823 case XML_COMMENT_NODE:
1824 case XML_PI_NODE: {
1825 miscNode2 = node2;
1826 if (node2->prev != NULL) {
1827 do {
1828 node2 = node2->prev;
1829 if (node2->type == XML_ELEMENT_NODE) {
1830 precedence2 = 3; /* element in prev-sibl axis */
1831 break;
1832 }
1833 if (node2->prev == NULL) {
1834 precedence2 = 2; /* element is parent */
1835 node2 = node2->parent;
1836 break;
1837 }
1838 } while (1);
1839 } else {
1840 precedence2 = 2; /* element is parent */
1841 node2 = node2->parent;
1842 }
1843 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
1844 (0 <= (long) node1->content))
1845 {
1846 node2 = miscNode2;
1847 precedence2 = 0;
1848 } else
1849 misc = 1;
1850 }
1851 break;
1852 case XML_NAMESPACE_DECL:
1853 return(1);
1854 default:
1855 break;
1856 }
1857 if (misc) {
1858 if (node1 == node2) {
1859 if (precedence1 == precedence2) {
1860 /*
1861 * The ugly case; but normally there aren't many
1862 * adjacent non-element nodes around.
1863 */
1864 cur = miscNode2->prev;
1865 while (cur != NULL) {
1866 if (cur == miscNode1)
1867 return(1);
1868 if (cur->type == XML_ELEMENT_NODE)
1869 return(-1);
1870 cur = cur->prev;
1871 }
1872 return (-1);
1873 } else {
1874 /*
1875 * Evaluate based on higher precedence wrt to the element.
1876 * TODO: This assumes attributes are sorted before content.
1877 * Is this 100% correct?
1878 */
1879 if (precedence1 < precedence2)
1880 return(1);
1881 else
1882 return(-1);
1883 }
1884 }
1885 /*
1886 * Special case: One of the helper-elements is contained by the other.
1887 * <foo>
1888 * <node2>
1889 * <node1>Text-1(precedence1 == 2)</node1>
1890 * </node2>
1891 * Text-6(precedence2 == 3)
1892 * </foo>
1893 */
1894 if ((precedence2 == 3) && (precedence1 > 1)) {
1895 cur = node1->parent;
1896 while (cur) {
1897 if (cur == node2)
1898 return(1);
1899 cur = cur->parent;
1900 }
1901 }
1902 if ((precedence1 == 3) && (precedence2 > 1)) {
1903 cur = node2->parent;
1904 while (cur) {
1905 if (cur == node1)
1906 return(-1);
1907 cur = cur->parent;
1908 }
1909 }
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001910 }
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001911
1912 /*
1913 * Speedup using document order if availble.
1914 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001915 if ((node1->type == XML_ELEMENT_NODE) &&
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001916 (node2->type == XML_ELEMENT_NODE) &&
1917 (0 > (long) node1->content) &&
1918 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001919 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001920
1921 l1 = -((long) node1->content);
1922 l2 = -((long) node2->content);
1923 if (l1 < l2)
1924 return(1);
1925 if (l1 > l2)
1926 return(-1);
1927 }
1928
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001929turtle_comparison:
1930
1931 if (node1 == node2->prev)
1932 return(1);
1933 if (node1 == node2->next)
1934 return(-1);
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001935 /*
1936 * compute depth to root
1937 */
1938 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1939 if (cur == node1)
1940 return(1);
1941 depth2++;
1942 }
1943 root = cur;
1944 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1945 if (cur == node2)
1946 return(-1);
1947 depth1++;
1948 }
1949 /*
1950 * Distinct document (or distinct entities :-( ) case.
1951 */
1952 if (root != cur) {
1953 return(-2);
1954 }
1955 /*
1956 * get the nearest common ancestor.
1957 */
1958 while (depth1 > depth2) {
1959 depth1--;
1960 node1 = node1->parent;
1961 }
1962 while (depth2 > depth1) {
1963 depth2--;
1964 node2 = node2->parent;
1965 }
1966 while (node1->parent != node2->parent) {
1967 node1 = node1->parent;
1968 node2 = node2->parent;
1969 /* should not happen but just in case ... */
1970 if ((node1 == NULL) || (node2 == NULL))
1971 return(-2);
1972 }
1973 /*
1974 * Find who's first.
1975 */
1976 if (node1 == node2->prev)
1977 return(1);
1978 if (node1 == node2->next)
1979 return(-1);
1980 /*
1981 * Speedup using document order if availble.
1982 */
1983 if ((node1->type == XML_ELEMENT_NODE) &&
1984 (node2->type == XML_ELEMENT_NODE) &&
1985 (0 > (long) node1->content) &&
1986 (0 > (long) node2->content) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00001987 (node1->doc == node2->doc)) {
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00001988
1989 l1 = -((long) node1->content);
1990 l2 = -((long) node2->content);
1991 if (l1 < l2)
1992 return(1);
1993 if (l1 > l2)
1994 return(-1);
1995 }
1996
1997 for (cur = node1->next;cur != NULL;cur = cur->next)
1998 if (cur == node2)
1999 return(1);
2000 return(-1); /* assume there is no sibling list corruption */
2001}
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002002#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002003
Owen Taylor3473f882001-02-23 17:55:21 +00002004/**
2005 * xmlXPathNodeSetSort:
2006 * @set: the node set
2007 *
2008 * Sort the node set in document order
2009 */
2010void
2011xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002012 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00002013 xmlNodePtr tmp;
2014
2015 if (set == NULL)
2016 return;
2017
2018 /* Use Shell's sort to sort the node-set */
2019 len = set->nodeNr;
2020 for (incr = len / 2; incr > 0; incr /= 2) {
2021 for (i = incr; i < len; i++) {
2022 j = i - incr;
2023 while (j >= 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002024#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002025 if (xmlXPathCmpNodesExt(set->nodeTab[j],
2026 set->nodeTab[j + incr]) == -1)
2027#else
Bjorn Reesee1dc0112001-03-03 12:09:03 +00002028 if (xmlXPathCmpNodes(set->nodeTab[j],
Kasimier T. Buchcik2bdabbd2006-05-19 11:26:15 +00002029 set->nodeTab[j + incr]) == -1)
2030#endif
2031 {
Owen Taylor3473f882001-02-23 17:55:21 +00002032 tmp = set->nodeTab[j];
2033 set->nodeTab[j] = set->nodeTab[j + incr];
2034 set->nodeTab[j + incr] = tmp;
2035 j -= incr;
2036 } else
2037 break;
2038 }
2039 }
2040 }
2041}
2042
2043#define XML_NODESET_DEFAULT 10
2044/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002045 * xmlXPathNodeSetDupNs:
2046 * @node: the parent node of the namespace XPath node
2047 * @ns: the libxml namespace declaration node.
2048 *
2049 * Namespace node in libxml don't match the XPath semantic. In a node set
2050 * the namespace nodes are duplicated and the next pointer is set to the
2051 * parent node in the XPath semantic.
2052 *
2053 * Returns the newly created object.
2054 */
2055static xmlNodePtr
2056xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2057 xmlNsPtr cur;
2058
2059 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2060 return(NULL);
2061 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2062 return((xmlNodePtr) ns);
2063
2064 /*
2065 * Allocate a new Namespace and fill the fields.
2066 */
2067 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2068 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002069 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002070 return(NULL);
2071 }
2072 memset(cur, 0, sizeof(xmlNs));
2073 cur->type = XML_NAMESPACE_DECL;
2074 if (ns->href != NULL)
2075 cur->href = xmlStrdup(ns->href);
2076 if (ns->prefix != NULL)
2077 cur->prefix = xmlStrdup(ns->prefix);
2078 cur->next = (xmlNsPtr) node;
2079 return((xmlNodePtr) cur);
2080}
2081
2082/**
2083 * xmlXPathNodeSetFreeNs:
2084 * @ns: the XPath namespace node found in a nodeset.
2085 *
William M. Brack08171912003-12-29 02:52:11 +00002086 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002087 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00002088 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002089 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00002090void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002091xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2092 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2093 return;
2094
2095 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2096 if (ns->href != NULL)
2097 xmlFree((xmlChar *)ns->href);
2098 if (ns->prefix != NULL)
2099 xmlFree((xmlChar *)ns->prefix);
2100 xmlFree(ns);
2101 }
2102}
2103
2104/**
Owen Taylor3473f882001-02-23 17:55:21 +00002105 * xmlXPathNodeSetCreate:
2106 * @val: an initial xmlNodePtr, or NULL
2107 *
2108 * Create a new xmlNodeSetPtr of type double and of value @val
2109 *
2110 * Returns the newly created object.
2111 */
2112xmlNodeSetPtr
2113xmlXPathNodeSetCreate(xmlNodePtr val) {
2114 xmlNodeSetPtr ret;
2115
2116 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2117 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002118 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002119 return(NULL);
2120 }
2121 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
2122 if (val != NULL) {
2123 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2124 sizeof(xmlNodePtr));
2125 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002126 xmlXPathErrMemory(NULL, "creating nodeset\n");
2127 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002128 return(NULL);
2129 }
2130 memset(ret->nodeTab, 0 ,
2131 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2132 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002133 if (val->type == XML_NAMESPACE_DECL) {
2134 xmlNsPtr ns = (xmlNsPtr) val;
2135
2136 ret->nodeTab[ret->nodeNr++] =
2137 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2138 } else
2139 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002140 }
2141 return(ret);
2142}
2143
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00002144#if 0 /* enable if needed */
Owen Taylor3473f882001-02-23 17:55:21 +00002145/**
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002146 * xmlXPathNodeSetCreateSize:
2147 * @val: an initial xmlNodePtr, or NULL
2148 * @size: the initial size of the node-sets
2149 *
2150 * Create a new xmlNodeSetPtr of type double and of value @val
2151 *
2152 * Returns the newly created object.
2153 */
2154static xmlNodeSetPtr
2155xmlXPathNodeSetCreateSize(int size)
2156{
2157 xmlNodeSetPtr ret;
2158
2159 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2160 if (ret == NULL) {
2161 xmlXPathErrMemory(NULL, "creating nodeset\n");
2162 return(NULL);
2163 }
2164 memset(ret, 0, (size_t) sizeof(xmlNodeSet));
2165 if (size > 0) {
2166 if (size < XML_NODESET_DEFAULT)
2167 size = XML_NODESET_DEFAULT;
2168 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
2169 if (ret->nodeTab == NULL) {
2170 xmlXPathErrMemory(NULL, "creating nodeset\n");
2171 xmlFree(ret);
2172 return(NULL);
2173 }
2174 memset(ret->nodeTab, 0, size * (size_t) sizeof(xmlNodePtr));
2175 ret->nodeMax = size;
2176 }
2177 return(ret);
2178}
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00002179#endif
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002180
2181/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002182 * xmlXPathNodeSetContains:
2183 * @cur: the node-set
2184 * @val: the node
2185 *
2186 * checks whether @cur contains @val
2187 *
2188 * Returns true (1) if @cur contains @val, false (0) otherwise
2189 */
2190int
2191xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2192 int i;
2193
Daniel Veillarda82b1822004-11-08 16:24:57 +00002194 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002195 if (val->type == XML_NAMESPACE_DECL) {
2196 for (i = 0; i < cur->nodeNr; i++) {
2197 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2198 xmlNsPtr ns1, ns2;
2199
2200 ns1 = (xmlNsPtr) val;
2201 ns2 = (xmlNsPtr) cur->nodeTab[i];
2202 if (ns1 == ns2)
2203 return(1);
2204 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2205 (xmlStrEqual(ns1->prefix, ns2->prefix)))
2206 return(1);
2207 }
2208 }
2209 } else {
2210 for (i = 0; i < cur->nodeNr; i++) {
2211 if (cur->nodeTab[i] == val)
2212 return(1);
2213 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002214 }
2215 return(0);
2216}
2217
2218/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002219 * xmlXPathNodeSetAddNs:
2220 * @cur: the initial node set
2221 * @node: the hosting node
2222 * @ns: a the namespace node
2223 *
2224 * add a new namespace node to an existing NodeSet
2225 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00002226void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002227xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2228 int i;
2229
Daniel Veillarda82b1822004-11-08 16:24:57 +00002230
2231 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2232 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002233 (node->type != XML_ELEMENT_NODE))
2234 return;
2235
William M. Brack08171912003-12-29 02:52:11 +00002236 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002237 /*
William M. Brack08171912003-12-29 02:52:11 +00002238 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002239 */
2240 for (i = 0;i < cur->nodeNr;i++) {
2241 if ((cur->nodeTab[i] != NULL) &&
2242 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00002243 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002244 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2245 return;
2246 }
2247
2248 /*
2249 * grow the nodeTab if needed
2250 */
2251 if (cur->nodeMax == 0) {
2252 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2253 sizeof(xmlNodePtr));
2254 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002255 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002256 return;
2257 }
2258 memset(cur->nodeTab, 0 ,
2259 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2260 cur->nodeMax = XML_NODESET_DEFAULT;
2261 } else if (cur->nodeNr == cur->nodeMax) {
2262 xmlNodePtr *temp;
2263
2264 cur->nodeMax *= 2;
2265 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2266 sizeof(xmlNodePtr));
2267 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002268 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002269 return;
2270 }
2271 cur->nodeTab = temp;
2272 }
2273 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
2274}
2275
2276/**
Owen Taylor3473f882001-02-23 17:55:21 +00002277 * xmlXPathNodeSetAdd:
2278 * @cur: the initial node set
2279 * @val: a new xmlNodePtr
2280 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002281 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00002282 */
2283void
2284xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2285 int i;
2286
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 /*
William M. Brack08171912003-12-29 02:52:11 +00002296 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00002297 */
2298 for (i = 0;i < cur->nodeNr;i++)
2299 if (cur->nodeTab[i] == val) return;
2300
2301 /*
2302 * grow the nodeTab if needed
2303 */
2304 if (cur->nodeMax == 0) {
2305 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2306 sizeof(xmlNodePtr));
2307 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002308 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002309 return;
2310 }
2311 memset(cur->nodeTab, 0 ,
2312 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2313 cur->nodeMax = XML_NODESET_DEFAULT;
2314 } else if (cur->nodeNr == cur->nodeMax) {
2315 xmlNodePtr *temp;
2316
2317 cur->nodeMax *= 2;
2318 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2319 sizeof(xmlNodePtr));
2320 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002321 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002322 return;
2323 }
2324 cur->nodeTab = temp;
2325 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002326 if (val->type == XML_NAMESPACE_DECL) {
2327 xmlNsPtr ns = (xmlNsPtr) val;
2328
2329 cur->nodeTab[cur->nodeNr++] =
2330 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2331 } else
2332 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002333}
2334
2335/**
2336 * xmlXPathNodeSetAddUnique:
2337 * @cur: the initial node set
2338 * @val: a new xmlNodePtr
2339 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002340 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00002341 * when we are sure the node is not already in the set.
2342 */
2343void
2344xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00002345 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002346
Daniel Veillardef0b4502003-03-24 13:57:34 +00002347#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00002348 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
2349 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00002350#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00002351
William M. Brack08171912003-12-29 02:52:11 +00002352 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002353 /*
2354 * grow the nodeTab if needed
2355 */
2356 if (cur->nodeMax == 0) {
2357 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2358 sizeof(xmlNodePtr));
2359 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002360 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002361 return;
2362 }
2363 memset(cur->nodeTab, 0 ,
2364 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2365 cur->nodeMax = XML_NODESET_DEFAULT;
2366 } else if (cur->nodeNr == cur->nodeMax) {
2367 xmlNodePtr *temp;
2368
2369 cur->nodeMax *= 2;
2370 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2371 sizeof(xmlNodePtr));
2372 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002373 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002374 return;
2375 }
2376 cur->nodeTab = temp;
2377 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002378 if (val->type == XML_NAMESPACE_DECL) {
2379 xmlNsPtr ns = (xmlNsPtr) val;
2380
2381 cur->nodeTab[cur->nodeNr++] =
2382 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2383 } else
2384 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002385}
2386
2387/**
2388 * xmlXPathNodeSetMerge:
2389 * @val1: the first NodeSet or NULL
2390 * @val2: the second NodeSet
2391 *
2392 * Merges two nodesets, all nodes from @val2 are added to @val1
2393 * if @val1 is NULL, a new set is created and copied from @val2
2394 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002395 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002396 */
2397xmlNodeSetPtr
2398xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002399 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002400 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00002401
2402 if (val2 == NULL) return(val1);
2403 if (val1 == NULL) {
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00002404 val1 = xmlXPathNodeSetCreate(NULL);
2405#if 0
2406 /*
2407 * TODO: The optimization won't work in every case, since
2408 * those nasty namespace nodes need to be added with
2409 * xmlXPathNodeSetDupNs() to the set; thus a pure
2410 * memcpy is not possible.
2411 */
2412 /*
2413 * Optimization: Create an equally sized node-set
2414 * and memcpy the content.
2415 */
2416 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
2417 if (val1 == NULL)
2418 return(NULL);
2419 if (val2->nodeNr != 0) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002420 if (val2->nodeNr == 1)
2421 *(val1->nodeTab) = *(val2->nodeTab);
2422 else {
2423 memcpy(val1->nodeTab, val2->nodeTab,
2424 val2->nodeNr * sizeof(xmlNodePtr));
2425 }
2426 val1->nodeNr = val2->nodeNr;
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00002427 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002428 return(val1);
Kasimier T. Buchcik984a9ae2006-05-24 09:02:35 +00002429#endif /* if 0 */
Owen Taylor3473f882001-02-23 17:55:21 +00002430 }
2431
William M. Brack08171912003-12-29 02:52:11 +00002432 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002433 initNr = val1->nodeNr;
2434
2435 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002436 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002437 /*
William M. Brack08171912003-12-29 02:52:11 +00002438 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002439 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002440 skip = 0;
2441 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002442 n1 = val1->nodeTab[j];
2443 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002444 skip = 1;
2445 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002446 } else if ((n1->type == XML_NAMESPACE_DECL) &&
2447 (n2->type == XML_NAMESPACE_DECL)) {
2448 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2449 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2450 ((xmlNsPtr) n2)->prefix)))
2451 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002452 skip = 1;
2453 break;
2454 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002455 }
2456 }
2457 if (skip)
2458 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002459
2460 /*
2461 * grow the nodeTab if needed
2462 */
2463 if (val1->nodeMax == 0) {
2464 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2465 sizeof(xmlNodePtr));
2466 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002467 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002468 return(NULL);
2469 }
2470 memset(val1->nodeTab, 0 ,
2471 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2472 val1->nodeMax = XML_NODESET_DEFAULT;
2473 } else if (val1->nodeNr == val1->nodeMax) {
2474 xmlNodePtr *temp;
2475
2476 val1->nodeMax *= 2;
2477 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2478 sizeof(xmlNodePtr));
2479 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002480 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002481 return(NULL);
2482 }
2483 val1->nodeTab = temp;
2484 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002485 if (n2->type == XML_NAMESPACE_DECL) {
2486 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002487
2488 val1->nodeTab[val1->nodeNr++] =
2489 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2490 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002491 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00002492 }
2493
2494 return(val1);
2495}
2496
2497/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002498 * xmlXPathNodeSetMergeUnique:
2499 * @val1: the first NodeSet or NULL
2500 * @val2: the second NodeSet
2501 *
2502 * Merges two nodesets, all nodes from @val2 are added to @val1
2503 * if @val1 is NULL, a new set is created and copied from @val2
2504 *
2505 * Returns @val1 once extended or NULL in case of error.
2506 */
2507static xmlNodeSetPtr
2508xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002509 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002510
2511 if (val2 == NULL) return(val1);
2512 if (val1 == NULL) {
2513 val1 = xmlXPathNodeSetCreate(NULL);
2514 }
2515
William M. Brack08171912003-12-29 02:52:11 +00002516 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002517
2518 for (i = 0;i < val2->nodeNr;i++) {
2519 /*
2520 * grow the nodeTab if needed
2521 */
2522 if (val1->nodeMax == 0) {
2523 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2524 sizeof(xmlNodePtr));
2525 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002526 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002527 return(NULL);
2528 }
2529 memset(val1->nodeTab, 0 ,
2530 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2531 val1->nodeMax = XML_NODESET_DEFAULT;
2532 } else if (val1->nodeNr == val1->nodeMax) {
2533 xmlNodePtr *temp;
2534
2535 val1->nodeMax *= 2;
2536 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2537 sizeof(xmlNodePtr));
2538 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002539 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002540 return(NULL);
2541 }
2542 val1->nodeTab = temp;
2543 }
2544 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2545 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2546
2547 val1->nodeTab[val1->nodeNr++] =
2548 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2549 } else
2550 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2551 }
2552
2553 return(val1);
2554}
2555
2556/**
Owen Taylor3473f882001-02-23 17:55:21 +00002557 * xmlXPathNodeSetDel:
2558 * @cur: the initial node set
2559 * @val: an xmlNodePtr
2560 *
2561 * Removes an xmlNodePtr from an existing NodeSet
2562 */
2563void
2564xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2565 int i;
2566
2567 if (cur == NULL) return;
2568 if (val == NULL) return;
2569
2570 /*
William M. Brack08171912003-12-29 02:52:11 +00002571 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002572 */
2573 for (i = 0;i < cur->nodeNr;i++)
2574 if (cur->nodeTab[i] == val) break;
2575
William M. Brack08171912003-12-29 02:52:11 +00002576 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002577#ifdef DEBUG
2578 xmlGenericError(xmlGenericErrorContext,
2579 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2580 val->name);
2581#endif
2582 return;
2583 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002584 if ((cur->nodeTab[i] != NULL) &&
2585 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2586 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002587 cur->nodeNr--;
2588 for (;i < cur->nodeNr;i++)
2589 cur->nodeTab[i] = cur->nodeTab[i + 1];
2590 cur->nodeTab[cur->nodeNr] = NULL;
2591}
2592
2593/**
2594 * xmlXPathNodeSetRemove:
2595 * @cur: the initial node set
2596 * @val: the index to remove
2597 *
2598 * Removes an entry from an existing NodeSet list.
2599 */
2600void
2601xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2602 if (cur == NULL) return;
2603 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002604 if ((cur->nodeTab[val] != NULL) &&
2605 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2606 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002607 cur->nodeNr--;
2608 for (;val < cur->nodeNr;val++)
2609 cur->nodeTab[val] = cur->nodeTab[val + 1];
2610 cur->nodeTab[cur->nodeNr] = NULL;
2611}
2612
2613/**
2614 * xmlXPathFreeNodeSet:
2615 * @obj: the xmlNodeSetPtr to free
2616 *
2617 * Free the NodeSet compound (not the actual nodes !).
2618 */
2619void
2620xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2621 if (obj == NULL) return;
2622 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002623 int i;
2624
William M. Brack08171912003-12-29 02:52:11 +00002625 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002626 for (i = 0;i < obj->nodeNr;i++)
2627 if ((obj->nodeTab[i] != NULL) &&
2628 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2629 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002630 xmlFree(obj->nodeTab);
2631 }
Owen Taylor3473f882001-02-23 17:55:21 +00002632 xmlFree(obj);
2633}
2634
2635/**
2636 * xmlXPathFreeValueTree:
2637 * @obj: the xmlNodeSetPtr to free
2638 *
2639 * Free the NodeSet compound and the actual tree, this is different
2640 * from xmlXPathFreeNodeSet()
2641 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002642static void
Owen Taylor3473f882001-02-23 17:55:21 +00002643xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2644 int i;
2645
2646 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002647
2648 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002649 for (i = 0;i < obj->nodeNr;i++) {
2650 if (obj->nodeTab[i] != NULL) {
2651 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2652 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2653 } else {
2654 xmlFreeNodeList(obj->nodeTab[i]);
2655 }
2656 }
2657 }
Owen Taylor3473f882001-02-23 17:55:21 +00002658 xmlFree(obj->nodeTab);
2659 }
Owen Taylor3473f882001-02-23 17:55:21 +00002660 xmlFree(obj);
2661}
2662
2663#if defined(DEBUG) || defined(DEBUG_STEP)
2664/**
2665 * xmlGenericErrorContextNodeSet:
2666 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002667 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002668 *
2669 * Quick display of a NodeSet
2670 */
2671void
2672xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2673 int i;
2674
2675 if (output == NULL) output = xmlGenericErrorContext;
2676 if (obj == NULL) {
2677 fprintf(output, "NodeSet == NULL !\n");
2678 return;
2679 }
2680 if (obj->nodeNr == 0) {
2681 fprintf(output, "NodeSet is empty\n");
2682 return;
2683 }
2684 if (obj->nodeTab == NULL) {
2685 fprintf(output, " nodeTab == NULL !\n");
2686 return;
2687 }
2688 for (i = 0; i < obj->nodeNr; i++) {
2689 if (obj->nodeTab[i] == NULL) {
2690 fprintf(output, " NULL !\n");
2691 return;
2692 }
2693 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2694 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2695 fprintf(output, " /");
2696 else if (obj->nodeTab[i]->name == NULL)
2697 fprintf(output, " noname!");
2698 else fprintf(output, " %s", obj->nodeTab[i]->name);
2699 }
2700 fprintf(output, "\n");
2701}
2702#endif
2703
2704/**
2705 * xmlXPathNewNodeSet:
2706 * @val: the NodePtr value
2707 *
2708 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2709 * it with the single Node @val
2710 *
2711 * Returns the newly created object.
2712 */
2713xmlXPathObjectPtr
2714xmlXPathNewNodeSet(xmlNodePtr val) {
2715 xmlXPathObjectPtr ret;
2716
2717 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2718 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002719 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002720 return(NULL);
2721 }
2722 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2723 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002724 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002725 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002726 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002727 return(ret);
2728}
2729
2730/**
2731 * xmlXPathNewValueTree:
2732 * @val: the NodePtr value
2733 *
2734 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2735 * it with the tree root @val
2736 *
2737 * Returns the newly created object.
2738 */
2739xmlXPathObjectPtr
2740xmlXPathNewValueTree(xmlNodePtr val) {
2741 xmlXPathObjectPtr ret;
2742
2743 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2744 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002745 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002746 return(NULL);
2747 }
2748 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2749 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002750 ret->boolval = 1;
2751 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002752 ret->nodesetval = xmlXPathNodeSetCreate(val);
2753 return(ret);
2754}
2755
2756/**
2757 * xmlXPathNewNodeSetList:
2758 * @val: an existing NodeSet
2759 *
2760 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2761 * it with the Nodeset @val
2762 *
2763 * Returns the newly created object.
2764 */
2765xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002766xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2767{
Owen Taylor3473f882001-02-23 17:55:21 +00002768 xmlXPathObjectPtr ret;
2769 int i;
2770
2771 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002772 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002773 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002774 ret = xmlXPathNewNodeSet(NULL);
2775 else {
2776 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2777 for (i = 1; i < val->nodeNr; ++i)
2778 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2779 }
Owen Taylor3473f882001-02-23 17:55:21 +00002780
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002781 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002782}
2783
2784/**
2785 * xmlXPathWrapNodeSet:
2786 * @val: the NodePtr value
2787 *
2788 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2789 *
2790 * Returns the newly created object.
2791 */
2792xmlXPathObjectPtr
2793xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2794 xmlXPathObjectPtr ret;
2795
2796 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2797 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002798 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002799 return(NULL);
2800 }
2801 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2802 ret->type = XPATH_NODESET;
2803 ret->nodesetval = val;
2804 return(ret);
2805}
2806
2807/**
2808 * xmlXPathFreeNodeSetList:
2809 * @obj: an existing NodeSetList object
2810 *
2811 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2812 * the list contrary to xmlXPathFreeObject().
2813 */
2814void
2815xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2816 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002817 xmlFree(obj);
2818}
2819
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002820/**
2821 * xmlXPathDifference:
2822 * @nodes1: a node-set
2823 * @nodes2: a node-set
2824 *
2825 * Implements the EXSLT - Sets difference() function:
2826 * node-set set:difference (node-set, node-set)
2827 *
2828 * Returns the difference between the two node sets, or nodes1 if
2829 * nodes2 is empty
2830 */
2831xmlNodeSetPtr
2832xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2833 xmlNodeSetPtr ret;
2834 int i, l1;
2835 xmlNodePtr cur;
2836
2837 if (xmlXPathNodeSetIsEmpty(nodes2))
2838 return(nodes1);
2839
2840 ret = xmlXPathNodeSetCreate(NULL);
2841 if (xmlXPathNodeSetIsEmpty(nodes1))
2842 return(ret);
2843
2844 l1 = xmlXPathNodeSetGetLength(nodes1);
2845
2846 for (i = 0; i < l1; i++) {
2847 cur = xmlXPathNodeSetItem(nodes1, i);
2848 if (!xmlXPathNodeSetContains(nodes2, cur))
2849 xmlXPathNodeSetAddUnique(ret, cur);
2850 }
2851 return(ret);
2852}
2853
2854/**
2855 * xmlXPathIntersection:
2856 * @nodes1: a node-set
2857 * @nodes2: a node-set
2858 *
2859 * Implements the EXSLT - Sets intersection() function:
2860 * node-set set:intersection (node-set, node-set)
2861 *
2862 * Returns a node set comprising the nodes that are within both the
2863 * node sets passed as arguments
2864 */
2865xmlNodeSetPtr
2866xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2867 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2868 int i, l1;
2869 xmlNodePtr cur;
2870
2871 if (xmlXPathNodeSetIsEmpty(nodes1))
2872 return(ret);
2873 if (xmlXPathNodeSetIsEmpty(nodes2))
2874 return(ret);
2875
2876 l1 = xmlXPathNodeSetGetLength(nodes1);
2877
2878 for (i = 0; i < l1; i++) {
2879 cur = xmlXPathNodeSetItem(nodes1, i);
2880 if (xmlXPathNodeSetContains(nodes2, cur))
2881 xmlXPathNodeSetAddUnique(ret, cur);
2882 }
2883 return(ret);
2884}
2885
2886/**
2887 * xmlXPathDistinctSorted:
2888 * @nodes: a node-set, sorted by document order
2889 *
2890 * Implements the EXSLT - Sets distinct() function:
2891 * node-set set:distinct (node-set)
2892 *
2893 * Returns a subset of the nodes contained in @nodes, or @nodes if
2894 * it is empty
2895 */
2896xmlNodeSetPtr
2897xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2898 xmlNodeSetPtr ret;
2899 xmlHashTablePtr hash;
2900 int i, l;
2901 xmlChar * strval;
2902 xmlNodePtr cur;
2903
2904 if (xmlXPathNodeSetIsEmpty(nodes))
2905 return(nodes);
2906
2907 ret = xmlXPathNodeSetCreate(NULL);
2908 l = xmlXPathNodeSetGetLength(nodes);
2909 hash = xmlHashCreate (l);
2910 for (i = 0; i < l; i++) {
2911 cur = xmlXPathNodeSetItem(nodes, i);
2912 strval = xmlXPathCastNodeToString(cur);
2913 if (xmlHashLookup(hash, strval) == NULL) {
2914 xmlHashAddEntry(hash, strval, strval);
2915 xmlXPathNodeSetAddUnique(ret, cur);
2916 } else {
2917 xmlFree(strval);
2918 }
2919 }
2920 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2921 return(ret);
2922}
2923
2924/**
2925 * xmlXPathDistinct:
2926 * @nodes: a node-set
2927 *
2928 * Implements the EXSLT - Sets distinct() function:
2929 * node-set set:distinct (node-set)
2930 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2931 * is called with the sorted node-set
2932 *
2933 * Returns a subset of the nodes contained in @nodes, or @nodes if
2934 * it is empty
2935 */
2936xmlNodeSetPtr
2937xmlXPathDistinct (xmlNodeSetPtr nodes) {
2938 if (xmlXPathNodeSetIsEmpty(nodes))
2939 return(nodes);
2940
2941 xmlXPathNodeSetSort(nodes);
2942 return(xmlXPathDistinctSorted(nodes));
2943}
2944
2945/**
2946 * xmlXPathHasSameNodes:
2947 * @nodes1: a node-set
2948 * @nodes2: a node-set
2949 *
2950 * Implements the EXSLT - Sets has-same-nodes function:
2951 * boolean set:has-same-node(node-set, node-set)
2952 *
2953 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2954 * otherwise
2955 */
2956int
2957xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2958 int i, l;
2959 xmlNodePtr cur;
2960
2961 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2962 xmlXPathNodeSetIsEmpty(nodes2))
2963 return(0);
2964
2965 l = xmlXPathNodeSetGetLength(nodes1);
2966 for (i = 0; i < l; i++) {
2967 cur = xmlXPathNodeSetItem(nodes1, i);
2968 if (xmlXPathNodeSetContains(nodes2, cur))
2969 return(1);
2970 }
2971 return(0);
2972}
2973
2974/**
2975 * xmlXPathNodeLeadingSorted:
2976 * @nodes: a node-set, sorted by document order
2977 * @node: a node
2978 *
2979 * Implements the EXSLT - Sets leading() function:
2980 * node-set set:leading (node-set, node-set)
2981 *
2982 * Returns the nodes in @nodes that precede @node in document order,
2983 * @nodes if @node is NULL or an empty node-set if @nodes
2984 * doesn't contain @node
2985 */
2986xmlNodeSetPtr
2987xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2988 int i, l;
2989 xmlNodePtr cur;
2990 xmlNodeSetPtr ret;
2991
2992 if (node == NULL)
2993 return(nodes);
2994
2995 ret = xmlXPathNodeSetCreate(NULL);
2996 if (xmlXPathNodeSetIsEmpty(nodes) ||
2997 (!xmlXPathNodeSetContains(nodes, node)))
2998 return(ret);
2999
3000 l = xmlXPathNodeSetGetLength(nodes);
3001 for (i = 0; i < l; i++) {
3002 cur = xmlXPathNodeSetItem(nodes, i);
3003 if (cur == node)
3004 break;
3005 xmlXPathNodeSetAddUnique(ret, cur);
3006 }
3007 return(ret);
3008}
3009
3010/**
3011 * xmlXPathNodeLeading:
3012 * @nodes: a node-set
3013 * @node: a node
3014 *
3015 * Implements the EXSLT - Sets leading() function:
3016 * node-set set:leading (node-set, node-set)
3017 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3018 * is called.
3019 *
3020 * Returns the nodes in @nodes that precede @node in document order,
3021 * @nodes if @node is NULL or an empty node-set if @nodes
3022 * doesn't contain @node
3023 */
3024xmlNodeSetPtr
3025xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3026 xmlXPathNodeSetSort(nodes);
3027 return(xmlXPathNodeLeadingSorted(nodes, node));
3028}
3029
3030/**
3031 * xmlXPathLeadingSorted:
3032 * @nodes1: a node-set, sorted by document order
3033 * @nodes2: a node-set, sorted by document order
3034 *
3035 * Implements the EXSLT - Sets leading() function:
3036 * node-set set:leading (node-set, node-set)
3037 *
3038 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3039 * in document order, @nodes1 if @nodes2 is NULL or empty or
3040 * an empty node-set if @nodes1 doesn't contain @nodes2
3041 */
3042xmlNodeSetPtr
3043xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3044 if (xmlXPathNodeSetIsEmpty(nodes2))
3045 return(nodes1);
3046 return(xmlXPathNodeLeadingSorted(nodes1,
3047 xmlXPathNodeSetItem(nodes2, 1)));
3048}
3049
3050/**
3051 * xmlXPathLeading:
3052 * @nodes1: a node-set
3053 * @nodes2: a node-set
3054 *
3055 * Implements the EXSLT - Sets leading() function:
3056 * node-set set:leading (node-set, node-set)
3057 * @nodes1 and @nodes2 are sorted by document order, then
3058 * #exslSetsLeadingSorted is called.
3059 *
3060 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3061 * in document order, @nodes1 if @nodes2 is NULL or empty or
3062 * an empty node-set if @nodes1 doesn't contain @nodes2
3063 */
3064xmlNodeSetPtr
3065xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3066 if (xmlXPathNodeSetIsEmpty(nodes2))
3067 return(nodes1);
3068 if (xmlXPathNodeSetIsEmpty(nodes1))
3069 return(xmlXPathNodeSetCreate(NULL));
3070 xmlXPathNodeSetSort(nodes1);
3071 xmlXPathNodeSetSort(nodes2);
3072 return(xmlXPathNodeLeadingSorted(nodes1,
3073 xmlXPathNodeSetItem(nodes2, 1)));
3074}
3075
3076/**
3077 * xmlXPathNodeTrailingSorted:
3078 * @nodes: a node-set, sorted by document order
3079 * @node: a node
3080 *
3081 * Implements the EXSLT - Sets trailing() function:
3082 * node-set set:trailing (node-set, node-set)
3083 *
3084 * Returns the nodes in @nodes that follow @node in document order,
3085 * @nodes if @node is NULL or an empty node-set if @nodes
3086 * doesn't contain @node
3087 */
3088xmlNodeSetPtr
3089xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3090 int i, l;
3091 xmlNodePtr cur;
3092 xmlNodeSetPtr ret;
3093
3094 if (node == NULL)
3095 return(nodes);
3096
3097 ret = xmlXPathNodeSetCreate(NULL);
3098 if (xmlXPathNodeSetIsEmpty(nodes) ||
3099 (!xmlXPathNodeSetContains(nodes, node)))
3100 return(ret);
3101
3102 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00003103 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003104 cur = xmlXPathNodeSetItem(nodes, i);
3105 if (cur == node)
3106 break;
3107 xmlXPathNodeSetAddUnique(ret, cur);
3108 }
3109 return(ret);
3110}
3111
3112/**
3113 * xmlXPathNodeTrailing:
3114 * @nodes: a node-set
3115 * @node: a node
3116 *
3117 * Implements the EXSLT - Sets trailing() function:
3118 * node-set set:trailing (node-set, node-set)
3119 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3120 * is called.
3121 *
3122 * Returns the nodes in @nodes that follow @node in document order,
3123 * @nodes if @node is NULL or an empty node-set if @nodes
3124 * doesn't contain @node
3125 */
3126xmlNodeSetPtr
3127xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3128 xmlXPathNodeSetSort(nodes);
3129 return(xmlXPathNodeTrailingSorted(nodes, node));
3130}
3131
3132/**
3133 * xmlXPathTrailingSorted:
3134 * @nodes1: a node-set, sorted by document order
3135 * @nodes2: a node-set, sorted by document order
3136 *
3137 * Implements the EXSLT - Sets trailing() function:
3138 * node-set set:trailing (node-set, node-set)
3139 *
3140 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3141 * in document order, @nodes1 if @nodes2 is NULL or empty or
3142 * an empty node-set if @nodes1 doesn't contain @nodes2
3143 */
3144xmlNodeSetPtr
3145xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3146 if (xmlXPathNodeSetIsEmpty(nodes2))
3147 return(nodes1);
3148 return(xmlXPathNodeTrailingSorted(nodes1,
3149 xmlXPathNodeSetItem(nodes2, 0)));
3150}
3151
3152/**
3153 * xmlXPathTrailing:
3154 * @nodes1: a node-set
3155 * @nodes2: a node-set
3156 *
3157 * Implements the EXSLT - Sets trailing() function:
3158 * node-set set:trailing (node-set, node-set)
3159 * @nodes1 and @nodes2 are sorted by document order, then
3160 * #xmlXPathTrailingSorted is called.
3161 *
3162 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3163 * in document order, @nodes1 if @nodes2 is NULL or empty or
3164 * an empty node-set if @nodes1 doesn't contain @nodes2
3165 */
3166xmlNodeSetPtr
3167xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3168 if (xmlXPathNodeSetIsEmpty(nodes2))
3169 return(nodes1);
3170 if (xmlXPathNodeSetIsEmpty(nodes1))
3171 return(xmlXPathNodeSetCreate(NULL));
3172 xmlXPathNodeSetSort(nodes1);
3173 xmlXPathNodeSetSort(nodes2);
3174 return(xmlXPathNodeTrailingSorted(nodes1,
3175 xmlXPathNodeSetItem(nodes2, 0)));
3176}
3177
Owen Taylor3473f882001-02-23 17:55:21 +00003178/************************************************************************
3179 * *
3180 * Routines to handle extra functions *
3181 * *
3182 ************************************************************************/
3183
3184/**
3185 * xmlXPathRegisterFunc:
3186 * @ctxt: the XPath context
3187 * @name: the function name
3188 * @f: the function implementation or NULL
3189 *
3190 * Register a new function. If @f is NULL it unregisters the function
3191 *
3192 * Returns 0 in case of success, -1 in case of error
3193 */
3194int
3195xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3196 xmlXPathFunction f) {
3197 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3198}
3199
3200/**
3201 * xmlXPathRegisterFuncNS:
3202 * @ctxt: the XPath context
3203 * @name: the function name
3204 * @ns_uri: the function namespace URI
3205 * @f: the function implementation or NULL
3206 *
3207 * Register a new function. If @f is NULL it unregisters the function
3208 *
3209 * Returns 0 in case of success, -1 in case of error
3210 */
3211int
3212xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3213 const xmlChar *ns_uri, xmlXPathFunction f) {
3214 if (ctxt == NULL)
3215 return(-1);
3216 if (name == NULL)
3217 return(-1);
3218
3219 if (ctxt->funcHash == NULL)
3220 ctxt->funcHash = xmlHashCreate(0);
3221 if (ctxt->funcHash == NULL)
3222 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00003223 if (f == NULL)
3224 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00003225 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00003226}
3227
3228/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00003229 * xmlXPathRegisterFuncLookup:
3230 * @ctxt: the XPath context
3231 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003232 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00003233 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003234 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00003235 */
3236void
3237xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3238 xmlXPathFuncLookupFunc f,
3239 void *funcCtxt) {
3240 if (ctxt == NULL)
3241 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003242 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003243 ctxt->funcLookupData = funcCtxt;
3244}
3245
3246/**
Owen Taylor3473f882001-02-23 17:55:21 +00003247 * xmlXPathFunctionLookup:
3248 * @ctxt: the XPath context
3249 * @name: the function name
3250 *
3251 * Search in the Function array of the context for the given
3252 * function.
3253 *
3254 * Returns the xmlXPathFunction or NULL if not found
3255 */
3256xmlXPathFunction
3257xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00003258 if (ctxt == NULL)
3259 return (NULL);
3260
3261 if (ctxt->funcLookupFunc != NULL) {
3262 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00003263 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003264
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003265 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00003266 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00003267 if (ret != NULL)
3268 return(ret);
3269 }
Owen Taylor3473f882001-02-23 17:55:21 +00003270 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3271}
3272
3273/**
3274 * xmlXPathFunctionLookupNS:
3275 * @ctxt: the XPath context
3276 * @name: the function name
3277 * @ns_uri: the function namespace URI
3278 *
3279 * Search in the Function array of the context for the given
3280 * function.
3281 *
3282 * Returns the xmlXPathFunction or NULL if not found
3283 */
3284xmlXPathFunction
3285xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3286 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00003287 xmlXPathFunction ret;
3288
Owen Taylor3473f882001-02-23 17:55:21 +00003289 if (ctxt == NULL)
3290 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003291 if (name == NULL)
3292 return(NULL);
3293
Thomas Broyerba4ad322001-07-26 16:55:21 +00003294 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00003295 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003296
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003297 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00003298 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00003299 if (ret != NULL)
3300 return(ret);
3301 }
3302
3303 if (ctxt->funcHash == NULL)
3304 return(NULL);
3305
William M. Brackad0e67c2004-12-01 14:35:10 +00003306 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3307 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003308}
3309
3310/**
3311 * xmlXPathRegisteredFuncsCleanup:
3312 * @ctxt: the XPath context
3313 *
3314 * Cleanup the XPath context data associated to registered functions
3315 */
3316void
3317xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3318 if (ctxt == NULL)
3319 return;
3320
3321 xmlHashFree(ctxt->funcHash, NULL);
3322 ctxt->funcHash = NULL;
3323}
3324
3325/************************************************************************
3326 * *
William M. Brack08171912003-12-29 02:52:11 +00003327 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00003328 * *
3329 ************************************************************************/
3330
3331/**
3332 * xmlXPathRegisterVariable:
3333 * @ctxt: the XPath context
3334 * @name: the variable name
3335 * @value: the variable value or NULL
3336 *
3337 * Register a new variable value. If @value is NULL it unregisters
3338 * the variable
3339 *
3340 * Returns 0 in case of success, -1 in case of error
3341 */
3342int
3343xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3344 xmlXPathObjectPtr value) {
3345 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3346}
3347
3348/**
3349 * xmlXPathRegisterVariableNS:
3350 * @ctxt: the XPath context
3351 * @name: the variable name
3352 * @ns_uri: the variable namespace URI
3353 * @value: the variable value or NULL
3354 *
3355 * Register a new variable value. If @value is NULL it unregisters
3356 * the variable
3357 *
3358 * Returns 0 in case of success, -1 in case of error
3359 */
3360int
3361xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3362 const xmlChar *ns_uri,
3363 xmlXPathObjectPtr value) {
3364 if (ctxt == NULL)
3365 return(-1);
3366 if (name == NULL)
3367 return(-1);
3368
3369 if (ctxt->varHash == NULL)
3370 ctxt->varHash = xmlHashCreate(0);
3371 if (ctxt->varHash == NULL)
3372 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00003373 if (value == NULL)
3374 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3375 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00003376 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3377 (void *) value,
3378 (xmlHashDeallocator)xmlXPathFreeObject));
3379}
3380
3381/**
3382 * xmlXPathRegisterVariableLookup:
3383 * @ctxt: the XPath context
3384 * @f: the lookup function
3385 * @data: the lookup data
3386 *
3387 * register an external mechanism to do variable lookup
3388 */
3389void
3390xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3391 xmlXPathVariableLookupFunc f, void *data) {
3392 if (ctxt == NULL)
3393 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003394 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003395 ctxt->varLookupData = data;
3396}
3397
3398/**
3399 * xmlXPathVariableLookup:
3400 * @ctxt: the XPath context
3401 * @name: the variable name
3402 *
3403 * Search in the Variable array of the context for the given
3404 * variable value.
3405 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003406 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003407 */
3408xmlXPathObjectPtr
3409xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3410 if (ctxt == NULL)
3411 return(NULL);
3412
3413 if (ctxt->varLookupFunc != NULL) {
3414 xmlXPathObjectPtr ret;
3415
3416 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3417 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003418 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003419 }
3420 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3421}
3422
3423/**
3424 * xmlXPathVariableLookupNS:
3425 * @ctxt: the XPath context
3426 * @name: the variable name
3427 * @ns_uri: the variable namespace URI
3428 *
3429 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003430 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003431 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003432 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003433 */
3434xmlXPathObjectPtr
3435xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3436 const xmlChar *ns_uri) {
3437 if (ctxt == NULL)
3438 return(NULL);
3439
3440 if (ctxt->varLookupFunc != NULL) {
3441 xmlXPathObjectPtr ret;
3442
3443 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3444 (ctxt->varLookupData, name, ns_uri);
3445 if (ret != NULL) return(ret);
3446 }
3447
3448 if (ctxt->varHash == NULL)
3449 return(NULL);
3450 if (name == NULL)
3451 return(NULL);
3452
Daniel Veillard8c357d52001-07-03 23:43:33 +00003453 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3454 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003455}
3456
3457/**
3458 * xmlXPathRegisteredVariablesCleanup:
3459 * @ctxt: the XPath context
3460 *
3461 * Cleanup the XPath context data associated to registered variables
3462 */
3463void
3464xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3465 if (ctxt == NULL)
3466 return;
3467
Daniel Veillard76d66f42001-05-16 21:05:17 +00003468 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003469 ctxt->varHash = NULL;
3470}
3471
3472/**
3473 * xmlXPathRegisterNs:
3474 * @ctxt: the XPath context
3475 * @prefix: the namespace prefix
3476 * @ns_uri: the namespace name
3477 *
3478 * Register a new namespace. If @ns_uri is NULL it unregisters
3479 * the namespace
3480 *
3481 * Returns 0 in case of success, -1 in case of error
3482 */
3483int
3484xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3485 const xmlChar *ns_uri) {
3486 if (ctxt == NULL)
3487 return(-1);
3488 if (prefix == NULL)
3489 return(-1);
3490
3491 if (ctxt->nsHash == NULL)
3492 ctxt->nsHash = xmlHashCreate(10);
3493 if (ctxt->nsHash == NULL)
3494 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003495 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003496 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003497 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003498 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003499 (xmlHashDeallocator)xmlFree));
3500}
3501
3502/**
3503 * xmlXPathNsLookup:
3504 * @ctxt: the XPath context
3505 * @prefix: the namespace prefix value
3506 *
3507 * Search in the namespace declaration array of the context for the given
3508 * namespace name associated to the given prefix
3509 *
3510 * Returns the value or NULL if not found
3511 */
3512const xmlChar *
3513xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3514 if (ctxt == NULL)
3515 return(NULL);
3516 if (prefix == NULL)
3517 return(NULL);
3518
3519#ifdef XML_XML_NAMESPACE
3520 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3521 return(XML_XML_NAMESPACE);
3522#endif
3523
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003524 if (ctxt->namespaces != NULL) {
3525 int i;
3526
3527 for (i = 0;i < ctxt->nsNr;i++) {
3528 if ((ctxt->namespaces[i] != NULL) &&
3529 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3530 return(ctxt->namespaces[i]->href);
3531 }
3532 }
Owen Taylor3473f882001-02-23 17:55:21 +00003533
3534 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3535}
3536
3537/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003538 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003539 * @ctxt: the XPath context
3540 *
3541 * Cleanup the XPath context data associated to registered variables
3542 */
3543void
3544xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3545 if (ctxt == NULL)
3546 return;
3547
Daniel Veillard42766c02002-08-22 20:52:17 +00003548 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003549 ctxt->nsHash = NULL;
3550}
3551
3552/************************************************************************
3553 * *
3554 * Routines to handle Values *
3555 * *
3556 ************************************************************************/
3557
William M. Brack08171912003-12-29 02:52:11 +00003558/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003559
3560/**
3561 * xmlXPathNewFloat:
3562 * @val: the double value
3563 *
3564 * Create a new xmlXPathObjectPtr of type double and of value @val
3565 *
3566 * Returns the newly created object.
3567 */
3568xmlXPathObjectPtr
3569xmlXPathNewFloat(double val) {
3570 xmlXPathObjectPtr ret;
3571
3572 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3573 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003574 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003575 return(NULL);
3576 }
3577 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3578 ret->type = XPATH_NUMBER;
3579 ret->floatval = val;
3580 return(ret);
3581}
3582
3583/**
3584 * xmlXPathNewBoolean:
3585 * @val: the boolean value
3586 *
3587 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3588 *
3589 * Returns the newly created object.
3590 */
3591xmlXPathObjectPtr
3592xmlXPathNewBoolean(int val) {
3593 xmlXPathObjectPtr ret;
3594
3595 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3596 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003597 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003598 return(NULL);
3599 }
3600 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3601 ret->type = XPATH_BOOLEAN;
3602 ret->boolval = (val != 0);
3603 return(ret);
3604}
3605
3606/**
3607 * xmlXPathNewString:
3608 * @val: the xmlChar * value
3609 *
3610 * Create a new xmlXPathObjectPtr of type string and of value @val
3611 *
3612 * Returns the newly created object.
3613 */
3614xmlXPathObjectPtr
3615xmlXPathNewString(const xmlChar *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 string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003621 return(NULL);
3622 }
3623 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3624 ret->type = XPATH_STRING;
3625 if (val != NULL)
3626 ret->stringval = xmlStrdup(val);
3627 else
3628 ret->stringval = xmlStrdup((const xmlChar *)"");
3629 return(ret);
3630}
3631
3632/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003633 * xmlXPathWrapString:
3634 * @val: the xmlChar * value
3635 *
3636 * Wraps the @val string into an XPath object.
3637 *
3638 * Returns the newly created object.
3639 */
3640xmlXPathObjectPtr
3641xmlXPathWrapString (xmlChar *val) {
3642 xmlXPathObjectPtr ret;
3643
3644 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3645 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003646 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003647 return(NULL);
3648 }
3649 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3650 ret->type = XPATH_STRING;
3651 ret->stringval = val;
3652 return(ret);
3653}
3654
3655/**
Owen Taylor3473f882001-02-23 17:55:21 +00003656 * xmlXPathNewCString:
3657 * @val: the char * value
3658 *
3659 * Create a new xmlXPathObjectPtr of type string and of value @val
3660 *
3661 * Returns the newly created object.
3662 */
3663xmlXPathObjectPtr
3664xmlXPathNewCString(const char *val) {
3665 xmlXPathObjectPtr ret;
3666
3667 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3668 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003669 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003670 return(NULL);
3671 }
3672 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3673 ret->type = XPATH_STRING;
3674 ret->stringval = xmlStrdup(BAD_CAST val);
3675 return(ret);
3676}
3677
3678/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003679 * xmlXPathWrapCString:
3680 * @val: the char * value
3681 *
3682 * Wraps a string into an XPath object.
3683 *
3684 * Returns the newly created object.
3685 */
3686xmlXPathObjectPtr
3687xmlXPathWrapCString (char * val) {
3688 return(xmlXPathWrapString((xmlChar *)(val)));
3689}
3690
3691/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003692 * xmlXPathWrapExternal:
3693 * @val: the user data
3694 *
3695 * Wraps the @val data into an XPath object.
3696 *
3697 * Returns the newly created object.
3698 */
3699xmlXPathObjectPtr
3700xmlXPathWrapExternal (void *val) {
3701 xmlXPathObjectPtr ret;
3702
3703 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3704 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003705 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003706 return(NULL);
3707 }
3708 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3709 ret->type = XPATH_USERS;
3710 ret->user = val;
3711 return(ret);
3712}
3713
3714/**
Owen Taylor3473f882001-02-23 17:55:21 +00003715 * xmlXPathObjectCopy:
3716 * @val: the original object
3717 *
3718 * allocate a new copy of a given object
3719 *
3720 * Returns the newly created object.
3721 */
3722xmlXPathObjectPtr
3723xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3724 xmlXPathObjectPtr ret;
3725
3726 if (val == NULL)
3727 return(NULL);
3728
3729 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3730 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003731 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003732 return(NULL);
3733 }
3734 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3735 switch (val->type) {
3736 case XPATH_BOOLEAN:
3737 case XPATH_NUMBER:
3738 case XPATH_POINT:
3739 case XPATH_RANGE:
3740 break;
3741 case XPATH_STRING:
3742 ret->stringval = xmlStrdup(val->stringval);
3743 break;
3744 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003745#if 0
3746/*
3747 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3748 this previous handling is no longer correct, and can cause some serious
3749 problems (ref. bug 145547)
3750*/
Owen Taylor3473f882001-02-23 17:55:21 +00003751 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003752 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003753 xmlNodePtr cur, tmp;
3754 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003755
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003756 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003757 top = xmlNewDoc(NULL);
3758 top->name = (char *)
3759 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003760 ret->user = top;
3761 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003762 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003763 cur = val->nodesetval->nodeTab[0]->children;
3764 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003765 tmp = xmlDocCopyNode(cur, top, 1);
3766 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003767 cur = cur->next;
3768 }
3769 }
William M. Bracke9449c52004-07-11 14:41:20 +00003770
Daniel Veillard9adc0462003-03-24 18:39:54 +00003771 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003772 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003773 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003774 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003775 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003776#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003777 case XPATH_NODESET:
3778 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003779 /* Do not deallocate the copied tree value */
3780 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003781 break;
3782 case XPATH_LOCATIONSET:
3783#ifdef LIBXML_XPTR_ENABLED
3784 {
3785 xmlLocationSetPtr loc = val->user;
3786 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3787 break;
3788 }
3789#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003790 case XPATH_USERS:
3791 ret->user = val->user;
3792 break;
3793 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003794 xmlGenericError(xmlGenericErrorContext,
3795 "xmlXPathObjectCopy: unsupported type %d\n",
3796 val->type);
3797 break;
3798 }
3799 return(ret);
3800}
3801
3802/**
3803 * xmlXPathFreeObject:
3804 * @obj: the object to free
3805 *
3806 * Free up an xmlXPathObjectPtr object.
3807 */
3808void
3809xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3810 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003811 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003812 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003813#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003814 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003815 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003816 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003817 } else
3818#endif
3819 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003820 xmlXPathFreeValueTree(obj->nodesetval);
3821 } else {
3822 if (obj->nodesetval != NULL)
3823 xmlXPathFreeNodeSet(obj->nodesetval);
3824 }
Owen Taylor3473f882001-02-23 17:55:21 +00003825#ifdef LIBXML_XPTR_ENABLED
3826 } else if (obj->type == XPATH_LOCATIONSET) {
3827 if (obj->user != NULL)
3828 xmlXPtrFreeLocationSet(obj->user);
3829#endif
3830 } else if (obj->type == XPATH_STRING) {
3831 if (obj->stringval != NULL)
3832 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003833 }
3834
Owen Taylor3473f882001-02-23 17:55:21 +00003835 xmlFree(obj);
3836}
3837
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003838
3839/************************************************************************
3840 * *
3841 * Type Casting Routines *
3842 * *
3843 ************************************************************************/
3844
3845/**
3846 * xmlXPathCastBooleanToString:
3847 * @val: a boolean
3848 *
3849 * Converts a boolean to its string value.
3850 *
3851 * Returns a newly allocated string.
3852 */
3853xmlChar *
3854xmlXPathCastBooleanToString (int val) {
3855 xmlChar *ret;
3856 if (val)
3857 ret = xmlStrdup((const xmlChar *) "true");
3858 else
3859 ret = xmlStrdup((const xmlChar *) "false");
3860 return(ret);
3861}
3862
3863/**
3864 * xmlXPathCastNumberToString:
3865 * @val: a number
3866 *
3867 * Converts a number to its string value.
3868 *
3869 * Returns a newly allocated string.
3870 */
3871xmlChar *
3872xmlXPathCastNumberToString (double val) {
3873 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003874 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003875 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003876 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003877 break;
3878 case -1:
3879 ret = xmlStrdup((const xmlChar *) "-Infinity");
3880 break;
3881 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003882 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003883 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003884 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3885 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003886 } else {
3887 /* could be improved */
3888 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00003889 xmlXPathFormatNumber(val, buf, 99);
3890 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003891 ret = xmlStrdup((const xmlChar *) buf);
3892 }
3893 }
3894 return(ret);
3895}
3896
3897/**
3898 * xmlXPathCastNodeToString:
3899 * @node: a node
3900 *
3901 * Converts a node to its string value.
3902 *
3903 * Returns a newly allocated string.
3904 */
3905xmlChar *
3906xmlXPathCastNodeToString (xmlNodePtr node) {
3907 return(xmlNodeGetContent(node));
3908}
3909
3910/**
3911 * xmlXPathCastNodeSetToString:
3912 * @ns: a node-set
3913 *
3914 * Converts a node-set to its string value.
3915 *
3916 * Returns a newly allocated string.
3917 */
3918xmlChar *
3919xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3920 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3921 return(xmlStrdup((const xmlChar *) ""));
3922
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003923 if (ns->nodeNr > 1)
3924 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003925 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3926}
3927
3928/**
3929 * xmlXPathCastToString:
3930 * @val: an XPath object
3931 *
3932 * Converts an existing object to its string() equivalent
3933 *
3934 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003935 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003936 * string object).
3937 */
3938xmlChar *
3939xmlXPathCastToString(xmlXPathObjectPtr val) {
3940 xmlChar *ret = NULL;
3941
3942 if (val == NULL)
3943 return(xmlStrdup((const xmlChar *) ""));
3944 switch (val->type) {
3945 case XPATH_UNDEFINED:
3946#ifdef DEBUG_EXPR
3947 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3948#endif
3949 ret = xmlStrdup((const xmlChar *) "");
3950 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003951 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003952 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003953 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3954 break;
3955 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003956 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003957 case XPATH_BOOLEAN:
3958 ret = xmlXPathCastBooleanToString(val->boolval);
3959 break;
3960 case XPATH_NUMBER: {
3961 ret = xmlXPathCastNumberToString(val->floatval);
3962 break;
3963 }
3964 case XPATH_USERS:
3965 case XPATH_POINT:
3966 case XPATH_RANGE:
3967 case XPATH_LOCATIONSET:
3968 TODO
3969 ret = xmlStrdup((const xmlChar *) "");
3970 break;
3971 }
3972 return(ret);
3973}
3974
3975/**
3976 * xmlXPathConvertString:
3977 * @val: an XPath object
3978 *
3979 * Converts an existing object to its string() equivalent
3980 *
3981 * Returns the new object, the old one is freed (or the operation
3982 * is done directly on @val)
3983 */
3984xmlXPathObjectPtr
3985xmlXPathConvertString(xmlXPathObjectPtr val) {
3986 xmlChar *res = NULL;
3987
3988 if (val == NULL)
3989 return(xmlXPathNewCString(""));
3990
3991 switch (val->type) {
3992 case XPATH_UNDEFINED:
3993#ifdef DEBUG_EXPR
3994 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3995#endif
3996 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003997 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003998 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003999 res = xmlXPathCastNodeSetToString(val->nodesetval);
4000 break;
4001 case XPATH_STRING:
4002 return(val);
4003 case XPATH_BOOLEAN:
4004 res = xmlXPathCastBooleanToString(val->boolval);
4005 break;
4006 case XPATH_NUMBER:
4007 res = xmlXPathCastNumberToString(val->floatval);
4008 break;
4009 case XPATH_USERS:
4010 case XPATH_POINT:
4011 case XPATH_RANGE:
4012 case XPATH_LOCATIONSET:
4013 TODO;
4014 break;
4015 }
4016 xmlXPathFreeObject(val);
4017 if (res == NULL)
4018 return(xmlXPathNewCString(""));
4019 return(xmlXPathWrapString(res));
4020}
4021
4022/**
4023 * xmlXPathCastBooleanToNumber:
4024 * @val: a boolean
4025 *
4026 * Converts a boolean to its number value
4027 *
4028 * Returns the number value
4029 */
4030double
4031xmlXPathCastBooleanToNumber(int val) {
4032 if (val)
4033 return(1.0);
4034 return(0.0);
4035}
4036
4037/**
4038 * xmlXPathCastStringToNumber:
4039 * @val: a string
4040 *
4041 * Converts a string to its number value
4042 *
4043 * Returns the number value
4044 */
4045double
4046xmlXPathCastStringToNumber(const xmlChar * val) {
4047 return(xmlXPathStringEvalNumber(val));
4048}
4049
4050/**
4051 * xmlXPathCastNodeToNumber:
4052 * @node: a node
4053 *
4054 * Converts a node to its number value
4055 *
4056 * Returns the number value
4057 */
4058double
4059xmlXPathCastNodeToNumber (xmlNodePtr node) {
4060 xmlChar *strval;
4061 double ret;
4062
4063 if (node == NULL)
4064 return(xmlXPathNAN);
4065 strval = xmlXPathCastNodeToString(node);
4066 if (strval == NULL)
4067 return(xmlXPathNAN);
4068 ret = xmlXPathCastStringToNumber(strval);
4069 xmlFree(strval);
4070
4071 return(ret);
4072}
4073
4074/**
4075 * xmlXPathCastNodeSetToNumber:
4076 * @ns: a node-set
4077 *
4078 * Converts a node-set to its number value
4079 *
4080 * Returns the number value
4081 */
4082double
4083xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4084 xmlChar *str;
4085 double ret;
4086
4087 if (ns == NULL)
4088 return(xmlXPathNAN);
4089 str = xmlXPathCastNodeSetToString(ns);
4090 ret = xmlXPathCastStringToNumber(str);
4091 xmlFree(str);
4092 return(ret);
4093}
4094
4095/**
4096 * xmlXPathCastToNumber:
4097 * @val: an XPath object
4098 *
4099 * Converts an XPath object to its number value
4100 *
4101 * Returns the number value
4102 */
4103double
4104xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4105 double ret = 0.0;
4106
4107 if (val == NULL)
4108 return(xmlXPathNAN);
4109 switch (val->type) {
4110 case XPATH_UNDEFINED:
4111#ifdef DEGUB_EXPR
4112 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4113#endif
4114 ret = xmlXPathNAN;
4115 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004116 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00004117 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004118 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
4119 break;
4120 case XPATH_STRING:
4121 ret = xmlXPathCastStringToNumber(val->stringval);
4122 break;
4123 case XPATH_NUMBER:
4124 ret = val->floatval;
4125 break;
4126 case XPATH_BOOLEAN:
4127 ret = xmlXPathCastBooleanToNumber(val->boolval);
4128 break;
4129 case XPATH_USERS:
4130 case XPATH_POINT:
4131 case XPATH_RANGE:
4132 case XPATH_LOCATIONSET:
4133 TODO;
4134 ret = xmlXPathNAN;
4135 break;
4136 }
4137 return(ret);
4138}
4139
4140/**
4141 * xmlXPathConvertNumber:
4142 * @val: an XPath object
4143 *
4144 * Converts an existing object to its number() equivalent
4145 *
4146 * Returns the new object, the old one is freed (or the operation
4147 * is done directly on @val)
4148 */
4149xmlXPathObjectPtr
4150xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4151 xmlXPathObjectPtr ret;
4152
4153 if (val == NULL)
4154 return(xmlXPathNewFloat(0.0));
4155 if (val->type == XPATH_NUMBER)
4156 return(val);
4157 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4158 xmlXPathFreeObject(val);
4159 return(ret);
4160}
4161
4162/**
4163 * xmlXPathCastNumberToBoolean:
4164 * @val: a number
4165 *
4166 * Converts a number to its boolean value
4167 *
4168 * Returns the boolean value
4169 */
4170int
4171xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00004172 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004173 return(0);
4174 return(1);
4175}
4176
4177/**
4178 * xmlXPathCastStringToBoolean:
4179 * @val: a string
4180 *
4181 * Converts a string to its boolean value
4182 *
4183 * Returns the boolean value
4184 */
4185int
4186xmlXPathCastStringToBoolean (const xmlChar *val) {
4187 if ((val == NULL) || (xmlStrlen(val) == 0))
4188 return(0);
4189 return(1);
4190}
4191
4192/**
4193 * xmlXPathCastNodeSetToBoolean:
4194 * @ns: a node-set
4195 *
4196 * Converts a node-set to its boolean value
4197 *
4198 * Returns the boolean value
4199 */
4200int
4201xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4202 if ((ns == NULL) || (ns->nodeNr == 0))
4203 return(0);
4204 return(1);
4205}
4206
4207/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004208 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004209 * @val: an XPath object
4210 *
4211 * Converts an XPath object to its boolean value
4212 *
4213 * Returns the boolean value
4214 */
4215int
4216xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4217 int ret = 0;
4218
4219 if (val == NULL)
4220 return(0);
4221 switch (val->type) {
4222 case XPATH_UNDEFINED:
4223#ifdef DEBUG_EXPR
4224 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
4225#endif
4226 ret = 0;
4227 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004228 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00004229 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004230 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4231 break;
4232 case XPATH_STRING:
4233 ret = xmlXPathCastStringToBoolean(val->stringval);
4234 break;
4235 case XPATH_NUMBER:
4236 ret = xmlXPathCastNumberToBoolean(val->floatval);
4237 break;
4238 case XPATH_BOOLEAN:
4239 ret = val->boolval;
4240 break;
4241 case XPATH_USERS:
4242 case XPATH_POINT:
4243 case XPATH_RANGE:
4244 case XPATH_LOCATIONSET:
4245 TODO;
4246 ret = 0;
4247 break;
4248 }
4249 return(ret);
4250}
4251
4252
4253/**
4254 * xmlXPathConvertBoolean:
4255 * @val: an XPath object
4256 *
4257 * Converts an existing object to its boolean() equivalent
4258 *
4259 * Returns the new object, the old one is freed (or the operation
4260 * is done directly on @val)
4261 */
4262xmlXPathObjectPtr
4263xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4264 xmlXPathObjectPtr ret;
4265
4266 if (val == NULL)
4267 return(xmlXPathNewBoolean(0));
4268 if (val->type == XPATH_BOOLEAN)
4269 return(val);
4270 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4271 xmlXPathFreeObject(val);
4272 return(ret);
4273}
4274
Owen Taylor3473f882001-02-23 17:55:21 +00004275/************************************************************************
4276 * *
4277 * Routines to handle XPath contexts *
4278 * *
4279 ************************************************************************/
4280
4281/**
4282 * xmlXPathNewContext:
4283 * @doc: the XML document
4284 *
4285 * Create a new xmlXPathContext
4286 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00004287 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00004288 */
4289xmlXPathContextPtr
4290xmlXPathNewContext(xmlDocPtr doc) {
4291 xmlXPathContextPtr ret;
4292
4293 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4294 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004295 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004296 return(NULL);
4297 }
4298 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
4299 ret->doc = doc;
4300 ret->node = NULL;
4301
4302 ret->varHash = NULL;
4303
4304 ret->nb_types = 0;
4305 ret->max_types = 0;
4306 ret->types = NULL;
4307
4308 ret->funcHash = xmlHashCreate(0);
4309
4310 ret->nb_axis = 0;
4311 ret->max_axis = 0;
4312 ret->axis = NULL;
4313
4314 ret->nsHash = NULL;
4315 ret->user = NULL;
4316
4317 ret->contextSize = -1;
4318 ret->proximityPosition = -1;
4319
4320 xmlXPathRegisterAllFunctions(ret);
4321
4322 return(ret);
4323}
4324
4325/**
4326 * xmlXPathFreeContext:
4327 * @ctxt: the context to free
4328 *
4329 * Free up an xmlXPathContext
4330 */
4331void
4332xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00004333 if (ctxt == NULL) return;
4334
Owen Taylor3473f882001-02-23 17:55:21 +00004335 xmlXPathRegisteredNsCleanup(ctxt);
4336 xmlXPathRegisteredFuncsCleanup(ctxt);
4337 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00004338 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00004339 xmlFree(ctxt);
4340}
4341
4342/************************************************************************
4343 * *
4344 * Routines to handle XPath parser contexts *
4345 * *
4346 ************************************************************************/
4347
4348#define CHECK_CTXT(ctxt) \
4349 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00004350 __xmlRaiseError(NULL, NULL, NULL, \
4351 NULL, NULL, XML_FROM_XPATH, \
4352 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
4353 __FILE__, __LINE__, \
4354 NULL, NULL, NULL, 0, 0, \
4355 "NULL context pointer\n"); \
4356 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00004357 } \
4358
4359
4360#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00004361 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
4362 (ctxt->doc->children == NULL)) { \
4363 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00004364 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00004365 }
Owen Taylor3473f882001-02-23 17:55:21 +00004366
4367
4368/**
4369 * xmlXPathNewParserContext:
4370 * @str: the XPath expression
4371 * @ctxt: the XPath context
4372 *
4373 * Create a new xmlXPathParserContext
4374 *
4375 * Returns the xmlXPathParserContext just allocated.
4376 */
4377xmlXPathParserContextPtr
4378xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
4379 xmlXPathParserContextPtr ret;
4380
4381 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4382 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004383 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004384 return(NULL);
4385 }
4386 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4387 ret->cur = ret->base = str;
4388 ret->context = ctxt;
4389
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004390 ret->comp = xmlXPathNewCompExpr();
4391 if (ret->comp == NULL) {
4392 xmlFree(ret->valueTab);
4393 xmlFree(ret);
4394 return(NULL);
4395 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004396 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4397 ret->comp->dict = ctxt->dict;
4398 xmlDictReference(ret->comp->dict);
4399 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004400
4401 return(ret);
4402}
4403
4404/**
4405 * xmlXPathCompParserContext:
4406 * @comp: the XPath compiled expression
4407 * @ctxt: the XPath context
4408 *
4409 * Create a new xmlXPathParserContext when processing a compiled expression
4410 *
4411 * Returns the xmlXPathParserContext just allocated.
4412 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004413static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004414xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4415 xmlXPathParserContextPtr ret;
4416
4417 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4418 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004419 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004420 return(NULL);
4421 }
4422 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4423
Owen Taylor3473f882001-02-23 17:55:21 +00004424 /* Allocate the value stack */
4425 ret->valueTab = (xmlXPathObjectPtr *)
4426 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004427 if (ret->valueTab == NULL) {
4428 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004429 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004430 return(NULL);
4431 }
Owen Taylor3473f882001-02-23 17:55:21 +00004432 ret->valueNr = 0;
4433 ret->valueMax = 10;
4434 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004435
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004436 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004437 ret->comp = comp;
4438
Owen Taylor3473f882001-02-23 17:55:21 +00004439 return(ret);
4440}
4441
4442/**
4443 * xmlXPathFreeParserContext:
4444 * @ctxt: the context to free
4445 *
4446 * Free up an xmlXPathParserContext
4447 */
4448void
4449xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4450 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004451 xmlFree(ctxt->valueTab);
4452 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004453 if (ctxt->comp != NULL) {
4454#ifdef XPATH_STREAMING
4455 if (ctxt->comp->stream != NULL) {
4456 xmlFreePatternList(ctxt->comp->stream);
4457 ctxt->comp->stream = NULL;
4458 }
4459#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004460 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004461 }
Owen Taylor3473f882001-02-23 17:55:21 +00004462 xmlFree(ctxt);
4463}
4464
4465/************************************************************************
4466 * *
4467 * The implicit core function library *
4468 * *
4469 ************************************************************************/
4470
Owen Taylor3473f882001-02-23 17:55:21 +00004471/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004472 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004473 * @node: a node pointer
4474 *
4475 * Function computing the beginning of the string value of the node,
4476 * used to speed up comparisons
4477 *
4478 * Returns an int usable as a hash
4479 */
4480static unsigned int
4481xmlXPathNodeValHash(xmlNodePtr node) {
4482 int len = 2;
4483 const xmlChar * string = NULL;
4484 xmlNodePtr tmp = NULL;
4485 unsigned int ret = 0;
4486
4487 if (node == NULL)
4488 return(0);
4489
Daniel Veillard9adc0462003-03-24 18:39:54 +00004490 if (node->type == XML_DOCUMENT_NODE) {
4491 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4492 if (tmp == NULL)
4493 node = node->children;
4494 else
4495 node = tmp;
4496
4497 if (node == NULL)
4498 return(0);
4499 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500
4501 switch (node->type) {
4502 case XML_COMMENT_NODE:
4503 case XML_PI_NODE:
4504 case XML_CDATA_SECTION_NODE:
4505 case XML_TEXT_NODE:
4506 string = node->content;
4507 if (string == NULL)
4508 return(0);
4509 if (string[0] == 0)
4510 return(0);
4511 return(((unsigned int) string[0]) +
4512 (((unsigned int) string[1]) << 8));
4513 case XML_NAMESPACE_DECL:
4514 string = ((xmlNsPtr)node)->href;
4515 if (string == NULL)
4516 return(0);
4517 if (string[0] == 0)
4518 return(0);
4519 return(((unsigned int) string[0]) +
4520 (((unsigned int) string[1]) << 8));
4521 case XML_ATTRIBUTE_NODE:
4522 tmp = ((xmlAttrPtr) node)->children;
4523 break;
4524 case XML_ELEMENT_NODE:
4525 tmp = node->children;
4526 break;
4527 default:
4528 return(0);
4529 }
4530 while (tmp != NULL) {
4531 switch (tmp->type) {
4532 case XML_COMMENT_NODE:
4533 case XML_PI_NODE:
4534 case XML_CDATA_SECTION_NODE:
4535 case XML_TEXT_NODE:
4536 string = tmp->content;
4537 break;
4538 case XML_NAMESPACE_DECL:
4539 string = ((xmlNsPtr)tmp)->href;
4540 break;
4541 default:
4542 break;
4543 }
4544 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004545 if (len == 1) {
4546 return(ret + (((unsigned int) string[0]) << 8));
4547 }
4548 if (string[1] == 0) {
4549 len = 1;
4550 ret = (unsigned int) string[0];
4551 } else {
4552 return(((unsigned int) string[0]) +
4553 (((unsigned int) string[1]) << 8));
4554 }
4555 }
4556 /*
4557 * Skip to next node
4558 */
4559 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4560 if (tmp->children->type != XML_ENTITY_DECL) {
4561 tmp = tmp->children;
4562 continue;
4563 }
4564 }
4565 if (tmp == node)
4566 break;
4567
4568 if (tmp->next != NULL) {
4569 tmp = tmp->next;
4570 continue;
4571 }
4572
4573 do {
4574 tmp = tmp->parent;
4575 if (tmp == NULL)
4576 break;
4577 if (tmp == node) {
4578 tmp = NULL;
4579 break;
4580 }
4581 if (tmp->next != NULL) {
4582 tmp = tmp->next;
4583 break;
4584 }
4585 } while (tmp != NULL);
4586 }
4587 return(ret);
4588}
4589
4590/**
4591 * xmlXPathStringHash:
4592 * @string: a string
4593 *
4594 * Function computing the beginning of the string value of the node,
4595 * used to speed up comparisons
4596 *
4597 * Returns an int usable as a hash
4598 */
4599static unsigned int
4600xmlXPathStringHash(const xmlChar * string) {
4601 if (string == NULL)
4602 return((unsigned int) 0);
4603 if (string[0] == 0)
4604 return(0);
4605 return(((unsigned int) string[0]) +
4606 (((unsigned int) string[1]) << 8));
4607}
4608
4609/**
Owen Taylor3473f882001-02-23 17:55:21 +00004610 * xmlXPathCompareNodeSetFloat:
4611 * @ctxt: the XPath Parser context
4612 * @inf: less than (1) or greater than (0)
4613 * @strict: is the comparison strict
4614 * @arg: the node set
4615 * @f: the value
4616 *
4617 * Implement the compare operation between a nodeset and a number
4618 * @ns < @val (1, 1, ...
4619 * @ns <= @val (1, 0, ...
4620 * @ns > @val (0, 1, ...
4621 * @ns >= @val (0, 0, ...
4622 *
4623 * If one object to be compared is a node-set and the other is a number,
4624 * then the comparison will be true if and only if there is a node in the
4625 * node-set such that the result of performing the comparison on the number
4626 * to be compared and on the result of converting the string-value of that
4627 * node to a number using the number function is true.
4628 *
4629 * Returns 0 or 1 depending on the results of the test.
4630 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004631static int
Owen Taylor3473f882001-02-23 17:55:21 +00004632xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4633 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4634 int i, ret = 0;
4635 xmlNodeSetPtr ns;
4636 xmlChar *str2;
4637
4638 if ((f == NULL) || (arg == NULL) ||
4639 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4640 xmlXPathFreeObject(arg);
4641 xmlXPathFreeObject(f);
4642 return(0);
4643 }
4644 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004645 if (ns != NULL) {
4646 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004647 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004648 if (str2 != NULL) {
4649 valuePush(ctxt,
4650 xmlXPathNewString(str2));
4651 xmlFree(str2);
4652 xmlXPathNumberFunction(ctxt, 1);
4653 valuePush(ctxt, xmlXPathObjectCopy(f));
4654 ret = xmlXPathCompareValues(ctxt, inf, strict);
4655 if (ret)
4656 break;
4657 }
4658 }
Owen Taylor3473f882001-02-23 17:55:21 +00004659 }
4660 xmlXPathFreeObject(arg);
4661 xmlXPathFreeObject(f);
4662 return(ret);
4663}
4664
4665/**
4666 * xmlXPathCompareNodeSetString:
4667 * @ctxt: the XPath Parser context
4668 * @inf: less than (1) or greater than (0)
4669 * @strict: is the comparison strict
4670 * @arg: the node set
4671 * @s: the value
4672 *
4673 * Implement the compare operation between a nodeset and a string
4674 * @ns < @val (1, 1, ...
4675 * @ns <= @val (1, 0, ...
4676 * @ns > @val (0, 1, ...
4677 * @ns >= @val (0, 0, ...
4678 *
4679 * If one object to be compared is a node-set and the other is a string,
4680 * then the comparison will be true if and only if there is a node in
4681 * the node-set such that the result of performing the comparison on the
4682 * string-value of the node and the other string is true.
4683 *
4684 * Returns 0 or 1 depending on the results of the test.
4685 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004686static int
Owen Taylor3473f882001-02-23 17:55:21 +00004687xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4688 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4689 int i, ret = 0;
4690 xmlNodeSetPtr ns;
4691 xmlChar *str2;
4692
4693 if ((s == NULL) || (arg == NULL) ||
4694 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4695 xmlXPathFreeObject(arg);
4696 xmlXPathFreeObject(s);
4697 return(0);
4698 }
4699 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004700 if (ns != NULL) {
4701 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004702 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004703 if (str2 != NULL) {
4704 valuePush(ctxt,
4705 xmlXPathNewString(str2));
4706 xmlFree(str2);
4707 valuePush(ctxt, xmlXPathObjectCopy(s));
4708 ret = xmlXPathCompareValues(ctxt, inf, strict);
4709 if (ret)
4710 break;
4711 }
4712 }
Owen Taylor3473f882001-02-23 17:55:21 +00004713 }
4714 xmlXPathFreeObject(arg);
4715 xmlXPathFreeObject(s);
4716 return(ret);
4717}
4718
4719/**
4720 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004721 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004722 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004723 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004724 * @arg2: the second node set object
4725 *
4726 * Implement the compare operation on nodesets:
4727 *
4728 * If both objects to be compared are node-sets, then the comparison
4729 * will be true if and only if there is a node in the first node-set
4730 * and a node in the second node-set such that the result of performing
4731 * the comparison on the string-values of the two nodes is true.
4732 * ....
4733 * When neither object to be compared is a node-set and the operator
4734 * is <=, <, >= or >, then the objects are compared by converting both
4735 * objects to numbers and comparing the numbers according to IEEE 754.
4736 * ....
4737 * The number function converts its argument to a number as follows:
4738 * - a string that consists of optional whitespace followed by an
4739 * optional minus sign followed by a Number followed by whitespace
4740 * is converted to the IEEE 754 number that is nearest (according
4741 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4742 * represented by the string; any other string is converted to NaN
4743 *
4744 * Conclusion all nodes need to be converted first to their string value
4745 * and then the comparison must be done when possible
4746 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004747static int
4748xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004749 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4750 int i, j, init = 0;
4751 double val1;
4752 double *values2;
4753 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004754 xmlNodeSetPtr ns1;
4755 xmlNodeSetPtr ns2;
4756
4757 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004758 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4759 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004760 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004761 }
Owen Taylor3473f882001-02-23 17:55:21 +00004762 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004763 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4764 xmlXPathFreeObject(arg1);
4765 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004766 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004767 }
Owen Taylor3473f882001-02-23 17:55:21 +00004768
4769 ns1 = arg1->nodesetval;
4770 ns2 = arg2->nodesetval;
4771
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004772 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004773 xmlXPathFreeObject(arg1);
4774 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004775 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004776 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004777 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004778 xmlXPathFreeObject(arg1);
4779 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004780 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004781 }
Owen Taylor3473f882001-02-23 17:55:21 +00004782
4783 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4784 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004785 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004786 xmlXPathFreeObject(arg1);
4787 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004788 return(0);
4789 }
4790 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004791 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004792 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004793 continue;
4794 for (j = 0;j < ns2->nodeNr;j++) {
4795 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004796 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004797 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004798 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004799 continue;
4800 if (inf && strict)
4801 ret = (val1 < values2[j]);
4802 else if (inf && !strict)
4803 ret = (val1 <= values2[j]);
4804 else if (!inf && strict)
4805 ret = (val1 > values2[j]);
4806 else if (!inf && !strict)
4807 ret = (val1 >= values2[j]);
4808 if (ret)
4809 break;
4810 }
4811 if (ret)
4812 break;
4813 init = 1;
4814 }
4815 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004816 xmlXPathFreeObject(arg1);
4817 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004818 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004819}
4820
4821/**
4822 * xmlXPathCompareNodeSetValue:
4823 * @ctxt: the XPath Parser context
4824 * @inf: less than (1) or greater than (0)
4825 * @strict: is the comparison strict
4826 * @arg: the node set
4827 * @val: the value
4828 *
4829 * Implement the compare operation between a nodeset and a value
4830 * @ns < @val (1, 1, ...
4831 * @ns <= @val (1, 0, ...
4832 * @ns > @val (0, 1, ...
4833 * @ns >= @val (0, 0, ...
4834 *
4835 * If one object to be compared is a node-set and the other is a boolean,
4836 * then the comparison will be true if and only if the result of performing
4837 * the comparison on the boolean and on the result of converting
4838 * the node-set to a boolean using the boolean function is true.
4839 *
4840 * Returns 0 or 1 depending on the results of the test.
4841 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004842static int
Owen Taylor3473f882001-02-23 17:55:21 +00004843xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4844 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4845 if ((val == NULL) || (arg == NULL) ||
4846 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4847 return(0);
4848
4849 switch(val->type) {
4850 case XPATH_NUMBER:
4851 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4852 case XPATH_NODESET:
4853 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004854 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004855 case XPATH_STRING:
4856 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4857 case XPATH_BOOLEAN:
4858 valuePush(ctxt, arg);
4859 xmlXPathBooleanFunction(ctxt, 1);
4860 valuePush(ctxt, val);
4861 return(xmlXPathCompareValues(ctxt, inf, strict));
4862 default:
4863 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004864 }
4865 return(0);
4866}
4867
4868/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004869 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004870 * @arg: the nodeset object argument
4871 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004872 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004873 *
4874 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4875 * If one object to be compared is a node-set and the other is a string,
4876 * then the comparison will be true if and only if there is a node in
4877 * the node-set such that the result of performing the comparison on the
4878 * string-value of the node and the other string is true.
4879 *
4880 * Returns 0 or 1 depending on the results of the test.
4881 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004882static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004883xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004884{
Owen Taylor3473f882001-02-23 17:55:21 +00004885 int i;
4886 xmlNodeSetPtr ns;
4887 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004888 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004889
4890 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004891 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4892 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004893 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004894 /*
4895 * A NULL nodeset compared with a string is always false
4896 * (since there is no node equal, and no node not equal)
4897 */
4898 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004899 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004900 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004901 for (i = 0; i < ns->nodeNr; i++) {
4902 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4903 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4904 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4905 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004906 if (neq)
4907 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004908 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004909 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4910 if (neq)
4911 continue;
4912 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004913 } else if (neq) {
4914 if (str2 != NULL)
4915 xmlFree(str2);
4916 return (1);
4917 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004918 if (str2 != NULL)
4919 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004920 } else if (neq)
4921 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004922 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004923 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004924}
4925
4926/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004927 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004928 * @arg: the nodeset object argument
4929 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004930 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004931 *
4932 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4933 * If one object to be compared is a node-set and the other is a number,
4934 * then the comparison will be true if and only if there is a node in
4935 * the node-set such that the result of performing the comparison on the
4936 * number to be compared and on the result of converting the string-value
4937 * of that node to a number using the number function is true.
4938 *
4939 * Returns 0 or 1 depending on the results of the test.
4940 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004941static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004942xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4943 xmlXPathObjectPtr arg, double f, int neq) {
4944 int i, ret=0;
4945 xmlNodeSetPtr ns;
4946 xmlChar *str2;
4947 xmlXPathObjectPtr val;
4948 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004949
4950 if ((arg == NULL) ||
4951 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4952 return(0);
4953
William M. Brack0c022ad2002-07-12 00:56:01 +00004954 ns = arg->nodesetval;
4955 if (ns != NULL) {
4956 for (i=0;i<ns->nodeNr;i++) {
4957 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4958 if (str2 != NULL) {
4959 valuePush(ctxt, xmlXPathNewString(str2));
4960 xmlFree(str2);
4961 xmlXPathNumberFunction(ctxt, 1);
4962 val = valuePop(ctxt);
4963 v = val->floatval;
4964 xmlXPathFreeObject(val);
4965 if (!xmlXPathIsNaN(v)) {
4966 if ((!neq) && (v==f)) {
4967 ret = 1;
4968 break;
4969 } else if ((neq) && (v!=f)) {
4970 ret = 1;
4971 break;
4972 }
William M. Brack32f0f712005-07-14 07:00:33 +00004973 } else { /* NaN is unequal to any value */
4974 if (neq)
4975 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00004976 }
4977 }
4978 }
4979 }
4980
4981 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004982}
4983
4984
4985/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004986 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004987 * @arg1: first nodeset object argument
4988 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004989 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004990 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004991 * Implement the equal / not equal operation on XPath nodesets:
4992 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004993 * If both objects to be compared are node-sets, then the comparison
4994 * will be true if and only if there is a node in the first node-set and
4995 * a node in the second node-set such that the result of performing the
4996 * comparison on the string-values of the two nodes is true.
4997 *
4998 * (needless to say, this is a costly operation)
4999 *
5000 * Returns 0 or 1 depending on the results of the test.
5001 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005002static int
William M. Brack0c022ad2002-07-12 00:56:01 +00005003xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00005004 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005005 unsigned int *hashs1;
5006 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00005007 xmlChar **values1;
5008 xmlChar **values2;
5009 int ret = 0;
5010 xmlNodeSetPtr ns1;
5011 xmlNodeSetPtr ns2;
5012
5013 if ((arg1 == NULL) ||
5014 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5015 return(0);
5016 if ((arg2 == NULL) ||
5017 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5018 return(0);
5019
5020 ns1 = arg1->nodesetval;
5021 ns2 = arg2->nodesetval;
5022
Daniel Veillard911f49a2001-04-07 15:39:35 +00005023 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00005024 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005025 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00005026 return(0);
5027
5028 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00005029 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00005030 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005031 if (neq == 0)
5032 for (i = 0;i < ns1->nodeNr;i++)
5033 for (j = 0;j < ns2->nodeNr;j++)
5034 if (ns1->nodeTab[i] == ns2->nodeTab[j])
5035 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005036
5037 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005038 if (values1 == NULL) {
5039 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005040 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005041 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005042 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5043 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005044 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00005045 xmlFree(values1);
5046 return(0);
5047 }
Owen Taylor3473f882001-02-23 17:55:21 +00005048 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5049 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5050 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005051 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00005052 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 xmlFree(values1);
5054 return(0);
5055 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005056 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5057 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005058 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00005059 xmlFree(hashs1);
5060 xmlFree(values1);
5061 xmlFree(values2);
5062 return(0);
5063 }
Owen Taylor3473f882001-02-23 17:55:21 +00005064 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5065 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005066 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005067 for (j = 0;j < ns2->nodeNr;j++) {
5068 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005069 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00005070 if (hashs1[i] != hashs2[j]) {
5071 if (neq) {
5072 ret = 1;
5073 break;
5074 }
5075 }
5076 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005077 if (values1[i] == NULL)
5078 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5079 if (values2[j] == NULL)
5080 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00005081 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005082 if (ret)
5083 break;
5084 }
Owen Taylor3473f882001-02-23 17:55:21 +00005085 }
5086 if (ret)
5087 break;
5088 }
5089 for (i = 0;i < ns1->nodeNr;i++)
5090 if (values1[i] != NULL)
5091 xmlFree(values1[i]);
5092 for (j = 0;j < ns2->nodeNr;j++)
5093 if (values2[j] != NULL)
5094 xmlFree(values2[j]);
5095 xmlFree(values1);
5096 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005097 xmlFree(hashs1);
5098 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00005099 return(ret);
5100}
5101
William M. Brack0c022ad2002-07-12 00:56:01 +00005102static int
5103xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5104 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00005105 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00005106 /*
5107 *At this point we are assured neither arg1 nor arg2
5108 *is a nodeset, so we can just pick the appropriate routine.
5109 */
Owen Taylor3473f882001-02-23 17:55:21 +00005110 switch (arg1->type) {
5111 case XPATH_UNDEFINED:
5112#ifdef DEBUG_EXPR
5113 xmlGenericError(xmlGenericErrorContext,
5114 "Equal: undefined\n");
5115#endif
5116 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005117 case XPATH_BOOLEAN:
5118 switch (arg2->type) {
5119 case XPATH_UNDEFINED:
5120#ifdef DEBUG_EXPR
5121 xmlGenericError(xmlGenericErrorContext,
5122 "Equal: undefined\n");
5123#endif
5124 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005125 case XPATH_BOOLEAN:
5126#ifdef DEBUG_EXPR
5127 xmlGenericError(xmlGenericErrorContext,
5128 "Equal: %d boolean %d \n",
5129 arg1->boolval, arg2->boolval);
5130#endif
5131 ret = (arg1->boolval == arg2->boolval);
5132 break;
5133 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00005134 ret = (arg1->boolval ==
5135 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00005136 break;
5137 case XPATH_STRING:
5138 if ((arg2->stringval == NULL) ||
5139 (arg2->stringval[0] == 0)) ret = 0;
5140 else
5141 ret = 1;
5142 ret = (arg1->boolval == ret);
5143 break;
5144 case XPATH_USERS:
5145 case XPATH_POINT:
5146 case XPATH_RANGE:
5147 case XPATH_LOCATIONSET:
5148 TODO
5149 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005150 case XPATH_NODESET:
5151 case XPATH_XSLT_TREE:
5152 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005153 }
5154 break;
5155 case XPATH_NUMBER:
5156 switch (arg2->type) {
5157 case XPATH_UNDEFINED:
5158#ifdef DEBUG_EXPR
5159 xmlGenericError(xmlGenericErrorContext,
5160 "Equal: undefined\n");
5161#endif
5162 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005163 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00005164 ret = (arg2->boolval==
5165 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00005166 break;
5167 case XPATH_STRING:
5168 valuePush(ctxt, arg2);
5169 xmlXPathNumberFunction(ctxt, 1);
5170 arg2 = valuePop(ctxt);
5171 /* no break on purpose */
5172 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005173 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00005174 if (xmlXPathIsNaN(arg1->floatval) ||
5175 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00005176 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005177 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5178 if (xmlXPathIsInf(arg2->floatval) == 1)
5179 ret = 1;
5180 else
5181 ret = 0;
5182 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5183 if (xmlXPathIsInf(arg2->floatval) == -1)
5184 ret = 1;
5185 else
5186 ret = 0;
5187 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5188 if (xmlXPathIsInf(arg1->floatval) == 1)
5189 ret = 1;
5190 else
5191 ret = 0;
5192 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5193 if (xmlXPathIsInf(arg1->floatval) == -1)
5194 ret = 1;
5195 else
5196 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005197 } else {
5198 ret = (arg1->floatval == arg2->floatval);
5199 }
Owen Taylor3473f882001-02-23 17:55:21 +00005200 break;
5201 case XPATH_USERS:
5202 case XPATH_POINT:
5203 case XPATH_RANGE:
5204 case XPATH_LOCATIONSET:
5205 TODO
5206 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005207 case XPATH_NODESET:
5208 case XPATH_XSLT_TREE:
5209 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005210 }
5211 break;
5212 case XPATH_STRING:
5213 switch (arg2->type) {
5214 case XPATH_UNDEFINED:
5215#ifdef DEBUG_EXPR
5216 xmlGenericError(xmlGenericErrorContext,
5217 "Equal: undefined\n");
5218#endif
5219 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005220 case XPATH_BOOLEAN:
5221 if ((arg1->stringval == NULL) ||
5222 (arg1->stringval[0] == 0)) ret = 0;
5223 else
5224 ret = 1;
5225 ret = (arg2->boolval == ret);
5226 break;
5227 case XPATH_STRING:
5228 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5229 break;
5230 case XPATH_NUMBER:
5231 valuePush(ctxt, arg1);
5232 xmlXPathNumberFunction(ctxt, 1);
5233 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005234 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00005235 if (xmlXPathIsNaN(arg1->floatval) ||
5236 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00005237 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005238 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5239 if (xmlXPathIsInf(arg2->floatval) == 1)
5240 ret = 1;
5241 else
5242 ret = 0;
5243 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5244 if (xmlXPathIsInf(arg2->floatval) == -1)
5245 ret = 1;
5246 else
5247 ret = 0;
5248 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5249 if (xmlXPathIsInf(arg1->floatval) == 1)
5250 ret = 1;
5251 else
5252 ret = 0;
5253 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5254 if (xmlXPathIsInf(arg1->floatval) == -1)
5255 ret = 1;
5256 else
5257 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005258 } else {
5259 ret = (arg1->floatval == arg2->floatval);
5260 }
Owen Taylor3473f882001-02-23 17:55:21 +00005261 break;
5262 case XPATH_USERS:
5263 case XPATH_POINT:
5264 case XPATH_RANGE:
5265 case XPATH_LOCATIONSET:
5266 TODO
5267 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005268 case XPATH_NODESET:
5269 case XPATH_XSLT_TREE:
5270 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005271 }
5272 break;
5273 case XPATH_USERS:
5274 case XPATH_POINT:
5275 case XPATH_RANGE:
5276 case XPATH_LOCATIONSET:
5277 TODO
5278 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005279 case XPATH_NODESET:
5280 case XPATH_XSLT_TREE:
5281 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005282 }
5283 xmlXPathFreeObject(arg1);
5284 xmlXPathFreeObject(arg2);
5285 return(ret);
5286}
5287
William M. Brack0c022ad2002-07-12 00:56:01 +00005288/**
5289 * xmlXPathEqualValues:
5290 * @ctxt: the XPath Parser context
5291 *
5292 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5293 *
5294 * Returns 0 or 1 depending on the results of the test.
5295 */
5296int
5297xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5298 xmlXPathObjectPtr arg1, arg2, argtmp;
5299 int ret = 0;
5300
Daniel Veillard6128c012004-11-08 17:16:15 +00005301 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005302 arg2 = valuePop(ctxt);
5303 arg1 = valuePop(ctxt);
5304 if ((arg1 == NULL) || (arg2 == NULL)) {
5305 if (arg1 != NULL)
5306 xmlXPathFreeObject(arg1);
5307 else
5308 xmlXPathFreeObject(arg2);
5309 XP_ERROR0(XPATH_INVALID_OPERAND);
5310 }
5311
5312 if (arg1 == arg2) {
5313#ifdef DEBUG_EXPR
5314 xmlGenericError(xmlGenericErrorContext,
5315 "Equal: by pointer\n");
5316#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005317 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005318 return(1);
5319 }
5320
5321 /*
5322 *If either argument is a nodeset, it's a 'special case'
5323 */
5324 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5325 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5326 /*
5327 *Hack it to assure arg1 is the nodeset
5328 */
5329 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5330 argtmp = arg2;
5331 arg2 = arg1;
5332 arg1 = argtmp;
5333 }
5334 switch (arg2->type) {
5335 case XPATH_UNDEFINED:
5336#ifdef DEBUG_EXPR
5337 xmlGenericError(xmlGenericErrorContext,
5338 "Equal: undefined\n");
5339#endif
5340 break;
5341 case XPATH_NODESET:
5342 case XPATH_XSLT_TREE:
5343 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
5344 break;
5345 case XPATH_BOOLEAN:
5346 if ((arg1->nodesetval == NULL) ||
5347 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5348 else
5349 ret = 1;
5350 ret = (ret == arg2->boolval);
5351 break;
5352 case XPATH_NUMBER:
5353 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5354 break;
5355 case XPATH_STRING:
5356 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
5357 break;
5358 case XPATH_USERS:
5359 case XPATH_POINT:
5360 case XPATH_RANGE:
5361 case XPATH_LOCATIONSET:
5362 TODO
5363 break;
5364 }
5365 xmlXPathFreeObject(arg1);
5366 xmlXPathFreeObject(arg2);
5367 return(ret);
5368 }
5369
5370 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5371}
5372
5373/**
5374 * xmlXPathNotEqualValues:
5375 * @ctxt: the XPath Parser context
5376 *
5377 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5378 *
5379 * Returns 0 or 1 depending on the results of the test.
5380 */
5381int
5382xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
5383 xmlXPathObjectPtr arg1, arg2, argtmp;
5384 int ret = 0;
5385
Daniel Veillard6128c012004-11-08 17:16:15 +00005386 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005387 arg2 = valuePop(ctxt);
5388 arg1 = valuePop(ctxt);
5389 if ((arg1 == NULL) || (arg2 == NULL)) {
5390 if (arg1 != NULL)
5391 xmlXPathFreeObject(arg1);
5392 else
5393 xmlXPathFreeObject(arg2);
5394 XP_ERROR0(XPATH_INVALID_OPERAND);
5395 }
5396
5397 if (arg1 == arg2) {
5398#ifdef DEBUG_EXPR
5399 xmlGenericError(xmlGenericErrorContext,
5400 "NotEqual: by pointer\n");
5401#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005402 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005403 return(0);
5404 }
5405
5406 /*
5407 *If either argument is a nodeset, it's a 'special case'
5408 */
5409 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5410 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5411 /*
5412 *Hack it to assure arg1 is the nodeset
5413 */
5414 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5415 argtmp = arg2;
5416 arg2 = arg1;
5417 arg1 = argtmp;
5418 }
5419 switch (arg2->type) {
5420 case XPATH_UNDEFINED:
5421#ifdef DEBUG_EXPR
5422 xmlGenericError(xmlGenericErrorContext,
5423 "NotEqual: undefined\n");
5424#endif
5425 break;
5426 case XPATH_NODESET:
5427 case XPATH_XSLT_TREE:
5428 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5429 break;
5430 case XPATH_BOOLEAN:
5431 if ((arg1->nodesetval == NULL) ||
5432 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5433 else
5434 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005435 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005436 break;
5437 case XPATH_NUMBER:
5438 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5439 break;
5440 case XPATH_STRING:
5441 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5442 break;
5443 case XPATH_USERS:
5444 case XPATH_POINT:
5445 case XPATH_RANGE:
5446 case XPATH_LOCATIONSET:
5447 TODO
5448 break;
5449 }
5450 xmlXPathFreeObject(arg1);
5451 xmlXPathFreeObject(arg2);
5452 return(ret);
5453 }
5454
5455 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5456}
Owen Taylor3473f882001-02-23 17:55:21 +00005457
5458/**
5459 * xmlXPathCompareValues:
5460 * @ctxt: the XPath Parser context
5461 * @inf: less than (1) or greater than (0)
5462 * @strict: is the comparison strict
5463 *
5464 * Implement the compare operation on XPath objects:
5465 * @arg1 < @arg2 (1, 1, ...
5466 * @arg1 <= @arg2 (1, 0, ...
5467 * @arg1 > @arg2 (0, 1, ...
5468 * @arg1 >= @arg2 (0, 0, ...
5469 *
5470 * When neither object to be compared is a node-set and the operator is
5471 * <=, <, >=, >, then the objects are compared by converted both objects
5472 * to numbers and comparing the numbers according to IEEE 754. The <
5473 * comparison will be true if and only if the first number is less than the
5474 * second number. The <= comparison will be true if and only if the first
5475 * number is less than or equal to the second number. The > comparison
5476 * will be true if and only if the first number is greater than the second
5477 * number. The >= comparison will be true if and only if the first number
5478 * is greater than or equal to the second number.
5479 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005480 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005481 */
5482int
5483xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005484 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005485 xmlXPathObjectPtr arg1, arg2;
5486
Daniel Veillard6128c012004-11-08 17:16:15 +00005487 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005488 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005489 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005490 if ((arg1 == NULL) || (arg2 == NULL)) {
5491 if (arg1 != NULL)
5492 xmlXPathFreeObject(arg1);
5493 else
5494 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005495 XP_ERROR0(XPATH_INVALID_OPERAND);
5496 }
5497
William M. Brack0c022ad2002-07-12 00:56:01 +00005498 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5499 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00005500 /*
5501 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5502 * are not freed from within this routine; they will be freed from the
5503 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5504 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005505 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5506 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005507 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005508 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005509 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005510 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5511 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005512 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005513 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5514 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005515 }
5516 }
5517 return(ret);
5518 }
5519
5520 if (arg1->type != XPATH_NUMBER) {
5521 valuePush(ctxt, arg1);
5522 xmlXPathNumberFunction(ctxt, 1);
5523 arg1 = valuePop(ctxt);
5524 }
5525 if (arg1->type != XPATH_NUMBER) {
5526 xmlXPathFreeObject(arg1);
5527 xmlXPathFreeObject(arg2);
5528 XP_ERROR0(XPATH_INVALID_OPERAND);
5529 }
5530 if (arg2->type != XPATH_NUMBER) {
5531 valuePush(ctxt, arg2);
5532 xmlXPathNumberFunction(ctxt, 1);
5533 arg2 = valuePop(ctxt);
5534 }
5535 if (arg2->type != XPATH_NUMBER) {
5536 xmlXPathFreeObject(arg1);
5537 xmlXPathFreeObject(arg2);
5538 XP_ERROR0(XPATH_INVALID_OPERAND);
5539 }
5540 /*
5541 * Add tests for infinity and nan
5542 * => feedback on 3.4 for Inf and NaN
5543 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005544 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005545 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005546 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005547 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005548 arg1i=xmlXPathIsInf(arg1->floatval);
5549 arg2i=xmlXPathIsInf(arg2->floatval);
5550 if (inf && strict) {
5551 if ((arg1i == -1 && arg2i != -1) ||
5552 (arg2i == 1 && arg1i != 1)) {
5553 ret = 1;
5554 } else if (arg1i == 0 && arg2i == 0) {
5555 ret = (arg1->floatval < arg2->floatval);
5556 } else {
5557 ret = 0;
5558 }
5559 }
5560 else if (inf && !strict) {
5561 if (arg1i == -1 || arg2i == 1) {
5562 ret = 1;
5563 } else if (arg1i == 0 && arg2i == 0) {
5564 ret = (arg1->floatval <= arg2->floatval);
5565 } else {
5566 ret = 0;
5567 }
5568 }
5569 else if (!inf && strict) {
5570 if ((arg1i == 1 && arg2i != 1) ||
5571 (arg2i == -1 && arg1i != -1)) {
5572 ret = 1;
5573 } else if (arg1i == 0 && arg2i == 0) {
5574 ret = (arg1->floatval > arg2->floatval);
5575 } else {
5576 ret = 0;
5577 }
5578 }
5579 else if (!inf && !strict) {
5580 if (arg1i == 1 || arg2i == -1) {
5581 ret = 1;
5582 } else if (arg1i == 0 && arg2i == 0) {
5583 ret = (arg1->floatval >= arg2->floatval);
5584 } else {
5585 ret = 0;
5586 }
5587 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005588 }
Owen Taylor3473f882001-02-23 17:55:21 +00005589 xmlXPathFreeObject(arg1);
5590 xmlXPathFreeObject(arg2);
5591 return(ret);
5592}
5593
5594/**
5595 * xmlXPathValueFlipSign:
5596 * @ctxt: the XPath Parser context
5597 *
5598 * Implement the unary - operation on an XPath object
5599 * The numeric operators convert their operands to numbers as if
5600 * by calling the number function.
5601 */
5602void
5603xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005604 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005605 CAST_TO_NUMBER;
5606 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005607 if (xmlXPathIsNaN(ctxt->value->floatval))
5608 ctxt->value->floatval=xmlXPathNAN;
5609 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5610 ctxt->value->floatval=xmlXPathNINF;
5611 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5612 ctxt->value->floatval=xmlXPathPINF;
5613 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005614 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5615 ctxt->value->floatval = xmlXPathNZERO;
5616 else
5617 ctxt->value->floatval = 0;
5618 }
5619 else
5620 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005621}
5622
5623/**
5624 * xmlXPathAddValues:
5625 * @ctxt: the XPath Parser context
5626 *
5627 * Implement the add operation on XPath objects:
5628 * The numeric operators convert their operands to numbers as if
5629 * by calling the number function.
5630 */
5631void
5632xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5633 xmlXPathObjectPtr arg;
5634 double val;
5635
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005636 arg = valuePop(ctxt);
5637 if (arg == NULL)
5638 XP_ERROR(XPATH_INVALID_OPERAND);
5639 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005640 xmlXPathFreeObject(arg);
5641
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005642 CAST_TO_NUMBER;
5643 CHECK_TYPE(XPATH_NUMBER);
5644 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005645}
5646
5647/**
5648 * xmlXPathSubValues:
5649 * @ctxt: the XPath Parser context
5650 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005651 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005652 * The numeric operators convert their operands to numbers as if
5653 * by calling the number function.
5654 */
5655void
5656xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5657 xmlXPathObjectPtr arg;
5658 double val;
5659
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005660 arg = valuePop(ctxt);
5661 if (arg == NULL)
5662 XP_ERROR(XPATH_INVALID_OPERAND);
5663 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005664 xmlXPathFreeObject(arg);
5665
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005666 CAST_TO_NUMBER;
5667 CHECK_TYPE(XPATH_NUMBER);
5668 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005669}
5670
5671/**
5672 * xmlXPathMultValues:
5673 * @ctxt: the XPath Parser context
5674 *
5675 * Implement the multiply operation on XPath objects:
5676 * The numeric operators convert their operands to numbers as if
5677 * by calling the number function.
5678 */
5679void
5680xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5681 xmlXPathObjectPtr arg;
5682 double val;
5683
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005684 arg = valuePop(ctxt);
5685 if (arg == NULL)
5686 XP_ERROR(XPATH_INVALID_OPERAND);
5687 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005688 xmlXPathFreeObject(arg);
5689
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005690 CAST_TO_NUMBER;
5691 CHECK_TYPE(XPATH_NUMBER);
5692 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005693}
5694
5695/**
5696 * xmlXPathDivValues:
5697 * @ctxt: the XPath Parser context
5698 *
5699 * Implement the div operation on XPath objects @arg1 / @arg2:
5700 * The numeric operators convert their operands to numbers as if
5701 * by calling the number function.
5702 */
5703void
5704xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5705 xmlXPathObjectPtr arg;
5706 double val;
5707
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005708 arg = valuePop(ctxt);
5709 if (arg == NULL)
5710 XP_ERROR(XPATH_INVALID_OPERAND);
5711 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005712 xmlXPathFreeObject(arg);
5713
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005714 CAST_TO_NUMBER;
5715 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005716 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5717 ctxt->value->floatval = xmlXPathNAN;
5718 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005719 if (ctxt->value->floatval == 0)
5720 ctxt->value->floatval = xmlXPathNAN;
5721 else if (ctxt->value->floatval > 0)
5722 ctxt->value->floatval = xmlXPathNINF;
5723 else if (ctxt->value->floatval < 0)
5724 ctxt->value->floatval = xmlXPathPINF;
5725 }
5726 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005727 if (ctxt->value->floatval == 0)
5728 ctxt->value->floatval = xmlXPathNAN;
5729 else if (ctxt->value->floatval > 0)
5730 ctxt->value->floatval = xmlXPathPINF;
5731 else if (ctxt->value->floatval < 0)
5732 ctxt->value->floatval = xmlXPathNINF;
5733 } else
5734 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005735}
5736
5737/**
5738 * xmlXPathModValues:
5739 * @ctxt: the XPath Parser context
5740 *
5741 * Implement the mod operation on XPath objects: @arg1 / @arg2
5742 * The numeric operators convert their operands to numbers as if
5743 * by calling the number function.
5744 */
5745void
5746xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5747 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005748 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005749
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005750 arg = valuePop(ctxt);
5751 if (arg == NULL)
5752 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005753 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005754 xmlXPathFreeObject(arg);
5755
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005756 CAST_TO_NUMBER;
5757 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005758 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005759 if (arg2 == 0)
5760 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005761 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005762 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005763 }
Owen Taylor3473f882001-02-23 17:55:21 +00005764}
5765
5766/************************************************************************
5767 * *
5768 * The traversal functions *
5769 * *
5770 ************************************************************************/
5771
Owen Taylor3473f882001-02-23 17:55:21 +00005772/*
5773 * A traversal function enumerates nodes along an axis.
5774 * Initially it must be called with NULL, and it indicates
5775 * termination on the axis by returning NULL.
5776 */
5777typedef xmlNodePtr (*xmlXPathTraversalFunction)
5778 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5779
5780/**
5781 * xmlXPathNextSelf:
5782 * @ctxt: the XPath Parser context
5783 * @cur: the current node in the traversal
5784 *
5785 * Traversal function for the "self" direction
5786 * The self axis contains just the context node itself
5787 *
5788 * Returns the next element following that axis
5789 */
5790xmlNodePtr
5791xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005792 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005793 if (cur == NULL)
5794 return(ctxt->context->node);
5795 return(NULL);
5796}
5797
5798/**
5799 * xmlXPathNextChild:
5800 * @ctxt: the XPath Parser context
5801 * @cur: the current node in the traversal
5802 *
5803 * Traversal function for the "child" direction
5804 * The child axis contains the children of the context node in document order.
5805 *
5806 * Returns the next element following that axis
5807 */
5808xmlNodePtr
5809xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005810 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005811 if (cur == NULL) {
5812 if (ctxt->context->node == NULL) return(NULL);
5813 switch (ctxt->context->node->type) {
5814 case XML_ELEMENT_NODE:
5815 case XML_TEXT_NODE:
5816 case XML_CDATA_SECTION_NODE:
5817 case XML_ENTITY_REF_NODE:
5818 case XML_ENTITY_NODE:
5819 case XML_PI_NODE:
5820 case XML_COMMENT_NODE:
5821 case XML_NOTATION_NODE:
5822 case XML_DTD_NODE:
5823 return(ctxt->context->node->children);
5824 case XML_DOCUMENT_NODE:
5825 case XML_DOCUMENT_TYPE_NODE:
5826 case XML_DOCUMENT_FRAG_NODE:
5827 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005828#ifdef LIBXML_DOCB_ENABLED
5829 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005830#endif
5831 return(((xmlDocPtr) ctxt->context->node)->children);
5832 case XML_ELEMENT_DECL:
5833 case XML_ATTRIBUTE_DECL:
5834 case XML_ENTITY_DECL:
5835 case XML_ATTRIBUTE_NODE:
5836 case XML_NAMESPACE_DECL:
5837 case XML_XINCLUDE_START:
5838 case XML_XINCLUDE_END:
5839 return(NULL);
5840 }
5841 return(NULL);
5842 }
5843 if ((cur->type == XML_DOCUMENT_NODE) ||
5844 (cur->type == XML_HTML_DOCUMENT_NODE))
5845 return(NULL);
5846 return(cur->next);
5847}
5848
5849/**
5850 * xmlXPathNextDescendant:
5851 * @ctxt: the XPath Parser context
5852 * @cur: the current node in the traversal
5853 *
5854 * Traversal function for the "descendant" direction
5855 * the descendant axis contains the descendants of the context node in document
5856 * order; a descendant is a child or a child of a child and so on.
5857 *
5858 * Returns the next element following that axis
5859 */
5860xmlNodePtr
5861xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005862 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005863 if (cur == NULL) {
5864 if (ctxt->context->node == NULL)
5865 return(NULL);
5866 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5867 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5868 return(NULL);
5869
5870 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5871 return(ctxt->context->doc->children);
5872 return(ctxt->context->node->children);
5873 }
5874
Daniel Veillard567e1b42001-08-01 15:53:47 +00005875 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005876 /*
5877 * Do not descend on entities declarations
5878 */
5879 if (cur->children->type != XML_ENTITY_DECL) {
5880 cur = cur->children;
5881 /*
5882 * Skip DTDs
5883 */
5884 if (cur->type != XML_DTD_NODE)
5885 return(cur);
5886 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005887 }
5888
5889 if (cur == ctxt->context->node) return(NULL);
5890
Daniel Veillard68e9e742002-11-16 15:35:11 +00005891 while (cur->next != NULL) {
5892 cur = cur->next;
5893 if ((cur->type != XML_ENTITY_DECL) &&
5894 (cur->type != XML_DTD_NODE))
5895 return(cur);
5896 }
Owen Taylor3473f882001-02-23 17:55:21 +00005897
5898 do {
5899 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00005900 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00005901 if (cur == ctxt->context->node) return(NULL);
5902 if (cur->next != NULL) {
5903 cur = cur->next;
5904 return(cur);
5905 }
5906 } while (cur != NULL);
5907 return(cur);
5908}
5909
5910/**
5911 * xmlXPathNextDescendantOrSelf:
5912 * @ctxt: the XPath Parser context
5913 * @cur: the current node in the traversal
5914 *
5915 * Traversal function for the "descendant-or-self" direction
5916 * the descendant-or-self axis contains the context node and the descendants
5917 * of the context node in document order; thus the context node is the first
5918 * node on the axis, and the first child of the context node is the second node
5919 * on the axis
5920 *
5921 * Returns the next element following that axis
5922 */
5923xmlNodePtr
5924xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005925 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005926 if (cur == NULL) {
5927 if (ctxt->context->node == NULL)
5928 return(NULL);
5929 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5930 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5931 return(NULL);
5932 return(ctxt->context->node);
5933 }
5934
5935 return(xmlXPathNextDescendant(ctxt, cur));
5936}
5937
5938/**
5939 * xmlXPathNextParent:
5940 * @ctxt: the XPath Parser context
5941 * @cur: the current node in the traversal
5942 *
5943 * Traversal function for the "parent" direction
5944 * The parent axis contains the parent of the context node, if there is one.
5945 *
5946 * Returns the next element following that axis
5947 */
5948xmlNodePtr
5949xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005950 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005951 /*
5952 * the parent of an attribute or namespace node is the element
5953 * to which the attribute or namespace node is attached
5954 * Namespace handling !!!
5955 */
5956 if (cur == NULL) {
5957 if (ctxt->context->node == NULL) return(NULL);
5958 switch (ctxt->context->node->type) {
5959 case XML_ELEMENT_NODE:
5960 case XML_TEXT_NODE:
5961 case XML_CDATA_SECTION_NODE:
5962 case XML_ENTITY_REF_NODE:
5963 case XML_ENTITY_NODE:
5964 case XML_PI_NODE:
5965 case XML_COMMENT_NODE:
5966 case XML_NOTATION_NODE:
5967 case XML_DTD_NODE:
5968 case XML_ELEMENT_DECL:
5969 case XML_ATTRIBUTE_DECL:
5970 case XML_XINCLUDE_START:
5971 case XML_XINCLUDE_END:
5972 case XML_ENTITY_DECL:
5973 if (ctxt->context->node->parent == NULL)
5974 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005975 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005976 ((ctxt->context->node->parent->name[0] == ' ') ||
5977 (xmlStrEqual(ctxt->context->node->parent->name,
5978 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005979 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005980 return(ctxt->context->node->parent);
5981 case XML_ATTRIBUTE_NODE: {
5982 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5983
5984 return(att->parent);
5985 }
5986 case XML_DOCUMENT_NODE:
5987 case XML_DOCUMENT_TYPE_NODE:
5988 case XML_DOCUMENT_FRAG_NODE:
5989 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005990#ifdef LIBXML_DOCB_ENABLED
5991 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005992#endif
5993 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005994 case XML_NAMESPACE_DECL: {
5995 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5996
5997 if ((ns->next != NULL) &&
5998 (ns->next->type != XML_NAMESPACE_DECL))
5999 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00006000 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006001 }
Owen Taylor3473f882001-02-23 17:55:21 +00006002 }
6003 }
6004 return(NULL);
6005}
6006
6007/**
6008 * xmlXPathNextAncestor:
6009 * @ctxt: the XPath Parser context
6010 * @cur: the current node in the traversal
6011 *
6012 * Traversal function for the "ancestor" direction
6013 * the ancestor axis contains the ancestors of the context node; the ancestors
6014 * of the context node consist of the parent of context node and the parent's
6015 * parent and so on; the nodes are ordered in reverse document order; thus the
6016 * parent is the first node on the axis, and the parent's parent is the second
6017 * node on the axis
6018 *
6019 * Returns the next element following that axis
6020 */
6021xmlNodePtr
6022xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006023 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006024 /*
6025 * the parent of an attribute or namespace node is the element
6026 * to which the attribute or namespace node is attached
6027 * !!!!!!!!!!!!!
6028 */
6029 if (cur == NULL) {
6030 if (ctxt->context->node == NULL) return(NULL);
6031 switch (ctxt->context->node->type) {
6032 case XML_ELEMENT_NODE:
6033 case XML_TEXT_NODE:
6034 case XML_CDATA_SECTION_NODE:
6035 case XML_ENTITY_REF_NODE:
6036 case XML_ENTITY_NODE:
6037 case XML_PI_NODE:
6038 case XML_COMMENT_NODE:
6039 case XML_DTD_NODE:
6040 case XML_ELEMENT_DECL:
6041 case XML_ATTRIBUTE_DECL:
6042 case XML_ENTITY_DECL:
6043 case XML_NOTATION_NODE:
6044 case XML_XINCLUDE_START:
6045 case XML_XINCLUDE_END:
6046 if (ctxt->context->node->parent == NULL)
6047 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006048 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00006049 ((ctxt->context->node->parent->name[0] == ' ') ||
6050 (xmlStrEqual(ctxt->context->node->parent->name,
6051 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006052 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006053 return(ctxt->context->node->parent);
6054 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006055 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00006056
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006057 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00006058 }
6059 case XML_DOCUMENT_NODE:
6060 case XML_DOCUMENT_TYPE_NODE:
6061 case XML_DOCUMENT_FRAG_NODE:
6062 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00006063#ifdef LIBXML_DOCB_ENABLED
6064 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00006065#endif
6066 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006067 case XML_NAMESPACE_DECL: {
6068 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6069
6070 if ((ns->next != NULL) &&
6071 (ns->next->type != XML_NAMESPACE_DECL))
6072 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00006073 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00006074 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006075 }
Owen Taylor3473f882001-02-23 17:55:21 +00006076 }
6077 return(NULL);
6078 }
6079 if (cur == ctxt->context->doc->children)
6080 return((xmlNodePtr) ctxt->context->doc);
6081 if (cur == (xmlNodePtr) ctxt->context->doc)
6082 return(NULL);
6083 switch (cur->type) {
6084 case XML_ELEMENT_NODE:
6085 case XML_TEXT_NODE:
6086 case XML_CDATA_SECTION_NODE:
6087 case XML_ENTITY_REF_NODE:
6088 case XML_ENTITY_NODE:
6089 case XML_PI_NODE:
6090 case XML_COMMENT_NODE:
6091 case XML_NOTATION_NODE:
6092 case XML_DTD_NODE:
6093 case XML_ELEMENT_DECL:
6094 case XML_ATTRIBUTE_DECL:
6095 case XML_ENTITY_DECL:
6096 case XML_XINCLUDE_START:
6097 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006098 if (cur->parent == NULL)
6099 return(NULL);
6100 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00006101 ((cur->parent->name[0] == ' ') ||
6102 (xmlStrEqual(cur->parent->name,
6103 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006104 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006105 return(cur->parent);
6106 case XML_ATTRIBUTE_NODE: {
6107 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6108
6109 return(att->parent);
6110 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00006111 case XML_NAMESPACE_DECL: {
6112 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6113
6114 if ((ns->next != NULL) &&
6115 (ns->next->type != XML_NAMESPACE_DECL))
6116 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00006117 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00006118 return(NULL);
6119 }
Owen Taylor3473f882001-02-23 17:55:21 +00006120 case XML_DOCUMENT_NODE:
6121 case XML_DOCUMENT_TYPE_NODE:
6122 case XML_DOCUMENT_FRAG_NODE:
6123 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00006124#ifdef LIBXML_DOCB_ENABLED
6125 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00006126#endif
6127 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006128 }
6129 return(NULL);
6130}
6131
6132/**
6133 * xmlXPathNextAncestorOrSelf:
6134 * @ctxt: the XPath Parser context
6135 * @cur: the current node in the traversal
6136 *
6137 * Traversal function for the "ancestor-or-self" direction
6138 * he ancestor-or-self axis contains the context node and ancestors of
6139 * the context node in reverse document order; thus the context node is
6140 * the first node on the axis, and the context node's parent the second;
6141 * parent here is defined the same as with the parent axis.
6142 *
6143 * Returns the next element following that axis
6144 */
6145xmlNodePtr
6146xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006147 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006148 if (cur == NULL)
6149 return(ctxt->context->node);
6150 return(xmlXPathNextAncestor(ctxt, cur));
6151}
6152
6153/**
6154 * xmlXPathNextFollowingSibling:
6155 * @ctxt: the XPath Parser context
6156 * @cur: the current node in the traversal
6157 *
6158 * Traversal function for the "following-sibling" direction
6159 * The following-sibling axis contains the following siblings of the context
6160 * node in document order.
6161 *
6162 * Returns the next element following that axis
6163 */
6164xmlNodePtr
6165xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006166 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006167 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6168 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6169 return(NULL);
6170 if (cur == (xmlNodePtr) ctxt->context->doc)
6171 return(NULL);
6172 if (cur == NULL)
6173 return(ctxt->context->node->next);
6174 return(cur->next);
6175}
6176
6177/**
6178 * xmlXPathNextPrecedingSibling:
6179 * @ctxt: the XPath Parser context
6180 * @cur: the current node in the traversal
6181 *
6182 * Traversal function for the "preceding-sibling" direction
6183 * The preceding-sibling axis contains the preceding siblings of the context
6184 * node in reverse document order; the first preceding sibling is first on the
6185 * axis; the sibling preceding that node is the second on the axis and so on.
6186 *
6187 * Returns the next element following that axis
6188 */
6189xmlNodePtr
6190xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006191 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006192 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6193 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6194 return(NULL);
6195 if (cur == (xmlNodePtr) ctxt->context->doc)
6196 return(NULL);
6197 if (cur == NULL)
6198 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006199 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6200 cur = cur->prev;
6201 if (cur == NULL)
6202 return(ctxt->context->node->prev);
6203 }
Owen Taylor3473f882001-02-23 17:55:21 +00006204 return(cur->prev);
6205}
6206
6207/**
6208 * xmlXPathNextFollowing:
6209 * @ctxt: the XPath Parser context
6210 * @cur: the current node in the traversal
6211 *
6212 * Traversal function for the "following" direction
6213 * The following axis contains all nodes in the same document as the context
6214 * node that are after the context node in document order, excluding any
6215 * descendants and excluding attribute nodes and namespace nodes; the nodes
6216 * are ordered in document order
6217 *
6218 * Returns the next element following that axis
6219 */
6220xmlNodePtr
6221xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006222 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006223 if (cur != NULL && cur->children != NULL)
6224 return cur->children ;
6225 if (cur == NULL) cur = ctxt->context->node;
6226 if (cur == NULL) return(NULL) ; /* ERROR */
6227 if (cur->next != NULL) return(cur->next) ;
6228 do {
6229 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00006230 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00006231 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6232 if (cur->next != NULL) return(cur->next);
6233 } while (cur != NULL);
6234 return(cur);
6235}
6236
6237/*
6238 * xmlXPathIsAncestor:
6239 * @ancestor: the ancestor node
6240 * @node: the current node
6241 *
6242 * Check that @ancestor is a @node's ancestor
6243 *
6244 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
6245 */
6246static int
6247xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6248 if ((ancestor == NULL) || (node == NULL)) return(0);
6249 /* nodes need to be in the same document */
6250 if (ancestor->doc != node->doc) return(0);
6251 /* avoid searching if ancestor or node is the root node */
6252 if (ancestor == (xmlNodePtr) node->doc) return(1);
6253 if (node == (xmlNodePtr) ancestor->doc) return(0);
6254 while (node->parent != NULL) {
6255 if (node->parent == ancestor)
6256 return(1);
6257 node = node->parent;
6258 }
6259 return(0);
6260}
6261
6262/**
6263 * xmlXPathNextPreceding:
6264 * @ctxt: the XPath Parser context
6265 * @cur: the current node in the traversal
6266 *
6267 * Traversal function for the "preceding" direction
6268 * the preceding axis contains all nodes in the same document as the context
6269 * node that are before the context node in document order, excluding any
6270 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6271 * ordered in reverse document order
6272 *
6273 * Returns the next element following that axis
6274 */
6275xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00006276xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
6277{
Daniel Veillarda82b1822004-11-08 16:24:57 +00006278 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006279 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006280 cur = ctxt->context->node;
6281 if (cur == NULL)
6282 return (NULL);
6283 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6284 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00006285 do {
6286 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006287 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6288 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006289 }
6290
6291 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006292 if (cur == NULL)
6293 return (NULL);
6294 if (cur == ctxt->context->doc->children)
6295 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006296 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00006297 return (cur);
6298}
6299
6300/**
6301 * xmlXPathNextPrecedingInternal:
6302 * @ctxt: the XPath Parser context
6303 * @cur: the current node in the traversal
6304 *
6305 * Traversal function for the "preceding" direction
6306 * the preceding axis contains all nodes in the same document as the context
6307 * node that are before the context node in document order, excluding any
6308 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6309 * ordered in reverse document order
6310 * This is a faster implementation but internal only since it requires a
6311 * state kept in the parser context: ctxt->ancestor.
6312 *
6313 * Returns the next element following that axis
6314 */
6315static xmlNodePtr
6316xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6317 xmlNodePtr cur)
6318{
Daniel Veillarda82b1822004-11-08 16:24:57 +00006319 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006320 if (cur == NULL) {
6321 cur = ctxt->context->node;
6322 if (cur == NULL)
6323 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00006324 if (cur->type == XML_NAMESPACE_DECL)
6325 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006326 ctxt->ancestor = cur->parent;
6327 }
6328 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6329 cur = cur->prev;
6330 while (cur->prev == NULL) {
6331 cur = cur->parent;
6332 if (cur == NULL)
6333 return (NULL);
6334 if (cur == ctxt->context->doc->children)
6335 return (NULL);
6336 if (cur != ctxt->ancestor)
6337 return (cur);
6338 ctxt->ancestor = cur->parent;
6339 }
6340 cur = cur->prev;
6341 while (cur->last != NULL)
6342 cur = cur->last;
6343 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006344}
6345
6346/**
6347 * xmlXPathNextNamespace:
6348 * @ctxt: the XPath Parser context
6349 * @cur: the current attribute in the traversal
6350 *
6351 * Traversal function for the "namespace" direction
6352 * the namespace axis contains the namespace nodes of the context node;
6353 * the order of nodes on this axis is implementation-defined; the axis will
6354 * be empty unless the context node is an element
6355 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00006356 * We keep the XML namespace node at the end of the list.
6357 *
Owen Taylor3473f882001-02-23 17:55:21 +00006358 * Returns the next element following that axis
6359 */
6360xmlNodePtr
6361xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006362 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006363 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00006364 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006365 if (ctxt->context->tmpNsList != NULL)
6366 xmlFree(ctxt->context->tmpNsList);
6367 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00006368 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006369 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00006370 if (ctxt->context->tmpNsList != NULL) {
6371 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6372 ctxt->context->tmpNsNr++;
6373 }
6374 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00006375 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006376 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00006377 if (ctxt->context->tmpNsNr > 0) {
6378 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6379 } else {
6380 if (ctxt->context->tmpNsList != NULL)
6381 xmlFree(ctxt->context->tmpNsList);
6382 ctxt->context->tmpNsList = NULL;
6383 return(NULL);
6384 }
Owen Taylor3473f882001-02-23 17:55:21 +00006385}
6386
6387/**
6388 * xmlXPathNextAttribute:
6389 * @ctxt: the XPath Parser context
6390 * @cur: the current attribute in the traversal
6391 *
6392 * Traversal function for the "attribute" direction
6393 * TODO: support DTD inherited default attributes
6394 *
6395 * Returns the next element following that axis
6396 */
6397xmlNodePtr
6398xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006399 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006400 if (ctxt->context->node == NULL)
6401 return(NULL);
6402 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6403 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006404 if (cur == NULL) {
6405 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6406 return(NULL);
6407 return((xmlNodePtr)ctxt->context->node->properties);
6408 }
6409 return((xmlNodePtr)cur->next);
6410}
6411
6412/************************************************************************
6413 * *
6414 * NodeTest Functions *
6415 * *
6416 ************************************************************************/
6417
Owen Taylor3473f882001-02-23 17:55:21 +00006418#define IS_FUNCTION 200
6419
Owen Taylor3473f882001-02-23 17:55:21 +00006420
6421/************************************************************************
6422 * *
6423 * Implicit tree core function library *
6424 * *
6425 ************************************************************************/
6426
6427/**
6428 * xmlXPathRoot:
6429 * @ctxt: the XPath Parser context
6430 *
6431 * Initialize the context to the root of the document
6432 */
6433void
6434xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006435 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006436 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6437 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6438}
6439
6440/************************************************************************
6441 * *
6442 * The explicit core function library *
6443 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6444 * *
6445 ************************************************************************/
6446
6447
6448/**
6449 * xmlXPathLastFunction:
6450 * @ctxt: the XPath Parser context
6451 * @nargs: the number of arguments
6452 *
6453 * Implement the last() XPath function
6454 * number last()
6455 * The last function returns the number of nodes in the context node list.
6456 */
6457void
6458xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6459 CHECK_ARITY(0);
6460 if (ctxt->context->contextSize >= 0) {
6461 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6462#ifdef DEBUG_EXPR
6463 xmlGenericError(xmlGenericErrorContext,
6464 "last() : %d\n", ctxt->context->contextSize);
6465#endif
6466 } else {
6467 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6468 }
6469}
6470
6471/**
6472 * xmlXPathPositionFunction:
6473 * @ctxt: the XPath Parser context
6474 * @nargs: the number of arguments
6475 *
6476 * Implement the position() XPath function
6477 * number position()
6478 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006479 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006480 * will be equal to last().
6481 */
6482void
6483xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6484 CHECK_ARITY(0);
6485 if (ctxt->context->proximityPosition >= 0) {
6486 valuePush(ctxt,
6487 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6488#ifdef DEBUG_EXPR
6489 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6490 ctxt->context->proximityPosition);
6491#endif
6492 } else {
6493 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6494 }
6495}
6496
6497/**
6498 * xmlXPathCountFunction:
6499 * @ctxt: the XPath Parser context
6500 * @nargs: the number of arguments
6501 *
6502 * Implement the count() XPath function
6503 * number count(node-set)
6504 */
6505void
6506xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6507 xmlXPathObjectPtr cur;
6508
6509 CHECK_ARITY(1);
6510 if ((ctxt->value == NULL) ||
6511 ((ctxt->value->type != XPATH_NODESET) &&
6512 (ctxt->value->type != XPATH_XSLT_TREE)))
6513 XP_ERROR(XPATH_INVALID_TYPE);
6514 cur = valuePop(ctxt);
6515
Daniel Veillard911f49a2001-04-07 15:39:35 +00006516 if ((cur == NULL) || (cur->nodesetval == NULL))
6517 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006518 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006519 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006520 } else {
6521 if ((cur->nodesetval->nodeNr != 1) ||
6522 (cur->nodesetval->nodeTab == NULL)) {
6523 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6524 } else {
6525 xmlNodePtr tmp;
6526 int i = 0;
6527
6528 tmp = cur->nodesetval->nodeTab[0];
6529 if (tmp != NULL) {
6530 tmp = tmp->children;
6531 while (tmp != NULL) {
6532 tmp = tmp->next;
6533 i++;
6534 }
6535 }
6536 valuePush(ctxt, xmlXPathNewFloat((double) i));
6537 }
6538 }
Owen Taylor3473f882001-02-23 17:55:21 +00006539 xmlXPathFreeObject(cur);
6540}
6541
6542/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006543 * xmlXPathGetElementsByIds:
6544 * @doc: the document
6545 * @ids: a whitespace separated list of IDs
6546 *
6547 * Selects elements by their unique ID.
6548 *
6549 * Returns a node-set of selected elements.
6550 */
6551static xmlNodeSetPtr
6552xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6553 xmlNodeSetPtr ret;
6554 const xmlChar *cur = ids;
6555 xmlChar *ID;
6556 xmlAttrPtr attr;
6557 xmlNodePtr elem = NULL;
6558
Daniel Veillard7a985a12003-07-06 17:57:42 +00006559 if (ids == NULL) return(NULL);
6560
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006561 ret = xmlXPathNodeSetCreate(NULL);
6562
William M. Brack76e95df2003-10-18 16:20:14 +00006563 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006564 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006565 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006566 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006567
6568 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006569 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006570 /*
6571 * We used to check the fact that the value passed
6572 * was an NCName, but this generated much troubles for
6573 * me and Aleksey Sanin, people blatantly violated that
6574 * constaint, like Visa3D spec.
6575 * if (xmlValidateNCName(ID, 1) == 0)
6576 */
6577 attr = xmlGetID(doc, ID);
6578 if (attr != NULL) {
6579 if (attr->type == XML_ATTRIBUTE_NODE)
6580 elem = attr->parent;
6581 else if (attr->type == XML_ELEMENT_NODE)
6582 elem = (xmlNodePtr) attr;
6583 else
6584 elem = NULL;
6585 if (elem != NULL)
6586 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006587 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006588 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006589 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006590
William M. Brack76e95df2003-10-18 16:20:14 +00006591 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006592 ids = cur;
6593 }
6594 return(ret);
6595}
6596
6597/**
Owen Taylor3473f882001-02-23 17:55:21 +00006598 * xmlXPathIdFunction:
6599 * @ctxt: the XPath Parser context
6600 * @nargs: the number of arguments
6601 *
6602 * Implement the id() XPath function
6603 * node-set id(object)
6604 * The id function selects elements by their unique ID
6605 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6606 * then the result is the union of the result of applying id to the
6607 * string value of each of the nodes in the argument node-set. When the
6608 * argument to id is of any other type, the argument is converted to a
6609 * string as if by a call to the string function; the string is split
6610 * into a whitespace-separated list of tokens (whitespace is any sequence
6611 * of characters matching the production S); the result is a node-set
6612 * containing the elements in the same document as the context node that
6613 * have a unique ID equal to any of the tokens in the list.
6614 */
6615void
6616xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006617 xmlChar *tokens;
6618 xmlNodeSetPtr ret;
6619 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006620
6621 CHECK_ARITY(1);
6622 obj = valuePop(ctxt);
6623 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006624 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006625 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006626 int i;
6627
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006628 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006629
Daniel Veillard911f49a2001-04-07 15:39:35 +00006630 if (obj->nodesetval != NULL) {
6631 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006632 tokens =
6633 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6634 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6635 ret = xmlXPathNodeSetMerge(ret, ns);
6636 xmlXPathFreeNodeSet(ns);
6637 if (tokens != NULL)
6638 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006639 }
Owen Taylor3473f882001-02-23 17:55:21 +00006640 }
6641
6642 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006643 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006644 return;
6645 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006646 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006647
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006648 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6649 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006650
Owen Taylor3473f882001-02-23 17:55:21 +00006651 xmlXPathFreeObject(obj);
6652 return;
6653}
6654
6655/**
6656 * xmlXPathLocalNameFunction:
6657 * @ctxt: the XPath Parser context
6658 * @nargs: the number of arguments
6659 *
6660 * Implement the local-name() XPath function
6661 * string local-name(node-set?)
6662 * The local-name function returns a string containing the local part
6663 * of the name of the node in the argument node-set that is first in
6664 * document order. If the node-set is empty or the first node has no
6665 * name, an empty string is returned. If the argument is omitted it
6666 * defaults to the context node.
6667 */
6668void
6669xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6670 xmlXPathObjectPtr cur;
6671
Daniel Veillarda82b1822004-11-08 16:24:57 +00006672 if (ctxt == NULL) return;
6673
Owen Taylor3473f882001-02-23 17:55:21 +00006674 if (nargs == 0) {
6675 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6676 nargs = 1;
6677 }
6678
6679 CHECK_ARITY(1);
6680 if ((ctxt->value == NULL) ||
6681 ((ctxt->value->type != XPATH_NODESET) &&
6682 (ctxt->value->type != XPATH_XSLT_TREE)))
6683 XP_ERROR(XPATH_INVALID_TYPE);
6684 cur = valuePop(ctxt);
6685
Daniel Veillard911f49a2001-04-07 15:39:35 +00006686 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006687 valuePush(ctxt, xmlXPathNewCString(""));
6688 } else {
6689 int i = 0; /* Should be first in document order !!!!! */
6690 switch (cur->nodesetval->nodeTab[i]->type) {
6691 case XML_ELEMENT_NODE:
6692 case XML_ATTRIBUTE_NODE:
6693 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006694 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6695 valuePush(ctxt, xmlXPathNewCString(""));
6696 else
6697 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006698 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6699 break;
6700 case XML_NAMESPACE_DECL:
6701 valuePush(ctxt, xmlXPathNewString(
6702 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6703 break;
6704 default:
6705 valuePush(ctxt, xmlXPathNewCString(""));
6706 }
6707 }
6708 xmlXPathFreeObject(cur);
6709}
6710
6711/**
6712 * xmlXPathNamespaceURIFunction:
6713 * @ctxt: the XPath Parser context
6714 * @nargs: the number of arguments
6715 *
6716 * Implement the namespace-uri() XPath function
6717 * string namespace-uri(node-set?)
6718 * The namespace-uri function returns a string containing the
6719 * namespace URI of the expanded name of the node in the argument
6720 * node-set that is first in document order. If the node-set is empty,
6721 * the first node has no name, or the expanded name has no namespace
6722 * URI, an empty string is returned. If the argument is omitted it
6723 * defaults to the context node.
6724 */
6725void
6726xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6727 xmlXPathObjectPtr cur;
6728
Daniel Veillarda82b1822004-11-08 16:24:57 +00006729 if (ctxt == NULL) return;
6730
Owen Taylor3473f882001-02-23 17:55:21 +00006731 if (nargs == 0) {
6732 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6733 nargs = 1;
6734 }
6735 CHECK_ARITY(1);
6736 if ((ctxt->value == NULL) ||
6737 ((ctxt->value->type != XPATH_NODESET) &&
6738 (ctxt->value->type != XPATH_XSLT_TREE)))
6739 XP_ERROR(XPATH_INVALID_TYPE);
6740 cur = valuePop(ctxt);
6741
Daniel Veillard911f49a2001-04-07 15:39:35 +00006742 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006743 valuePush(ctxt, xmlXPathNewCString(""));
6744 } else {
6745 int i = 0; /* Should be first in document order !!!!! */
6746 switch (cur->nodesetval->nodeTab[i]->type) {
6747 case XML_ELEMENT_NODE:
6748 case XML_ATTRIBUTE_NODE:
6749 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6750 valuePush(ctxt, xmlXPathNewCString(""));
6751 else
6752 valuePush(ctxt, xmlXPathNewString(
6753 cur->nodesetval->nodeTab[i]->ns->href));
6754 break;
6755 default:
6756 valuePush(ctxt, xmlXPathNewCString(""));
6757 }
6758 }
6759 xmlXPathFreeObject(cur);
6760}
6761
6762/**
6763 * xmlXPathNameFunction:
6764 * @ctxt: the XPath Parser context
6765 * @nargs: the number of arguments
6766 *
6767 * Implement the name() XPath function
6768 * string name(node-set?)
6769 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006770 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006771 * order. The QName must represent the name with respect to the namespace
6772 * declarations in effect on the node whose name is being represented.
6773 * Typically, this will be the form in which the name occurred in the XML
6774 * source. This need not be the case if there are namespace declarations
6775 * in effect on the node that associate multiple prefixes with the same
6776 * namespace. However, an implementation may include information about
6777 * the original prefix in its representation of nodes; in this case, an
6778 * implementation can ensure that the returned string is always the same
6779 * as the QName used in the XML source. If the argument it omitted it
6780 * defaults to the context node.
6781 * Libxml keep the original prefix so the "real qualified name" used is
6782 * returned.
6783 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006784static void
Daniel Veillard04383752001-07-08 14:27:15 +00006785xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6786{
Owen Taylor3473f882001-02-23 17:55:21 +00006787 xmlXPathObjectPtr cur;
6788
6789 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006790 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6791 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006792 }
6793
6794 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006795 if ((ctxt->value == NULL) ||
6796 ((ctxt->value->type != XPATH_NODESET) &&
6797 (ctxt->value->type != XPATH_XSLT_TREE)))
6798 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006799 cur = valuePop(ctxt);
6800
Daniel Veillard911f49a2001-04-07 15:39:35 +00006801 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006802 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006803 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006804 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006805
Daniel Veillard04383752001-07-08 14:27:15 +00006806 switch (cur->nodesetval->nodeTab[i]->type) {
6807 case XML_ELEMENT_NODE:
6808 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006809 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6810 valuePush(ctxt, xmlXPathNewCString(""));
6811 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6812 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006813 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006814 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006815
Daniel Veillard652d8a92003-02-04 19:28:49 +00006816 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006817 xmlChar *fullname;
6818
6819 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6820 cur->nodesetval->nodeTab[i]->ns->prefix,
6821 NULL, 0);
6822 if (fullname == cur->nodesetval->nodeTab[i]->name)
6823 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6824 if (fullname == NULL) {
6825 XP_ERROR(XPATH_MEMORY_ERROR);
6826 }
6827 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006828 }
6829 break;
6830 default:
6831 valuePush(ctxt,
6832 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6833 xmlXPathLocalNameFunction(ctxt, 1);
6834 }
Owen Taylor3473f882001-02-23 17:55:21 +00006835 }
6836 xmlXPathFreeObject(cur);
6837}
6838
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006839
6840/**
Owen Taylor3473f882001-02-23 17:55:21 +00006841 * xmlXPathStringFunction:
6842 * @ctxt: the XPath Parser context
6843 * @nargs: the number of arguments
6844 *
6845 * Implement the string() XPath function
6846 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006847 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006848 * - A node-set is converted to a string by returning the value of
6849 * the node in the node-set that is first in document order.
6850 * If the node-set is empty, an empty string is returned.
6851 * - A number is converted to a string as follows
6852 * + NaN is converted to the string NaN
6853 * + positive zero is converted to the string 0
6854 * + negative zero is converted to the string 0
6855 * + positive infinity is converted to the string Infinity
6856 * + negative infinity is converted to the string -Infinity
6857 * + if the number is an integer, the number is represented in
6858 * decimal form as a Number with no decimal point and no leading
6859 * zeros, preceded by a minus sign (-) if the number is negative
6860 * + otherwise, the number is represented in decimal form as a
6861 * Number including a decimal point with at least one digit
6862 * before the decimal point and at least one digit after the
6863 * decimal point, preceded by a minus sign (-) if the number
6864 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006865 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006866 * before the decimal point; beyond the one required digit
6867 * after the decimal point there must be as many, but only as
6868 * many, more digits as are needed to uniquely distinguish the
6869 * number from all other IEEE 754 numeric values.
6870 * - The boolean false value is converted to the string false.
6871 * The boolean true value is converted to the string true.
6872 *
6873 * If the argument is omitted, it defaults to a node-set with the
6874 * context node as its only member.
6875 */
6876void
6877xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6878 xmlXPathObjectPtr cur;
6879
Daniel Veillarda82b1822004-11-08 16:24:57 +00006880 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006881 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006882 valuePush(ctxt,
6883 xmlXPathWrapString(
6884 xmlXPathCastNodeToString(ctxt->context->node)));
6885 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006886 }
6887
6888 CHECK_ARITY(1);
6889 cur = valuePop(ctxt);
6890 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006891 cur = xmlXPathConvertString(cur);
6892 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006893}
6894
6895/**
6896 * xmlXPathStringLengthFunction:
6897 * @ctxt: the XPath Parser context
6898 * @nargs: the number of arguments
6899 *
6900 * Implement the string-length() XPath function
6901 * number string-length(string?)
6902 * The string-length returns the number of characters in the string
6903 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6904 * the context node converted to a string, in other words the value
6905 * of the context node.
6906 */
6907void
6908xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6909 xmlXPathObjectPtr cur;
6910
6911 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006912 if ((ctxt == NULL) || (ctxt->context == NULL))
6913 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006914 if (ctxt->context->node == NULL) {
6915 valuePush(ctxt, xmlXPathNewFloat(0));
6916 } else {
6917 xmlChar *content;
6918
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006919 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006920 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006921 xmlFree(content);
6922 }
6923 return;
6924 }
6925 CHECK_ARITY(1);
6926 CAST_TO_STRING;
6927 CHECK_TYPE(XPATH_STRING);
6928 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006929 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006930 xmlXPathFreeObject(cur);
6931}
6932
6933/**
6934 * xmlXPathConcatFunction:
6935 * @ctxt: the XPath Parser context
6936 * @nargs: the number of arguments
6937 *
6938 * Implement the concat() XPath function
6939 * string concat(string, string, string*)
6940 * The concat function returns the concatenation of its arguments.
6941 */
6942void
6943xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6944 xmlXPathObjectPtr cur, newobj;
6945 xmlChar *tmp;
6946
Daniel Veillarda82b1822004-11-08 16:24:57 +00006947 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006948 if (nargs < 2) {
6949 CHECK_ARITY(2);
6950 }
6951
6952 CAST_TO_STRING;
6953 cur = valuePop(ctxt);
6954 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6955 xmlXPathFreeObject(cur);
6956 return;
6957 }
6958 nargs--;
6959
6960 while (nargs > 0) {
6961 CAST_TO_STRING;
6962 newobj = valuePop(ctxt);
6963 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6964 xmlXPathFreeObject(newobj);
6965 xmlXPathFreeObject(cur);
6966 XP_ERROR(XPATH_INVALID_TYPE);
6967 }
6968 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6969 newobj->stringval = cur->stringval;
6970 cur->stringval = tmp;
6971
6972 xmlXPathFreeObject(newobj);
6973 nargs--;
6974 }
6975 valuePush(ctxt, cur);
6976}
6977
6978/**
6979 * xmlXPathContainsFunction:
6980 * @ctxt: the XPath Parser context
6981 * @nargs: the number of arguments
6982 *
6983 * Implement the contains() XPath function
6984 * boolean contains(string, string)
6985 * The contains function returns true if the first argument string
6986 * contains the second argument string, and otherwise returns false.
6987 */
6988void
6989xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6990 xmlXPathObjectPtr hay, needle;
6991
6992 CHECK_ARITY(2);
6993 CAST_TO_STRING;
6994 CHECK_TYPE(XPATH_STRING);
6995 needle = valuePop(ctxt);
6996 CAST_TO_STRING;
6997 hay = valuePop(ctxt);
6998 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6999 xmlXPathFreeObject(hay);
7000 xmlXPathFreeObject(needle);
7001 XP_ERROR(XPATH_INVALID_TYPE);
7002 }
7003 if (xmlStrstr(hay->stringval, needle->stringval))
7004 valuePush(ctxt, xmlXPathNewBoolean(1));
7005 else
7006 valuePush(ctxt, xmlXPathNewBoolean(0));
7007 xmlXPathFreeObject(hay);
7008 xmlXPathFreeObject(needle);
7009}
7010
7011/**
7012 * xmlXPathStartsWithFunction:
7013 * @ctxt: the XPath Parser context
7014 * @nargs: the number of arguments
7015 *
7016 * Implement the starts-with() XPath function
7017 * boolean starts-with(string, string)
7018 * The starts-with function returns true if the first argument string
7019 * starts with the second argument string, and otherwise returns false.
7020 */
7021void
7022xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7023 xmlXPathObjectPtr hay, needle;
7024 int n;
7025
7026 CHECK_ARITY(2);
7027 CAST_TO_STRING;
7028 CHECK_TYPE(XPATH_STRING);
7029 needle = valuePop(ctxt);
7030 CAST_TO_STRING;
7031 hay = valuePop(ctxt);
7032 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7033 xmlXPathFreeObject(hay);
7034 xmlXPathFreeObject(needle);
7035 XP_ERROR(XPATH_INVALID_TYPE);
7036 }
7037 n = xmlStrlen(needle->stringval);
7038 if (xmlStrncmp(hay->stringval, needle->stringval, n))
7039 valuePush(ctxt, xmlXPathNewBoolean(0));
7040 else
7041 valuePush(ctxt, xmlXPathNewBoolean(1));
7042 xmlXPathFreeObject(hay);
7043 xmlXPathFreeObject(needle);
7044}
7045
7046/**
7047 * xmlXPathSubstringFunction:
7048 * @ctxt: the XPath Parser context
7049 * @nargs: the number of arguments
7050 *
7051 * Implement the substring() XPath function
7052 * string substring(string, number, number?)
7053 * The substring function returns the substring of the first argument
7054 * starting at the position specified in the second argument with
7055 * length specified in the third argument. For example,
7056 * substring("12345",2,3) returns "234". If the third argument is not
7057 * specified, it returns the substring starting at the position specified
7058 * in the second argument and continuing to the end of the string. For
7059 * example, substring("12345",2) returns "2345". More precisely, each
7060 * character in the string (see [3.6 Strings]) is considered to have a
7061 * numeric position: the position of the first character is 1, the position
7062 * of the second character is 2 and so on. The returned substring contains
7063 * those characters for which the position of the character is greater than
7064 * or equal to the second argument and, if the third argument is specified,
7065 * less than the sum of the second and third arguments; the comparisons
7066 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7067 * - substring("12345", 1.5, 2.6) returns "234"
7068 * - substring("12345", 0, 3) returns "12"
7069 * - substring("12345", 0 div 0, 3) returns ""
7070 * - substring("12345", 1, 0 div 0) returns ""
7071 * - substring("12345", -42, 1 div 0) returns "12345"
7072 * - substring("12345", -1 div 0, 1 div 0) returns ""
7073 */
7074void
7075xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7076 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007077 double le=0, in;
7078 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00007079 xmlChar *ret;
7080
Owen Taylor3473f882001-02-23 17:55:21 +00007081 if (nargs < 2) {
7082 CHECK_ARITY(2);
7083 }
7084 if (nargs > 3) {
7085 CHECK_ARITY(3);
7086 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007087 /*
7088 * take care of possible last (position) argument
7089 */
Owen Taylor3473f882001-02-23 17:55:21 +00007090 if (nargs == 3) {
7091 CAST_TO_NUMBER;
7092 CHECK_TYPE(XPATH_NUMBER);
7093 len = valuePop(ctxt);
7094 le = len->floatval;
7095 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00007096 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007097
Owen Taylor3473f882001-02-23 17:55:21 +00007098 CAST_TO_NUMBER;
7099 CHECK_TYPE(XPATH_NUMBER);
7100 start = valuePop(ctxt);
7101 in = start->floatval;
7102 xmlXPathFreeObject(start);
7103 CAST_TO_STRING;
7104 CHECK_TYPE(XPATH_STRING);
7105 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00007106 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00007107
Daniel Veillard97ac1312001-05-30 19:14:17 +00007108 /*
7109 * If last pos not present, calculate last position
7110 */
Daniel Veillard9e412302002-06-10 15:59:44 +00007111 if (nargs != 3) {
7112 le = (double)m;
7113 if (in < 1.0)
7114 in = 1.0;
7115 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007116
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007117 /* Need to check for the special cases where either
7118 * the index is NaN, the length is NaN, or both
7119 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00007120 */
Daniel Veillard9e412302002-06-10 15:59:44 +00007121 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007122 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00007123 * To meet the requirements of the spec, the arguments
7124 * must be converted to integer format before
7125 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007126 *
Daniel Veillard9e412302002-06-10 15:59:44 +00007127 * First we go to integer form, rounding up
7128 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007129 */
7130 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00007131 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00007132
Daniel Veillard9e412302002-06-10 15:59:44 +00007133 if (xmlXPathIsInf(le) == 1) {
7134 l = m;
7135 if (i < 1)
7136 i = 1;
7137 }
7138 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
7139 l = 0;
7140 else {
7141 l = (int) le;
7142 if (((double)l)+0.5 <= le) l++;
7143 }
7144
7145 /* Now we normalize inidices */
7146 i -= 1;
7147 l += i;
7148 if (i < 0)
7149 i = 0;
7150 if (l > m)
7151 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00007152
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007153 /* number of chars to copy */
7154 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00007155
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007156 ret = xmlUTF8Strsub(str->stringval, i, l);
7157 }
7158 else {
7159 ret = NULL;
7160 }
7161
Owen Taylor3473f882001-02-23 17:55:21 +00007162 if (ret == NULL)
7163 valuePush(ctxt, xmlXPathNewCString(""));
7164 else {
7165 valuePush(ctxt, xmlXPathNewString(ret));
7166 xmlFree(ret);
7167 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007168
Owen Taylor3473f882001-02-23 17:55:21 +00007169 xmlXPathFreeObject(str);
7170}
7171
7172/**
7173 * xmlXPathSubstringBeforeFunction:
7174 * @ctxt: the XPath Parser context
7175 * @nargs: the number of arguments
7176 *
7177 * Implement the substring-before() XPath function
7178 * string substring-before(string, string)
7179 * The substring-before function returns the substring of the first
7180 * argument string that precedes the first occurrence of the second
7181 * argument string in the first argument string, or the empty string
7182 * if the first argument string does not contain the second argument
7183 * string. For example, substring-before("1999/04/01","/") returns 1999.
7184 */
7185void
7186xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7187 xmlXPathObjectPtr str;
7188 xmlXPathObjectPtr find;
7189 xmlBufferPtr target;
7190 const xmlChar *point;
7191 int offset;
7192
7193 CHECK_ARITY(2);
7194 CAST_TO_STRING;
7195 find = valuePop(ctxt);
7196 CAST_TO_STRING;
7197 str = valuePop(ctxt);
7198
7199 target = xmlBufferCreate();
7200 if (target) {
7201 point = xmlStrstr(str->stringval, find->stringval);
7202 if (point) {
7203 offset = (int)(point - str->stringval);
7204 xmlBufferAdd(target, str->stringval, offset);
7205 }
7206 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7207 xmlBufferFree(target);
7208 }
7209
7210 xmlXPathFreeObject(str);
7211 xmlXPathFreeObject(find);
7212}
7213
7214/**
7215 * xmlXPathSubstringAfterFunction:
7216 * @ctxt: the XPath Parser context
7217 * @nargs: the number of arguments
7218 *
7219 * Implement the substring-after() XPath function
7220 * string substring-after(string, string)
7221 * The substring-after function returns the substring of the first
7222 * argument string that follows the first occurrence of the second
7223 * argument string in the first argument string, or the empty stringi
7224 * if the first argument string does not contain the second argument
7225 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7226 * and substring-after("1999/04/01","19") returns 99/04/01.
7227 */
7228void
7229xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7230 xmlXPathObjectPtr str;
7231 xmlXPathObjectPtr find;
7232 xmlBufferPtr target;
7233 const xmlChar *point;
7234 int offset;
7235
7236 CHECK_ARITY(2);
7237 CAST_TO_STRING;
7238 find = valuePop(ctxt);
7239 CAST_TO_STRING;
7240 str = valuePop(ctxt);
7241
7242 target = xmlBufferCreate();
7243 if (target) {
7244 point = xmlStrstr(str->stringval, find->stringval);
7245 if (point) {
7246 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
7247 xmlBufferAdd(target, &str->stringval[offset],
7248 xmlStrlen(str->stringval) - offset);
7249 }
7250 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7251 xmlBufferFree(target);
7252 }
7253
7254 xmlXPathFreeObject(str);
7255 xmlXPathFreeObject(find);
7256}
7257
7258/**
7259 * xmlXPathNormalizeFunction:
7260 * @ctxt: the XPath Parser context
7261 * @nargs: the number of arguments
7262 *
7263 * Implement the normalize-space() XPath function
7264 * string normalize-space(string?)
7265 * The normalize-space function returns the argument string with white
7266 * space normalized by stripping leading and trailing whitespace
7267 * and replacing sequences of whitespace characters by a single
7268 * space. Whitespace characters are the same allowed by the S production
7269 * in XML. If the argument is omitted, it defaults to the context
7270 * node converted to a string, in other words the value of the context node.
7271 */
7272void
7273xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7274 xmlXPathObjectPtr obj = NULL;
7275 xmlChar *source = NULL;
7276 xmlBufferPtr target;
7277 xmlChar blank;
7278
Daniel Veillarda82b1822004-11-08 16:24:57 +00007279 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007280 if (nargs == 0) {
7281 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007282 valuePush(ctxt,
7283 xmlXPathWrapString(
7284 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00007285 nargs = 1;
7286 }
7287
7288 CHECK_ARITY(1);
7289 CAST_TO_STRING;
7290 CHECK_TYPE(XPATH_STRING);
7291 obj = valuePop(ctxt);
7292 source = obj->stringval;
7293
7294 target = xmlBufferCreate();
7295 if (target && source) {
7296
7297 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00007298 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00007299 source++;
7300
7301 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7302 blank = 0;
7303 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00007304 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00007305 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00007306 } else {
7307 if (blank) {
7308 xmlBufferAdd(target, &blank, 1);
7309 blank = 0;
7310 }
7311 xmlBufferAdd(target, source, 1);
7312 }
7313 source++;
7314 }
7315
7316 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7317 xmlBufferFree(target);
7318 }
7319 xmlXPathFreeObject(obj);
7320}
7321
7322/**
7323 * xmlXPathTranslateFunction:
7324 * @ctxt: the XPath Parser context
7325 * @nargs: the number of arguments
7326 *
7327 * Implement the translate() XPath function
7328 * string translate(string, string, string)
7329 * The translate function returns the first argument string with
7330 * occurrences of characters in the second argument string replaced
7331 * by the character at the corresponding position in the third argument
7332 * string. For example, translate("bar","abc","ABC") returns the string
7333 * BAr. If there is a character in the second argument string with no
7334 * character at a corresponding position in the third argument string
7335 * (because the second argument string is longer than the third argument
7336 * string), then occurrences of that character in the first argument
7337 * string are removed. For example, translate("--aaa--","abc-","ABC")
7338 * returns "AAA". If a character occurs more than once in second
7339 * argument string, then the first occurrence determines the replacement
7340 * character. If the third argument string is longer than the second
7341 * argument string, then excess characters are ignored.
7342 */
7343void
7344xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00007345 xmlXPathObjectPtr str;
7346 xmlXPathObjectPtr from;
7347 xmlXPathObjectPtr to;
7348 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007349 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007350 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00007351 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007352 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00007353
Daniel Veillarde043ee12001-04-16 14:08:07 +00007354 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00007355
Daniel Veillarde043ee12001-04-16 14:08:07 +00007356 CAST_TO_STRING;
7357 to = valuePop(ctxt);
7358 CAST_TO_STRING;
7359 from = valuePop(ctxt);
7360 CAST_TO_STRING;
7361 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007362
Daniel Veillarde043ee12001-04-16 14:08:07 +00007363 target = xmlBufferCreate();
7364 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00007365 max = xmlUTF8Strlen(to->stringval);
7366 for (cptr = str->stringval; (ch=*cptr); ) {
7367 offset = xmlUTF8Strloc(from->stringval, cptr);
7368 if (offset >= 0) {
7369 if (offset < max) {
7370 point = xmlUTF8Strpos(to->stringval, offset);
7371 if (point)
7372 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
7373 }
7374 } else
7375 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7376
7377 /* Step to next character in input */
7378 cptr++;
7379 if ( ch & 0x80 ) {
7380 /* if not simple ascii, verify proper format */
7381 if ( (ch & 0xc0) != 0xc0 ) {
7382 xmlGenericError(xmlGenericErrorContext,
7383 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7384 break;
7385 }
7386 /* then skip over remaining bytes for this char */
7387 while ( (ch <<= 1) & 0x80 )
7388 if ( (*cptr++ & 0xc0) != 0x80 ) {
7389 xmlGenericError(xmlGenericErrorContext,
7390 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7391 break;
7392 }
7393 if (ch & 0x80) /* must have had error encountered */
7394 break;
7395 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007396 }
Owen Taylor3473f882001-02-23 17:55:21 +00007397 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007398 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7399 xmlBufferFree(target);
7400 xmlXPathFreeObject(str);
7401 xmlXPathFreeObject(from);
7402 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007403}
7404
7405/**
7406 * xmlXPathBooleanFunction:
7407 * @ctxt: the XPath Parser context
7408 * @nargs: the number of arguments
7409 *
7410 * Implement the boolean() XPath function
7411 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007412 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007413 * - a number is true if and only if it is neither positive or
7414 * negative zero nor NaN
7415 * - a node-set is true if and only if it is non-empty
7416 * - a string is true if and only if its length is non-zero
7417 */
7418void
7419xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7420 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007421
7422 CHECK_ARITY(1);
7423 cur = valuePop(ctxt);
7424 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007425 cur = xmlXPathConvertBoolean(cur);
7426 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007427}
7428
7429/**
7430 * xmlXPathNotFunction:
7431 * @ctxt: the XPath Parser context
7432 * @nargs: the number of arguments
7433 *
7434 * Implement the not() XPath function
7435 * boolean not(boolean)
7436 * The not function returns true if its argument is false,
7437 * and false otherwise.
7438 */
7439void
7440xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7441 CHECK_ARITY(1);
7442 CAST_TO_BOOLEAN;
7443 CHECK_TYPE(XPATH_BOOLEAN);
7444 ctxt->value->boolval = ! ctxt->value->boolval;
7445}
7446
7447/**
7448 * xmlXPathTrueFunction:
7449 * @ctxt: the XPath Parser context
7450 * @nargs: the number of arguments
7451 *
7452 * Implement the true() XPath function
7453 * boolean true()
7454 */
7455void
7456xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7457 CHECK_ARITY(0);
7458 valuePush(ctxt, xmlXPathNewBoolean(1));
7459}
7460
7461/**
7462 * xmlXPathFalseFunction:
7463 * @ctxt: the XPath Parser context
7464 * @nargs: the number of arguments
7465 *
7466 * Implement the false() XPath function
7467 * boolean false()
7468 */
7469void
7470xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7471 CHECK_ARITY(0);
7472 valuePush(ctxt, xmlXPathNewBoolean(0));
7473}
7474
7475/**
7476 * xmlXPathLangFunction:
7477 * @ctxt: the XPath Parser context
7478 * @nargs: the number of arguments
7479 *
7480 * Implement the lang() XPath function
7481 * boolean lang(string)
7482 * The lang function returns true or false depending on whether the
7483 * language of the context node as specified by xml:lang attributes
7484 * is the same as or is a sublanguage of the language specified by
7485 * the argument string. The language of the context node is determined
7486 * by the value of the xml:lang attribute on the context node, or, if
7487 * the context node has no xml:lang attribute, by the value of the
7488 * xml:lang attribute on the nearest ancestor of the context node that
7489 * has an xml:lang attribute. If there is no such attribute, then lang
7490 * returns false. If there is such an attribute, then lang returns
7491 * true if the attribute value is equal to the argument ignoring case,
7492 * or if there is some suffix starting with - such that the attribute
7493 * value is equal to the argument ignoring that suffix of the attribute
7494 * value and ignoring case.
7495 */
7496void
7497xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007498 xmlXPathObjectPtr val = NULL;
7499 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007500 const xmlChar *lang;
7501 int ret = 0;
7502 int i;
7503
7504 CHECK_ARITY(1);
7505 CAST_TO_STRING;
7506 CHECK_TYPE(XPATH_STRING);
7507 val = valuePop(ctxt);
7508 lang = val->stringval;
7509 theLang = xmlNodeGetLang(ctxt->context->node);
7510 if ((theLang != NULL) && (lang != NULL)) {
7511 for (i = 0;lang[i] != 0;i++)
7512 if (toupper(lang[i]) != toupper(theLang[i]))
7513 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007514 if ((theLang[i] == 0) || (theLang[i] == '-'))
7515 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007516 }
7517not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007518 if (theLang != NULL)
7519 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007520 xmlXPathFreeObject(val);
7521 valuePush(ctxt, xmlXPathNewBoolean(ret));
7522}
7523
7524/**
7525 * xmlXPathNumberFunction:
7526 * @ctxt: the XPath Parser context
7527 * @nargs: the number of arguments
7528 *
7529 * Implement the number() XPath function
7530 * number number(object?)
7531 */
7532void
7533xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7534 xmlXPathObjectPtr cur;
7535 double res;
7536
Daniel Veillarda82b1822004-11-08 16:24:57 +00007537 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007538 if (nargs == 0) {
7539 if (ctxt->context->node == NULL) {
7540 valuePush(ctxt, xmlXPathNewFloat(0.0));
7541 } else {
7542 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7543
7544 res = xmlXPathStringEvalNumber(content);
7545 valuePush(ctxt, xmlXPathNewFloat(res));
7546 xmlFree(content);
7547 }
7548 return;
7549 }
7550
7551 CHECK_ARITY(1);
7552 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007553 cur = xmlXPathConvertNumber(cur);
7554 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007555}
7556
7557/**
7558 * xmlXPathSumFunction:
7559 * @ctxt: the XPath Parser context
7560 * @nargs: the number of arguments
7561 *
7562 * Implement the sum() XPath function
7563 * number sum(node-set)
7564 * The sum function returns the sum of the values of the nodes in
7565 * the argument node-set.
7566 */
7567void
7568xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7569 xmlXPathObjectPtr cur;
7570 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007571 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007572
7573 CHECK_ARITY(1);
7574 if ((ctxt->value == NULL) ||
7575 ((ctxt->value->type != XPATH_NODESET) &&
7576 (ctxt->value->type != XPATH_XSLT_TREE)))
7577 XP_ERROR(XPATH_INVALID_TYPE);
7578 cur = valuePop(ctxt);
7579
William M. Brack08171912003-12-29 02:52:11 +00007580 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007581 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7582 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007583 }
7584 }
William M. Brack08171912003-12-29 02:52:11 +00007585 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007586 xmlXPathFreeObject(cur);
7587}
7588
William M. Brack3d426662005-04-19 14:40:28 +00007589/*
7590 * To assure working code on multiple platforms, we want to only depend
7591 * upon the characteristic truncation of converting a floating point value
7592 * to an integer. Unfortunately, because of the different storage sizes
7593 * of our internal floating point value (double) and integer (int), we
7594 * can't directly convert (see bug 301162). This macro is a messy
7595 * 'workaround'
7596 */
7597#define XTRUNC(f, v) \
7598 f = fmod((v), INT_MAX); \
7599 f = (v) - (f) + (double)((int)(f));
7600
Owen Taylor3473f882001-02-23 17:55:21 +00007601/**
7602 * xmlXPathFloorFunction:
7603 * @ctxt: the XPath Parser context
7604 * @nargs: the number of arguments
7605 *
7606 * Implement the floor() XPath function
7607 * number floor(number)
7608 * The floor function returns the largest (closest to positive infinity)
7609 * number that is not greater than the argument and that is an integer.
7610 */
7611void
7612xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007613 double f;
7614
Owen Taylor3473f882001-02-23 17:55:21 +00007615 CHECK_ARITY(1);
7616 CAST_TO_NUMBER;
7617 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007618
William M. Brack3d426662005-04-19 14:40:28 +00007619 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007620 if (f != ctxt->value->floatval) {
7621 if (ctxt->value->floatval > 0)
7622 ctxt->value->floatval = f;
7623 else
7624 ctxt->value->floatval = f - 1;
7625 }
Owen Taylor3473f882001-02-23 17:55:21 +00007626}
7627
7628/**
7629 * xmlXPathCeilingFunction:
7630 * @ctxt: the XPath Parser context
7631 * @nargs: the number of arguments
7632 *
7633 * Implement the ceiling() XPath function
7634 * number ceiling(number)
7635 * The ceiling function returns the smallest (closest to negative infinity)
7636 * number that is not less than the argument and that is an integer.
7637 */
7638void
7639xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7640 double f;
7641
7642 CHECK_ARITY(1);
7643 CAST_TO_NUMBER;
7644 CHECK_TYPE(XPATH_NUMBER);
7645
7646#if 0
7647 ctxt->value->floatval = ceil(ctxt->value->floatval);
7648#else
William M. Brack3d426662005-04-19 14:40:28 +00007649 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007650 if (f != ctxt->value->floatval) {
7651 if (ctxt->value->floatval > 0)
7652 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007653 else {
7654 if (ctxt->value->floatval < 0 && f == 0)
7655 ctxt->value->floatval = xmlXPathNZERO;
7656 else
7657 ctxt->value->floatval = f;
7658 }
7659
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007660 }
Owen Taylor3473f882001-02-23 17:55:21 +00007661#endif
7662}
7663
7664/**
7665 * xmlXPathRoundFunction:
7666 * @ctxt: the XPath Parser context
7667 * @nargs: the number of arguments
7668 *
7669 * Implement the round() XPath function
7670 * number round(number)
7671 * The round function returns the number that is closest to the
7672 * argument and that is an integer. If there are two such numbers,
7673 * then the one that is even is returned.
7674 */
7675void
7676xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7677 double f;
7678
7679 CHECK_ARITY(1);
7680 CAST_TO_NUMBER;
7681 CHECK_TYPE(XPATH_NUMBER);
7682
Daniel Veillardcda96922001-08-21 10:56:31 +00007683 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7684 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7685 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007686 (ctxt->value->floatval == 0.0))
7687 return;
7688
William M. Brack3d426662005-04-19 14:40:28 +00007689 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007690 if (ctxt->value->floatval < 0) {
7691 if (ctxt->value->floatval < f - 0.5)
7692 ctxt->value->floatval = f - 1;
7693 else
7694 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007695 if (ctxt->value->floatval == 0)
7696 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007697 } else {
7698 if (ctxt->value->floatval < f + 0.5)
7699 ctxt->value->floatval = f;
7700 else
7701 ctxt->value->floatval = f + 1;
7702 }
Owen Taylor3473f882001-02-23 17:55:21 +00007703}
7704
7705/************************************************************************
7706 * *
7707 * The Parser *
7708 * *
7709 ************************************************************************/
7710
7711/*
William M. Brack08171912003-12-29 02:52:11 +00007712 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007713 * implementation.
7714 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00007715static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007716static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007717static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007718static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007719static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7720 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007721
7722/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007723 * xmlXPathCurrentChar:
7724 * @ctxt: the XPath parser context
7725 * @cur: pointer to the beginning of the char
7726 * @len: pointer to the length of the char read
7727 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007728 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007729 * bytes in the input buffer.
7730 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007731 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007732 */
7733
7734static int
7735xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7736 unsigned char c;
7737 unsigned int val;
7738 const xmlChar *cur;
7739
7740 if (ctxt == NULL)
7741 return(0);
7742 cur = ctxt->cur;
7743
7744 /*
7745 * We are supposed to handle UTF8, check it's valid
7746 * From rfc2044: encoding of the Unicode values on UTF-8:
7747 *
7748 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7749 * 0000 0000-0000 007F 0xxxxxxx
7750 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7751 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7752 *
7753 * Check for the 0x110000 limit too
7754 */
7755 c = *cur;
7756 if (c & 0x80) {
7757 if ((cur[1] & 0xc0) != 0x80)
7758 goto encoding_error;
7759 if ((c & 0xe0) == 0xe0) {
7760
7761 if ((cur[2] & 0xc0) != 0x80)
7762 goto encoding_error;
7763 if ((c & 0xf0) == 0xf0) {
7764 if (((c & 0xf8) != 0xf0) ||
7765 ((cur[3] & 0xc0) != 0x80))
7766 goto encoding_error;
7767 /* 4-byte code */
7768 *len = 4;
7769 val = (cur[0] & 0x7) << 18;
7770 val |= (cur[1] & 0x3f) << 12;
7771 val |= (cur[2] & 0x3f) << 6;
7772 val |= cur[3] & 0x3f;
7773 } else {
7774 /* 3-byte code */
7775 *len = 3;
7776 val = (cur[0] & 0xf) << 12;
7777 val |= (cur[1] & 0x3f) << 6;
7778 val |= cur[2] & 0x3f;
7779 }
7780 } else {
7781 /* 2-byte code */
7782 *len = 2;
7783 val = (cur[0] & 0x1f) << 6;
7784 val |= cur[1] & 0x3f;
7785 }
7786 if (!IS_CHAR(val)) {
7787 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7788 }
7789 return(val);
7790 } else {
7791 /* 1-byte code */
7792 *len = 1;
7793 return((int) *cur);
7794 }
7795encoding_error:
7796 /*
William M. Brack08171912003-12-29 02:52:11 +00007797 * If we detect an UTF8 error that probably means that the
7798 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007799 * declaration header. Report the error and switch the encoding
7800 * to ISO-Latin-1 (if you don't like this policy, just declare the
7801 * encoding !)
7802 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007803 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007804 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007805}
7806
7807/**
Owen Taylor3473f882001-02-23 17:55:21 +00007808 * xmlXPathParseNCName:
7809 * @ctxt: the XPath Parser context
7810 *
7811 * parse an XML namespace non qualified name.
7812 *
7813 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7814 *
7815 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7816 * CombiningChar | Extender
7817 *
7818 * Returns the namespace name or NULL
7819 */
7820
7821xmlChar *
7822xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007823 const xmlChar *in;
7824 xmlChar *ret;
7825 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007826
Daniel Veillarda82b1822004-11-08 16:24:57 +00007827 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007828 /*
7829 * Accelerator for simple ASCII names
7830 */
7831 in = ctxt->cur;
7832 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7833 ((*in >= 0x41) && (*in <= 0x5A)) ||
7834 (*in == '_')) {
7835 in++;
7836 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7837 ((*in >= 0x41) && (*in <= 0x5A)) ||
7838 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007839 (*in == '_') || (*in == '.') ||
7840 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007841 in++;
7842 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7843 (*in == '[') || (*in == ']') || (*in == ':') ||
7844 (*in == '@') || (*in == '*')) {
7845 count = in - ctxt->cur;
7846 if (count == 0)
7847 return(NULL);
7848 ret = xmlStrndup(ctxt->cur, count);
7849 ctxt->cur = in;
7850 return(ret);
7851 }
7852 }
7853 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007854}
7855
Daniel Veillard2156a562001-04-28 12:24:34 +00007856
Owen Taylor3473f882001-02-23 17:55:21 +00007857/**
7858 * xmlXPathParseQName:
7859 * @ctxt: the XPath Parser context
7860 * @prefix: a xmlChar **
7861 *
7862 * parse an XML qualified name
7863 *
7864 * [NS 5] QName ::= (Prefix ':')? LocalPart
7865 *
7866 * [NS 6] Prefix ::= NCName
7867 *
7868 * [NS 7] LocalPart ::= NCName
7869 *
7870 * Returns the function returns the local part, and prefix is updated
7871 * to get the Prefix if any.
7872 */
7873
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007874static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007875xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7876 xmlChar *ret = NULL;
7877
7878 *prefix = NULL;
7879 ret = xmlXPathParseNCName(ctxt);
7880 if (CUR == ':') {
7881 *prefix = ret;
7882 NEXT;
7883 ret = xmlXPathParseNCName(ctxt);
7884 }
7885 return(ret);
7886}
7887
7888/**
7889 * xmlXPathParseName:
7890 * @ctxt: the XPath Parser context
7891 *
7892 * parse an XML name
7893 *
7894 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7895 * CombiningChar | Extender
7896 *
7897 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7898 *
7899 * Returns the namespace name or NULL
7900 */
7901
7902xmlChar *
7903xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007904 const xmlChar *in;
7905 xmlChar *ret;
7906 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007907
Daniel Veillarda82b1822004-11-08 16:24:57 +00007908 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007909 /*
7910 * Accelerator for simple ASCII names
7911 */
7912 in = ctxt->cur;
7913 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7914 ((*in >= 0x41) && (*in <= 0x5A)) ||
7915 (*in == '_') || (*in == ':')) {
7916 in++;
7917 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7918 ((*in >= 0x41) && (*in <= 0x5A)) ||
7919 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007920 (*in == '_') || (*in == '-') ||
7921 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007922 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007923 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007924 count = in - ctxt->cur;
7925 ret = xmlStrndup(ctxt->cur, count);
7926 ctxt->cur = in;
7927 return(ret);
7928 }
7929 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007930 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007931}
7932
Daniel Veillard61d80a22001-04-27 17:13:01 +00007933static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007934xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007935 xmlChar buf[XML_MAX_NAMELEN + 5];
7936 int len = 0, l;
7937 int c;
7938
7939 /*
7940 * Handler for more complex cases
7941 */
7942 c = CUR_CHAR(l);
7943 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007944 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7945 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007946 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007947 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007948 return(NULL);
7949 }
7950
7951 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7952 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7953 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007954 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007955 (IS_COMBINING(c)) ||
7956 (IS_EXTENDER(c)))) {
7957 COPY_BUF(l,buf,len,c);
7958 NEXTL(l);
7959 c = CUR_CHAR(l);
7960 if (len >= XML_MAX_NAMELEN) {
7961 /*
7962 * Okay someone managed to make a huge name, so he's ready to pay
7963 * for the processing speed.
7964 */
7965 xmlChar *buffer;
7966 int max = len * 2;
7967
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007968 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007969 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007970 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007971 }
7972 memcpy(buffer, buf, len);
7973 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7974 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007975 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007976 (IS_COMBINING(c)) ||
7977 (IS_EXTENDER(c))) {
7978 if (len + 10 > max) {
7979 max *= 2;
7980 buffer = (xmlChar *) xmlRealloc(buffer,
7981 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007982 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007983 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007984 }
7985 }
7986 COPY_BUF(l,buffer,len,c);
7987 NEXTL(l);
7988 c = CUR_CHAR(l);
7989 }
7990 buffer[len] = 0;
7991 return(buffer);
7992 }
7993 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007994 if (len == 0)
7995 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007996 return(xmlStrndup(buf, len));
7997}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007998
7999#define MAX_FRAC 20
8000
William M. Brack372a4452004-02-17 13:09:23 +00008001/*
8002 * These are used as divisors for the fractional part of a number.
8003 * Since the table includes 1.0 (representing '0' fractional digits),
8004 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
8005 */
8006static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00008007 1.0, 10.0, 100.0, 1000.0, 10000.0,
8008 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
8009 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
8010 100000000000000.0,
8011 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00008012 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00008013};
8014
Owen Taylor3473f882001-02-23 17:55:21 +00008015/**
8016 * xmlXPathStringEvalNumber:
8017 * @str: A string to scan
8018 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00008019 * [30a] Float ::= Number ('e' Digits?)?
8020 *
Owen Taylor3473f882001-02-23 17:55:21 +00008021 * [30] Number ::= Digits ('.' Digits?)?
8022 * | '.' Digits
8023 * [31] Digits ::= [0-9]+
8024 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008025 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00008026 * In complement of the Number expression, this function also handles
8027 * negative values : '-' Number.
8028 *
8029 * Returns the double value.
8030 */
8031double
8032xmlXPathStringEvalNumber(const xmlChar *str) {
8033 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00008034 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008035 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008036 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008037 int exponent = 0;
8038 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008039#ifdef __GNUC__
8040 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00008041 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008042#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00008043 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00008044 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008045 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
8046 return(xmlXPathNAN);
8047 }
8048 if (*cur == '-') {
8049 isneg = 1;
8050 cur++;
8051 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00008052
8053#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008054 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00008055 * tmp/temp is a workaround against a gcc compiler bug
8056 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008057 */
Daniel Veillard7b416132002-03-07 08:36:03 +00008058 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008059 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00008060 ret = ret * 10;
8061 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00008062 ok = 1;
8063 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00008064 temp = (double) tmp;
8065 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00008066 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00008067#else
Daniel Veillard7b416132002-03-07 08:36:03 +00008068 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008069 while ((*cur >= '0') && (*cur <= '9')) {
8070 ret = ret * 10 + (*cur - '0');
8071 ok = 1;
8072 cur++;
8073 }
8074#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008075
Owen Taylor3473f882001-02-23 17:55:21 +00008076 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00008077 int v, frac = 0;
8078 double fraction = 0;
8079
Owen Taylor3473f882001-02-23 17:55:21 +00008080 cur++;
8081 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8082 return(xmlXPathNAN);
8083 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00008084 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
8085 v = (*cur - '0');
8086 fraction = fraction * 10 + v;
8087 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008088 cur++;
8089 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00008090 fraction /= my_pow10[frac];
8091 ret = ret + fraction;
8092 while ((*cur >= '0') && (*cur <= '9'))
8093 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008094 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00008095 if ((*cur == 'e') || (*cur == 'E')) {
8096 cur++;
8097 if (*cur == '-') {
8098 is_exponent_negative = 1;
8099 cur++;
William M. Brack99127052004-05-24 02:52:28 +00008100 } else if (*cur == '+') {
8101 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008102 }
8103 while ((*cur >= '0') && (*cur <= '9')) {
8104 exponent = exponent * 10 + (*cur - '0');
8105 cur++;
8106 }
8107 }
William M. Brack76e95df2003-10-18 16:20:14 +00008108 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008109 if (*cur != 0) return(xmlXPathNAN);
8110 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008111 if (is_exponent_negative) exponent = -exponent;
8112 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00008113 return(ret);
8114}
8115
8116/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008117 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00008118 * @ctxt: the XPath Parser context
8119 *
8120 * [30] Number ::= Digits ('.' Digits?)?
8121 * | '.' Digits
8122 * [31] Digits ::= [0-9]+
8123 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008124 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00008125 *
8126 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008127static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008128xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8129{
Owen Taylor3473f882001-02-23 17:55:21 +00008130 double ret = 0.0;
8131 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00008132 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008133 int exponent = 0;
8134 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00008135#ifdef __GNUC__
8136 unsigned long tmp = 0;
8137 double temp;
8138#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008139
8140 CHECK_ERROR;
8141 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8142 XP_ERROR(XPATH_NUMBER_ERROR);
8143 }
Daniel Veillard7b416132002-03-07 08:36:03 +00008144#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008145 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00008146 * tmp/temp is a workaround against a gcc compiler bug
8147 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008148 */
Daniel Veillard7b416132002-03-07 08:36:03 +00008149 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008150 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00008151 ret = ret * 10;
8152 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008153 ok = 1;
8154 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00008155 temp = (double) tmp;
8156 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00008157 }
Daniel Veillard7b416132002-03-07 08:36:03 +00008158#else
8159 ret = 0;
8160 while ((CUR >= '0') && (CUR <= '9')) {
8161 ret = ret * 10 + (CUR - '0');
8162 ok = 1;
8163 NEXT;
8164 }
8165#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008166 if (CUR == '.') {
8167 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008168 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8169 XP_ERROR(XPATH_NUMBER_ERROR);
8170 }
8171 while ((CUR >= '0') && (CUR <= '9')) {
8172 mult /= 10;
8173 ret = ret + (CUR - '0') * mult;
8174 NEXT;
8175 }
Owen Taylor3473f882001-02-23 17:55:21 +00008176 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00008177 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008178 NEXT;
8179 if (CUR == '-') {
8180 is_exponent_negative = 1;
8181 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00008182 } else if (CUR == '+') {
8183 NEXT;
8184 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008185 while ((CUR >= '0') && (CUR <= '9')) {
8186 exponent = exponent * 10 + (CUR - '0');
8187 NEXT;
8188 }
8189 if (is_exponent_negative)
8190 exponent = -exponent;
8191 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00008192 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008193 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008194 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008195}
8196
8197/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008198 * xmlXPathParseLiteral:
8199 * @ctxt: the XPath Parser context
8200 *
8201 * Parse a Literal
8202 *
8203 * [29] Literal ::= '"' [^"]* '"'
8204 * | "'" [^']* "'"
8205 *
8206 * Returns the value found or NULL in case of error
8207 */
8208static xmlChar *
8209xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8210 const xmlChar *q;
8211 xmlChar *ret = NULL;
8212
8213 if (CUR == '"') {
8214 NEXT;
8215 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008216 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008217 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008218 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008219 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008220 } else {
8221 ret = xmlStrndup(q, CUR_PTR - q);
8222 NEXT;
8223 }
8224 } else if (CUR == '\'') {
8225 NEXT;
8226 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008227 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008228 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008229 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008230 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008231 } else {
8232 ret = xmlStrndup(q, CUR_PTR - q);
8233 NEXT;
8234 }
8235 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00008236 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008237 }
8238 return(ret);
8239}
8240
8241/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008242 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00008243 * @ctxt: the XPath Parser context
8244 *
8245 * Parse a Literal and push it on the stack.
8246 *
8247 * [29] Literal ::= '"' [^"]* '"'
8248 * | "'" [^']* "'"
8249 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008250 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00008251 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008252static void
8253xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008254 const xmlChar *q;
8255 xmlChar *ret = NULL;
8256
8257 if (CUR == '"') {
8258 NEXT;
8259 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008260 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00008261 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008262 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00008263 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
8264 } else {
8265 ret = xmlStrndup(q, CUR_PTR - q);
8266 NEXT;
8267 }
8268 } else if (CUR == '\'') {
8269 NEXT;
8270 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008271 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00008272 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008273 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00008274 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
8275 } else {
8276 ret = xmlStrndup(q, CUR_PTR - q);
8277 NEXT;
8278 }
8279 } else {
8280 XP_ERROR(XPATH_START_LITERAL_ERROR);
8281 }
8282 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008283 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
8284 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008285 xmlFree(ret);
8286}
8287
8288/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008289 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00008290 * @ctxt: the XPath Parser context
8291 *
8292 * Parse a VariableReference, evaluate it and push it on the stack.
8293 *
8294 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00008295 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00008296 * of any of the types that are possible for the value of an expression,
8297 * and may also be of additional types not specified here.
8298 *
8299 * Early evaluation is possible since:
8300 * The variable bindings [...] used to evaluate a subexpression are
8301 * always the same as those used to evaluate the containing expression.
8302 *
8303 * [36] VariableReference ::= '$' QName
8304 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008305static void
8306xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008307 xmlChar *name;
8308 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00008309
8310 SKIP_BLANKS;
8311 if (CUR != '$') {
8312 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8313 }
8314 NEXT;
8315 name = xmlXPathParseQName(ctxt, &prefix);
8316 if (name == NULL) {
8317 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8318 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008319 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008320 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
8321 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008322 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00008323 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8324 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
8325 }
Owen Taylor3473f882001-02-23 17:55:21 +00008326}
8327
8328/**
8329 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00008330 * @name: a name string
8331 *
8332 * Is the name given a NodeType one.
8333 *
8334 * [38] NodeType ::= 'comment'
8335 * | 'text'
8336 * | 'processing-instruction'
8337 * | 'node'
8338 *
8339 * Returns 1 if true 0 otherwise
8340 */
8341int
8342xmlXPathIsNodeType(const xmlChar *name) {
8343 if (name == NULL)
8344 return(0);
8345
Daniel Veillard1971ee22002-01-31 20:29:19 +00008346 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00008347 return(1);
8348 if (xmlStrEqual(name, BAD_CAST "text"))
8349 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00008350 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00008351 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00008352 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00008353 return(1);
8354 return(0);
8355}
8356
8357/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008358 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00008359 * @ctxt: the XPath Parser context
8360 *
8361 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8362 * [17] Argument ::= Expr
8363 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008364 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00008365 * pushed on the stack
8366 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008367static void
8368xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008369 xmlChar *name;
8370 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00008371 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008372 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008373
8374 name = xmlXPathParseQName(ctxt, &prefix);
8375 if (name == NULL) {
8376 XP_ERROR(XPATH_EXPR_ERROR);
8377 }
8378 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008379#ifdef DEBUG_EXPR
8380 if (prefix == NULL)
8381 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
8382 name);
8383 else
8384 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
8385 prefix, name);
8386#endif
8387
Owen Taylor3473f882001-02-23 17:55:21 +00008388 if (CUR != '(') {
8389 XP_ERROR(XPATH_EXPR_ERROR);
8390 }
8391 NEXT;
8392 SKIP_BLANKS;
8393
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008394 /*
8395 * Optimization for count(): we don't need the node-set to be sorted.
8396 */
8397 if ((prefix == NULL) && (name[0] == 'c') &&
8398 xmlStrEqual(name, BAD_CAST "count"))
8399 {
8400 sort = 0;
8401 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008402 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00008403 if (CUR != ')') {
8404 while (CUR != 0) {
8405 int op1 = ctxt->comp->last;
8406 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008407 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +00008408 CHECK_ERROR;
8409 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8410 nbargs++;
8411 if (CUR == ')') break;
8412 if (CUR != ',') {
8413 XP_ERROR(XPATH_EXPR_ERROR);
8414 }
8415 NEXT;
8416 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008417 }
Owen Taylor3473f882001-02-23 17:55:21 +00008418 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008419 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8420 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008421 NEXT;
8422 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008423}
8424
8425/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008426 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008427 * @ctxt: the XPath Parser context
8428 *
8429 * [15] PrimaryExpr ::= VariableReference
8430 * | '(' Expr ')'
8431 * | Literal
8432 * | Number
8433 * | FunctionCall
8434 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008435 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008436 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008437static void
8438xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008439 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008440 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008441 else if (CUR == '(') {
8442 NEXT;
8443 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008444 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008445 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008446 if (CUR != ')') {
8447 XP_ERROR(XPATH_EXPR_ERROR);
8448 }
8449 NEXT;
8450 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008451 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008453 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008454 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008455 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008456 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008457 }
8458 SKIP_BLANKS;
8459}
8460
8461/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008462 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008463 * @ctxt: the XPath Parser context
8464 *
8465 * [20] FilterExpr ::= PrimaryExpr
8466 * | FilterExpr Predicate
8467 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008468 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008469 * Square brackets are used to filter expressions in the same way that
8470 * they are used in location paths. It is an error if the expression to
8471 * be filtered does not evaluate to a node-set. The context node list
8472 * used for evaluating the expression in square brackets is the node-set
8473 * to be filtered listed in document order.
8474 */
8475
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008476static void
8477xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8478 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008479 CHECK_ERROR;
8480 SKIP_BLANKS;
8481
8482 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008483 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008484 SKIP_BLANKS;
8485 }
8486
8487
8488}
8489
8490/**
8491 * xmlXPathScanName:
8492 * @ctxt: the XPath Parser context
8493 *
8494 * Trickery: parse an XML name but without consuming the input flow
8495 * Needed to avoid insanity in the parser state.
8496 *
8497 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8498 * CombiningChar | Extender
8499 *
8500 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8501 *
8502 * [6] Names ::= Name (S Name)*
8503 *
8504 * Returns the Name parsed or NULL
8505 */
8506
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008507static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008508xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008509 int len = 0, l;
8510 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008511 const xmlChar *cur;
8512 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008513
Daniel Veillard03226812004-11-01 14:55:21 +00008514 cur = ctxt->cur;
8515
8516 c = CUR_CHAR(l);
8517 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8518 (!IS_LETTER(c) && (c != '_') &&
8519 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008520 return(NULL);
8521 }
8522
Daniel Veillard03226812004-11-01 14:55:21 +00008523 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8524 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8525 (c == '.') || (c == '-') ||
8526 (c == '_') || (c == ':') ||
8527 (IS_COMBINING(c)) ||
8528 (IS_EXTENDER(c)))) {
8529 len += l;
8530 NEXTL(l);
8531 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008532 }
Daniel Veillard03226812004-11-01 14:55:21 +00008533 ret = xmlStrndup(cur, ctxt->cur - cur);
8534 ctxt->cur = cur;
8535 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008536}
8537
8538/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008539 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008540 * @ctxt: the XPath Parser context
8541 *
8542 * [19] PathExpr ::= LocationPath
8543 * | FilterExpr
8544 * | FilterExpr '/' RelativeLocationPath
8545 * | FilterExpr '//' RelativeLocationPath
8546 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008547 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008548 * The / operator and // operators combine an arbitrary expression
8549 * and a relative location path. It is an error if the expression
8550 * does not evaluate to a node-set.
8551 * The / operator does composition in the same way as when / is
8552 * used in a location path. As in location paths, // is short for
8553 * /descendant-or-self::node()/.
8554 */
8555
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008556static void
8557xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008558 int lc = 1; /* Should we branch to LocationPath ? */
8559 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8560
8561 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008562 if ((CUR == '$') || (CUR == '(') ||
8563 (IS_ASCII_DIGIT(CUR)) ||
8564 (CUR == '\'') || (CUR == '"') ||
8565 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008566 lc = 0;
8567 } else if (CUR == '*') {
8568 /* relative or absolute location path */
8569 lc = 1;
8570 } else if (CUR == '/') {
8571 /* relative or absolute location path */
8572 lc = 1;
8573 } else if (CUR == '@') {
8574 /* relative abbreviated attribute location path */
8575 lc = 1;
8576 } else if (CUR == '.') {
8577 /* relative abbreviated attribute location path */
8578 lc = 1;
8579 } else {
8580 /*
8581 * Problem is finding if we have a name here whether it's:
8582 * - a nodetype
8583 * - a function call in which case it's followed by '('
8584 * - an axis in which case it's followed by ':'
8585 * - a element name
8586 * We do an a priori analysis here rather than having to
8587 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008588 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008589 * read/write/debug.
8590 */
8591 SKIP_BLANKS;
8592 name = xmlXPathScanName(ctxt);
8593 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8594#ifdef DEBUG_STEP
8595 xmlGenericError(xmlGenericErrorContext,
8596 "PathExpr: Axis\n");
8597#endif
8598 lc = 1;
8599 xmlFree(name);
8600 } else if (name != NULL) {
8601 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008602
8603
8604 while (NXT(len) != 0) {
8605 if (NXT(len) == '/') {
8606 /* element name */
8607#ifdef DEBUG_STEP
8608 xmlGenericError(xmlGenericErrorContext,
8609 "PathExpr: AbbrRelLocation\n");
8610#endif
8611 lc = 1;
8612 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008613 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008614 /* ignore blanks */
8615 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008616 } else if (NXT(len) == ':') {
8617#ifdef DEBUG_STEP
8618 xmlGenericError(xmlGenericErrorContext,
8619 "PathExpr: AbbrRelLocation\n");
8620#endif
8621 lc = 1;
8622 break;
8623 } else if ((NXT(len) == '(')) {
8624 /* Note Type or Function */
8625 if (xmlXPathIsNodeType(name)) {
8626#ifdef DEBUG_STEP
8627 xmlGenericError(xmlGenericErrorContext,
8628 "PathExpr: Type search\n");
8629#endif
8630 lc = 1;
8631 } else {
8632#ifdef DEBUG_STEP
8633 xmlGenericError(xmlGenericErrorContext,
8634 "PathExpr: function call\n");
8635#endif
8636 lc = 0;
8637 }
8638 break;
8639 } else if ((NXT(len) == '[')) {
8640 /* element name */
8641#ifdef DEBUG_STEP
8642 xmlGenericError(xmlGenericErrorContext,
8643 "PathExpr: AbbrRelLocation\n");
8644#endif
8645 lc = 1;
8646 break;
8647 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8648 (NXT(len) == '=')) {
8649 lc = 1;
8650 break;
8651 } else {
8652 lc = 1;
8653 break;
8654 }
8655 len++;
8656 }
8657 if (NXT(len) == 0) {
8658#ifdef DEBUG_STEP
8659 xmlGenericError(xmlGenericErrorContext,
8660 "PathExpr: AbbrRelLocation\n");
8661#endif
8662 /* element name */
8663 lc = 1;
8664 }
8665 xmlFree(name);
8666 } else {
William M. Brack08171912003-12-29 02:52:11 +00008667 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008668 XP_ERROR(XPATH_EXPR_ERROR);
8669 }
8670 }
8671
8672 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008673 if (CUR == '/') {
8674 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8675 } else {
8676 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008677 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008678 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008679 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008680 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008681 CHECK_ERROR;
8682 if ((CUR == '/') && (NXT(1) == '/')) {
8683 SKIP(2);
8684 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008685
8686 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8687 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8688 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8689
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008690 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008691 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008692 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008693 }
8694 }
8695 SKIP_BLANKS;
8696}
8697
8698/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008699 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008700 * @ctxt: the XPath Parser context
8701 *
8702 * [18] UnionExpr ::= PathExpr
8703 * | UnionExpr '|' PathExpr
8704 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008705 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008706 */
8707
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008708static void
8709xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8710 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008711 CHECK_ERROR;
8712 SKIP_BLANKS;
8713 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008714 int op1 = ctxt->comp->last;
8715 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008716
8717 NEXT;
8718 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008719 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008720
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008721 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8722
Owen Taylor3473f882001-02-23 17:55:21 +00008723 SKIP_BLANKS;
8724 }
Owen Taylor3473f882001-02-23 17:55:21 +00008725}
8726
8727/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008728 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008729 * @ctxt: the XPath Parser context
8730 *
8731 * [27] UnaryExpr ::= UnionExpr
8732 * | '-' UnaryExpr
8733 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008734 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008735 */
8736
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008737static void
8738xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008739 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008740 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008741
8742 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008743 while (CUR == '-') {
8744 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008745 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008746 NEXT;
8747 SKIP_BLANKS;
8748 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008749
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008750 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008751 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008752 if (found) {
8753 if (minus)
8754 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8755 else
8756 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008757 }
8758}
8759
8760/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008761 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008762 * @ctxt: the XPath Parser context
8763 *
8764 * [26] MultiplicativeExpr ::= UnaryExpr
8765 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8766 * | MultiplicativeExpr 'div' UnaryExpr
8767 * | MultiplicativeExpr 'mod' UnaryExpr
8768 * [34] MultiplyOperator ::= '*'
8769 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008770 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008771 */
8772
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008773static void
8774xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8775 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008776 CHECK_ERROR;
8777 SKIP_BLANKS;
8778 while ((CUR == '*') ||
8779 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8780 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8781 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008782 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008783
8784 if (CUR == '*') {
8785 op = 0;
8786 NEXT;
8787 } else if (CUR == 'd') {
8788 op = 1;
8789 SKIP(3);
8790 } else if (CUR == 'm') {
8791 op = 2;
8792 SKIP(3);
8793 }
8794 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008795 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008796 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008797 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008798 SKIP_BLANKS;
8799 }
8800}
8801
8802/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008803 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008804 * @ctxt: the XPath Parser context
8805 *
8806 * [25] AdditiveExpr ::= MultiplicativeExpr
8807 * | AdditiveExpr '+' MultiplicativeExpr
8808 * | AdditiveExpr '-' MultiplicativeExpr
8809 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008810 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008811 */
8812
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008813static void
8814xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008815
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008816 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008817 CHECK_ERROR;
8818 SKIP_BLANKS;
8819 while ((CUR == '+') || (CUR == '-')) {
8820 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008821 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008822
8823 if (CUR == '+') plus = 1;
8824 else plus = 0;
8825 NEXT;
8826 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008827 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008828 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008829 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008830 SKIP_BLANKS;
8831 }
8832}
8833
8834/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008835 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008836 * @ctxt: the XPath Parser context
8837 *
8838 * [24] RelationalExpr ::= AdditiveExpr
8839 * | RelationalExpr '<' AdditiveExpr
8840 * | RelationalExpr '>' AdditiveExpr
8841 * | RelationalExpr '<=' AdditiveExpr
8842 * | RelationalExpr '>=' AdditiveExpr
8843 *
8844 * A <= B > C is allowed ? Answer from James, yes with
8845 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8846 * which is basically what got implemented.
8847 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008848 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008849 * on the stack
8850 */
8851
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008852static void
8853xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8854 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008855 CHECK_ERROR;
8856 SKIP_BLANKS;
8857 while ((CUR == '<') ||
8858 (CUR == '>') ||
8859 ((CUR == '<') && (NXT(1) == '=')) ||
8860 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008861 int inf, strict;
8862 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008863
8864 if (CUR == '<') inf = 1;
8865 else inf = 0;
8866 if (NXT(1) == '=') strict = 0;
8867 else strict = 1;
8868 NEXT;
8869 if (!strict) NEXT;
8870 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008871 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008872 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008873 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008874 SKIP_BLANKS;
8875 }
8876}
8877
8878/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008879 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008880 * @ctxt: the XPath Parser context
8881 *
8882 * [23] EqualityExpr ::= RelationalExpr
8883 * | EqualityExpr '=' RelationalExpr
8884 * | EqualityExpr '!=' RelationalExpr
8885 *
8886 * A != B != C is allowed ? Answer from James, yes with
8887 * (RelationalExpr = RelationalExpr) = RelationalExpr
8888 * (RelationalExpr != RelationalExpr) != RelationalExpr
8889 * which is basically what got implemented.
8890 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008891 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008892 *
8893 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008894static void
8895xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8896 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008897 CHECK_ERROR;
8898 SKIP_BLANKS;
8899 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008900 int eq;
8901 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008902
8903 if (CUR == '=') eq = 1;
8904 else eq = 0;
8905 NEXT;
8906 if (!eq) NEXT;
8907 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008908 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008909 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008910 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008911 SKIP_BLANKS;
8912 }
8913}
8914
8915/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008916 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008917 * @ctxt: the XPath Parser context
8918 *
8919 * [22] AndExpr ::= EqualityExpr
8920 * | AndExpr 'and' EqualityExpr
8921 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008922 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008923 *
8924 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008925static void
8926xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8927 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008928 CHECK_ERROR;
8929 SKIP_BLANKS;
8930 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008931 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008932 SKIP(3);
8933 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008934 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008935 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008936 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008937 SKIP_BLANKS;
8938 }
8939}
8940
8941/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008942 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008943 * @ctxt: the XPath Parser context
8944 *
8945 * [14] Expr ::= OrExpr
8946 * [21] OrExpr ::= AndExpr
8947 * | OrExpr 'or' AndExpr
8948 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008949 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008950 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008951static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008952xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008953 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008954 CHECK_ERROR;
8955 SKIP_BLANKS;
8956 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008957 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008958 SKIP(2);
8959 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008960 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008961 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008962 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8963 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008964 SKIP_BLANKS;
8965 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008966 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008967 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008968 /*
8969 * This is the main place to eliminate sorting for
8970 * operations which don't require a sorted node-set.
8971 * E.g. count().
8972 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008973 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8974 }
Owen Taylor3473f882001-02-23 17:55:21 +00008975}
8976
8977/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008978 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008979 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008980 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008981 *
8982 * [8] Predicate ::= '[' PredicateExpr ']'
8983 * [9] PredicateExpr ::= Expr
8984 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008985 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008986 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008987static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008988xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008989 int op1 = ctxt->comp->last;
8990
8991 SKIP_BLANKS;
8992 if (CUR != '[') {
8993 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8994 }
8995 NEXT;
8996 SKIP_BLANKS;
8997
8998 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008999 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009000 CHECK_ERROR;
9001
9002 if (CUR != ']') {
9003 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9004 }
9005
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009006 if (filter)
9007 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9008 else
9009 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009010
9011 NEXT;
9012 SKIP_BLANKS;
9013}
9014
9015/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009016 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00009017 * @ctxt: the XPath Parser context
9018 * @test: pointer to a xmlXPathTestVal
9019 * @type: pointer to a xmlXPathTypeVal
9020 * @prefix: placeholder for a possible name prefix
9021 *
9022 * [7] NodeTest ::= NameTest
9023 * | NodeType '(' ')'
9024 * | 'processing-instruction' '(' Literal ')'
9025 *
9026 * [37] NameTest ::= '*'
9027 * | NCName ':' '*'
9028 * | QName
9029 * [38] NodeType ::= 'comment'
9030 * | 'text'
9031 * | 'processing-instruction'
9032 * | 'node'
9033 *
William M. Brack08171912003-12-29 02:52:11 +00009034 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00009035 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009036static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009037xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9038 xmlXPathTypeVal *type, const xmlChar **prefix,
9039 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00009040 int blanks;
9041
9042 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9043 STRANGE;
9044 return(NULL);
9045 }
William M. Brack78637da2003-07-31 14:47:38 +00009046 *type = (xmlXPathTypeVal) 0;
9047 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009048 *prefix = NULL;
9049 SKIP_BLANKS;
9050
9051 if ((name == NULL) && (CUR == '*')) {
9052 /*
9053 * All elements
9054 */
9055 NEXT;
9056 *test = NODE_TEST_ALL;
9057 return(NULL);
9058 }
9059
9060 if (name == NULL)
9061 name = xmlXPathParseNCName(ctxt);
9062 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009063 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009064 }
9065
William M. Brack76e95df2003-10-18 16:20:14 +00009066 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00009067 SKIP_BLANKS;
9068 if (CUR == '(') {
9069 NEXT;
9070 /*
9071 * NodeType or PI search
9072 */
9073 if (xmlStrEqual(name, BAD_CAST "comment"))
9074 *type = NODE_TYPE_COMMENT;
9075 else if (xmlStrEqual(name, BAD_CAST "node"))
9076 *type = NODE_TYPE_NODE;
9077 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9078 *type = NODE_TYPE_PI;
9079 else if (xmlStrEqual(name, BAD_CAST "text"))
9080 *type = NODE_TYPE_TEXT;
9081 else {
9082 if (name != NULL)
9083 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00009084 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009085 }
9086
9087 *test = NODE_TEST_TYPE;
9088
9089 SKIP_BLANKS;
9090 if (*type == NODE_TYPE_PI) {
9091 /*
9092 * Specific case: search a PI by name.
9093 */
Owen Taylor3473f882001-02-23 17:55:21 +00009094 if (name != NULL)
9095 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00009096 name = NULL;
9097 if (CUR != ')') {
9098 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +00009099 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00009100 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00009101 SKIP_BLANKS;
9102 }
Owen Taylor3473f882001-02-23 17:55:21 +00009103 }
9104 if (CUR != ')') {
9105 if (name != NULL)
9106 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00009107 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009108 }
9109 NEXT;
9110 return(name);
9111 }
9112 *test = NODE_TEST_NAME;
9113 if ((!blanks) && (CUR == ':')) {
9114 NEXT;
9115
9116 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009117 * Since currently the parser context don't have a
9118 * namespace list associated:
9119 * The namespace name for this prefix can be computed
9120 * only at evaluation time. The compilation is done
9121 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00009122 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009123#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00009124 *prefix = xmlXPathNsLookup(ctxt->context, name);
9125 if (name != NULL)
9126 xmlFree(name);
9127 if (*prefix == NULL) {
9128 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9129 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009130#else
9131 *prefix = name;
9132#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009133
9134 if (CUR == '*') {
9135 /*
9136 * All elements
9137 */
9138 NEXT;
9139 *test = NODE_TEST_ALL;
9140 return(NULL);
9141 }
9142
9143 name = xmlXPathParseNCName(ctxt);
9144 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009145 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009146 }
9147 }
9148 return(name);
9149}
9150
9151/**
9152 * xmlXPathIsAxisName:
9153 * @name: a preparsed name token
9154 *
9155 * [6] AxisName ::= 'ancestor'
9156 * | 'ancestor-or-self'
9157 * | 'attribute'
9158 * | 'child'
9159 * | 'descendant'
9160 * | 'descendant-or-self'
9161 * | 'following'
9162 * | 'following-sibling'
9163 * | 'namespace'
9164 * | 'parent'
9165 * | 'preceding'
9166 * | 'preceding-sibling'
9167 * | 'self'
9168 *
9169 * Returns the axis or 0
9170 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009171static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00009172xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00009173 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009174 switch (name[0]) {
9175 case 'a':
9176 if (xmlStrEqual(name, BAD_CAST "ancestor"))
9177 ret = AXIS_ANCESTOR;
9178 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9179 ret = AXIS_ANCESTOR_OR_SELF;
9180 if (xmlStrEqual(name, BAD_CAST "attribute"))
9181 ret = AXIS_ATTRIBUTE;
9182 break;
9183 case 'c':
9184 if (xmlStrEqual(name, BAD_CAST "child"))
9185 ret = AXIS_CHILD;
9186 break;
9187 case 'd':
9188 if (xmlStrEqual(name, BAD_CAST "descendant"))
9189 ret = AXIS_DESCENDANT;
9190 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9191 ret = AXIS_DESCENDANT_OR_SELF;
9192 break;
9193 case 'f':
9194 if (xmlStrEqual(name, BAD_CAST "following"))
9195 ret = AXIS_FOLLOWING;
9196 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9197 ret = AXIS_FOLLOWING_SIBLING;
9198 break;
9199 case 'n':
9200 if (xmlStrEqual(name, BAD_CAST "namespace"))
9201 ret = AXIS_NAMESPACE;
9202 break;
9203 case 'p':
9204 if (xmlStrEqual(name, BAD_CAST "parent"))
9205 ret = AXIS_PARENT;
9206 if (xmlStrEqual(name, BAD_CAST "preceding"))
9207 ret = AXIS_PRECEDING;
9208 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9209 ret = AXIS_PRECEDING_SIBLING;
9210 break;
9211 case 's':
9212 if (xmlStrEqual(name, BAD_CAST "self"))
9213 ret = AXIS_SELF;
9214 break;
9215 }
9216 return(ret);
9217}
9218
9219/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009220 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00009221 * @ctxt: the XPath Parser context
9222 *
9223 * [4] Step ::= AxisSpecifier NodeTest Predicate*
9224 * | AbbreviatedStep
9225 *
9226 * [12] AbbreviatedStep ::= '.' | '..'
9227 *
9228 * [5] AxisSpecifier ::= AxisName '::'
9229 * | AbbreviatedAxisSpecifier
9230 *
9231 * [13] AbbreviatedAxisSpecifier ::= '@'?
9232 *
9233 * Modified for XPtr range support as:
9234 *
9235 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9236 * | AbbreviatedStep
9237 * | 'range-to' '(' Expr ')' Predicate*
9238 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009239 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00009240 * A location step of . is short for self::node(). This is
9241 * particularly useful in conjunction with //. For example, the
9242 * location path .//para is short for
9243 * self::node()/descendant-or-self::node()/child::para
9244 * and so will select all para descendant elements of the context
9245 * node.
9246 * Similarly, a location step of .. is short for parent::node().
9247 * For example, ../title is short for parent::node()/child::title
9248 * and so will select the title children of the parent of the context
9249 * node.
9250 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009251static void
9252xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009253#ifdef LIBXML_XPTR_ENABLED
9254 int rangeto = 0;
9255 int op2 = -1;
9256#endif
9257
Owen Taylor3473f882001-02-23 17:55:21 +00009258 SKIP_BLANKS;
9259 if ((CUR == '.') && (NXT(1) == '.')) {
9260 SKIP(2);
9261 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009262 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9263 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009264 } else if (CUR == '.') {
9265 NEXT;
9266 SKIP_BLANKS;
9267 } else {
9268 xmlChar *name = NULL;
9269 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +00009270 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +00009271 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +00009272 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009273 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00009274
9275 /*
9276 * The modification needed for XPointer change to the production
9277 */
9278#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009279 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00009280 name = xmlXPathParseNCName(ctxt);
9281 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009282 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00009283 xmlFree(name);
9284 SKIP_BLANKS;
9285 if (CUR != '(') {
9286 XP_ERROR(XPATH_EXPR_ERROR);
9287 }
9288 NEXT;
9289 SKIP_BLANKS;
9290
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009291 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009292 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00009293 CHECK_ERROR;
9294
9295 SKIP_BLANKS;
9296 if (CUR != ')') {
9297 XP_ERROR(XPATH_EXPR_ERROR);
9298 }
9299 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009300 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009301 goto eval_predicates;
9302 }
9303 }
9304#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00009305 if (CUR == '*') {
9306 axis = AXIS_CHILD;
9307 } else {
9308 if (name == NULL)
9309 name = xmlXPathParseNCName(ctxt);
9310 if (name != NULL) {
9311 axis = xmlXPathIsAxisName(name);
9312 if (axis != 0) {
9313 SKIP_BLANKS;
9314 if ((CUR == ':') && (NXT(1) == ':')) {
9315 SKIP(2);
9316 xmlFree(name);
9317 name = NULL;
9318 } else {
9319 /* an element name can conflict with an axis one :-\ */
9320 axis = AXIS_CHILD;
9321 }
Owen Taylor3473f882001-02-23 17:55:21 +00009322 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00009323 axis = AXIS_CHILD;
9324 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009325 } else if (CUR == '@') {
9326 NEXT;
9327 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00009328 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00009329 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00009330 }
Owen Taylor3473f882001-02-23 17:55:21 +00009331 }
9332
9333 CHECK_ERROR;
9334
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009335 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00009336 if (test == 0)
9337 return;
9338
Daniel Veillarded6c5492005-07-23 15:00:22 +00009339 if ((prefix != NULL) && (ctxt->context != NULL) &&
9340 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9341 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9342 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
9343 }
9344 }
Owen Taylor3473f882001-02-23 17:55:21 +00009345#ifdef DEBUG_STEP
9346 xmlGenericError(xmlGenericErrorContext,
9347 "Basis : computing new set\n");
9348#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009349
Owen Taylor3473f882001-02-23 17:55:21 +00009350#ifdef DEBUG_STEP
9351 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009352 if (ctxt->value == NULL)
9353 xmlGenericError(xmlGenericErrorContext, "no value\n");
9354 else if (ctxt->value->nodesetval == NULL)
9355 xmlGenericError(xmlGenericErrorContext, "Empty\n");
9356 else
9357 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00009358#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009359
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00009360#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00009361eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00009362#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009363 op1 = ctxt->comp->last;
9364 ctxt->comp->last = -1;
9365
Owen Taylor3473f882001-02-23 17:55:21 +00009366 SKIP_BLANKS;
9367 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009368 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00009369 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009370
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009371#ifdef LIBXML_XPTR_ENABLED
9372 if (rangeto) {
9373 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
9374 } else
9375#endif
9376 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9377 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009378
Owen Taylor3473f882001-02-23 17:55:21 +00009379 }
9380#ifdef DEBUG_STEP
9381 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009382 if (ctxt->value == NULL)
9383 xmlGenericError(xmlGenericErrorContext, "no value\n");
9384 else if (ctxt->value->nodesetval == NULL)
9385 xmlGenericError(xmlGenericErrorContext, "Empty\n");
9386 else
9387 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
9388 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00009389#endif
9390}
9391
9392/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009393 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009394 * @ctxt: the XPath Parser context
9395 *
9396 * [3] RelativeLocationPath ::= Step
9397 * | RelativeLocationPath '/' Step
9398 * | AbbreviatedRelativeLocationPath
9399 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
9400 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009401 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00009402 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009403static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009404xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00009405(xmlXPathParserContextPtr ctxt) {
9406 SKIP_BLANKS;
9407 if ((CUR == '/') && (NXT(1) == '/')) {
9408 SKIP(2);
9409 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009410 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9411 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009412 } else if (CUR == '/') {
9413 NEXT;
9414 SKIP_BLANKS;
9415 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009416 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009417 SKIP_BLANKS;
9418 while (CUR == '/') {
9419 if ((CUR == '/') && (NXT(1) == '/')) {
9420 SKIP(2);
9421 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009422 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009423 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009424 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009425 } else if (CUR == '/') {
9426 NEXT;
9427 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009428 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009429 }
9430 SKIP_BLANKS;
9431 }
9432}
9433
9434/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009435 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009436 * @ctxt: the XPath Parser context
9437 *
9438 * [1] LocationPath ::= RelativeLocationPath
9439 * | AbsoluteLocationPath
9440 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9441 * | AbbreviatedAbsoluteLocationPath
9442 * [10] AbbreviatedAbsoluteLocationPath ::=
9443 * '//' RelativeLocationPath
9444 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009445 * Compile a location path
9446 *
Owen Taylor3473f882001-02-23 17:55:21 +00009447 * // is short for /descendant-or-self::node()/. For example,
9448 * //para is short for /descendant-or-self::node()/child::para and
9449 * so will select any para element in the document (even a para element
9450 * that is a document element will be selected by //para since the
9451 * document element node is a child of the root node); div//para is
9452 * short for div/descendant-or-self::node()/child::para and so will
9453 * select all para descendants of div children.
9454 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009455static void
9456xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009457 SKIP_BLANKS;
9458 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009459 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009460 } else {
9461 while (CUR == '/') {
9462 if ((CUR == '/') && (NXT(1) == '/')) {
9463 SKIP(2);
9464 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009465 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9466 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009467 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009468 } else if (CUR == '/') {
9469 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009470 SKIP_BLANKS;
9471 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009472 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009473 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009474 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009475 }
9476 }
9477 }
9478}
9479
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009480/************************************************************************
9481 * *
9482 * XPath precompiled expression evaluation *
9483 * *
9484 ************************************************************************/
9485
Daniel Veillardf06307e2001-07-03 10:35:50 +00009486static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009487xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9488
9489/**
9490 * xmlXPathNodeCollectAndTest:
9491 * @ctxt: the XPath Parser context
9492 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493 * @first: pointer to the first element in document order
9494 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009495 *
9496 * This is the function implementing a step: based on the current list
9497 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009498 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009499 *
9500 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009501 *
William M. Brack08171912003-12-29 02:52:11 +00009502 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009503 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009504static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009505xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009506 xmlXPathStepOpPtr op,
9507 xmlNodePtr * first, xmlNodePtr * last)
9508{
William M. Brack78637da2003-07-31 14:47:38 +00009509 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9510 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9511 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009512 const xmlChar *prefix = op->value4;
9513 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009514 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009515
9516#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009517 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009518#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009519 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009520 xmlNodeSetPtr ret, list;
9521 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009522 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009523 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009524 xmlNodePtr cur = NULL;
9525 xmlXPathObjectPtr obj;
9526 xmlNodeSetPtr nodelist;
9527 xmlNodePtr tmp;
9528
Daniel Veillardf06307e2001-07-03 10:35:50 +00009529 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009530 obj = valuePop(ctxt);
9531 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009532 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009533 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009534 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009535 if (URI == NULL) {
9536 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009538 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009539 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009540#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009541 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009542#endif
9543 switch (axis) {
9544 case AXIS_ANCESTOR:
9545#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009546 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009547#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009548 first = NULL;
9549 next = xmlXPathNextAncestor;
9550 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009551 case AXIS_ANCESTOR_OR_SELF:
9552#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009553 xmlGenericError(xmlGenericErrorContext,
9554 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009555#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009556 first = NULL;
9557 next = xmlXPathNextAncestorOrSelf;
9558 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009559 case AXIS_ATTRIBUTE:
9560#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009561 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009562#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009563 first = NULL;
9564 last = NULL;
9565 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009566 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009568 case AXIS_CHILD:
9569#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009570 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009571#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009572 last = NULL;
9573 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009574 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009575 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009576 case AXIS_DESCENDANT:
9577#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009578 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009579#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009580 last = NULL;
9581 next = xmlXPathNextDescendant;
9582 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009583 case AXIS_DESCENDANT_OR_SELF:
9584#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009585 xmlGenericError(xmlGenericErrorContext,
9586 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009587#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009588 last = NULL;
9589 next = xmlXPathNextDescendantOrSelf;
9590 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009591 case AXIS_FOLLOWING:
9592#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009593 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009594#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009595 last = NULL;
9596 next = xmlXPathNextFollowing;
9597 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009598 case AXIS_FOLLOWING_SIBLING:
9599#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009600 xmlGenericError(xmlGenericErrorContext,
9601 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009602#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009603 last = NULL;
9604 next = xmlXPathNextFollowingSibling;
9605 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009606 case AXIS_NAMESPACE:
9607#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009609#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009610 first = NULL;
9611 last = NULL;
9612 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009613 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009614 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009615 case AXIS_PARENT:
9616#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009617 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009618#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009619 first = NULL;
9620 next = xmlXPathNextParent;
9621 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009622 case AXIS_PRECEDING:
9623#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009624 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009625#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009626 first = NULL;
9627 next = xmlXPathNextPrecedingInternal;
9628 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009629 case AXIS_PRECEDING_SIBLING:
9630#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009631 xmlGenericError(xmlGenericErrorContext,
9632 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009633#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009634 first = NULL;
9635 next = xmlXPathNextPrecedingSibling;
9636 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009637 case AXIS_SELF:
9638#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009639 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009640#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009641 first = NULL;
9642 last = NULL;
9643 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009644 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009645 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009646 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009647 if (next == NULL) {
9648 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009649 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009650 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009651
9652 nodelist = obj->nodesetval;
9653 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009654 xmlXPathFreeObject(obj);
9655 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9656 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009657 }
9658 addNode = xmlXPathNodeSetAddUnique;
9659 ret = NULL;
9660#ifdef DEBUG_STEP
9661 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009662 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009663 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 case NODE_TEST_NONE:
9665 xmlGenericError(xmlGenericErrorContext,
9666 " searching for none !!!\n");
9667 break;
9668 case NODE_TEST_TYPE:
9669 xmlGenericError(xmlGenericErrorContext,
9670 " searching for type %d\n", type);
9671 break;
9672 case NODE_TEST_PI:
9673 xmlGenericError(xmlGenericErrorContext,
9674 " searching for PI !!!\n");
9675 break;
9676 case NODE_TEST_ALL:
9677 xmlGenericError(xmlGenericErrorContext,
9678 " searching for *\n");
9679 break;
9680 case NODE_TEST_NS:
9681 xmlGenericError(xmlGenericErrorContext,
9682 " searching for namespace %s\n",
9683 prefix);
9684 break;
9685 case NODE_TEST_NAME:
9686 xmlGenericError(xmlGenericErrorContext,
9687 " searching for name %s\n", name);
9688 if (prefix != NULL)
9689 xmlGenericError(xmlGenericErrorContext,
9690 " with namespace %s\n", prefix);
9691 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009692 }
9693 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9694#endif
9695 /*
9696 * 2.3 Node Tests
9697 * - For the attribute axis, the principal node type is attribute.
9698 * - For the namespace axis, the principal node type is namespace.
9699 * - For other axes, the principal node type is element.
9700 *
9701 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009702 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009703 * select all element children of the context node
9704 */
9705 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009706 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009707 ctxt->context->node = nodelist->nodeTab[i];
9708
Daniel Veillardf06307e2001-07-03 10:35:50 +00009709 cur = NULL;
9710 list = xmlXPathNodeSetCreate(NULL);
9711 do {
9712 cur = next(ctxt, cur);
9713 if (cur == NULL)
9714 break;
9715 if ((first != NULL) && (*first == cur))
9716 break;
9717 if (((t % 256) == 0) &&
9718 (first != NULL) && (*first != NULL) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009719#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009720 (xmlXPathCmpNodesExt(*first, cur) >= 0))
9721#else
Daniel Veillardf06307e2001-07-03 10:35:50 +00009722 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009723#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009724 break;
9725 if ((last != NULL) && (*last == cur))
9726 break;
9727 if (((t % 256) == 0) &&
9728 (last != NULL) && (*last != NULL) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009729#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009730 (xmlXPathCmpNodesExt(cur, *last) >= 0))
9731#else
Daniel Veillardf06307e2001-07-03 10:35:50 +00009732 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009733#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009734 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009735 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009736#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009737 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9738#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009739 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009740 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009741 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009742 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009743 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009744 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009745 if ((cur->type == type) ||
9746 ((type == NODE_TYPE_NODE) &&
9747 ((cur->type == XML_DOCUMENT_NODE) ||
9748 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9749 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009750 (cur->type == XML_NAMESPACE_DECL) ||
9751 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009752 (cur->type == XML_PI_NODE) ||
9753 (cur->type == XML_COMMENT_NODE) ||
9754 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009755 (cur->type == XML_TEXT_NODE))) ||
9756 ((type == NODE_TYPE_TEXT) &&
9757 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009758#ifdef DEBUG_STEP
9759 n++;
9760#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009761 addNode(list, cur);
9762 }
9763 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009764 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 if (cur->type == XML_PI_NODE) {
9766 if ((name != NULL) &&
9767 (!xmlStrEqual(name, cur->name)))
9768 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009769#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009770 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009771#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009772 addNode(list, cur);
9773 }
9774 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009775 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009776 if (axis == AXIS_ATTRIBUTE) {
9777 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009778#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009780#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009781 addNode(list, cur);
9782 }
9783 } else if (axis == AXIS_NAMESPACE) {
9784 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009785#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009787#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009788 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9789 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009790 }
9791 } else {
9792 if (cur->type == XML_ELEMENT_NODE) {
9793 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009794#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009795 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009796#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009797 addNode(list, cur);
9798 } else if ((cur->ns != NULL) &&
9799 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009800#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009801 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009802#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009803 addNode(list, cur);
9804 }
9805 }
9806 }
9807 break;
9808 case NODE_TEST_NS:{
9809 TODO;
9810 break;
9811 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009812 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009813 switch (cur->type) {
9814 case XML_ELEMENT_NODE:
9815 if (xmlStrEqual(name, cur->name)) {
9816 if (prefix == NULL) {
9817 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009818#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009819 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009820#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009821 addNode(list, cur);
9822 }
9823 } else {
9824 if ((cur->ns != NULL) &&
9825 (xmlStrEqual(URI,
9826 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009827#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009828 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009829#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009830 addNode(list, cur);
9831 }
9832 }
9833 }
9834 break;
9835 case XML_ATTRIBUTE_NODE:{
9836 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009837
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 if (xmlStrEqual(name, attr->name)) {
9839 if (prefix == NULL) {
9840 if ((attr->ns == NULL) ||
9841 (attr->ns->prefix == NULL)) {
9842#ifdef DEBUG_STEP
9843 n++;
9844#endif
9845 addNode(list,
9846 (xmlNodePtr) attr);
9847 }
9848 } else {
9849 if ((attr->ns != NULL) &&
9850 (xmlStrEqual(URI,
9851 attr->ns->
9852 href))) {
9853#ifdef DEBUG_STEP
9854 n++;
9855#endif
9856 addNode(list,
9857 (xmlNodePtr) attr);
9858 }
9859 }
9860 }
9861 break;
9862 }
9863 case XML_NAMESPACE_DECL:
9864 if (cur->type == XML_NAMESPACE_DECL) {
9865 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009866
Daniel Veillardf06307e2001-07-03 10:35:50 +00009867 if ((ns->prefix != NULL) && (name != NULL)
9868 && (xmlStrEqual(ns->prefix, name))) {
9869#ifdef DEBUG_STEP
9870 n++;
9871#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009872 xmlXPathNodeSetAddNs(list,
9873 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009874 }
9875 }
9876 break;
9877 default:
9878 break;
9879 }
9880 break;
9881 break;
9882 }
9883 } while (cur != NULL);
9884
9885 /*
9886 * If there is some predicate filtering do it now
9887 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009888 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009889 xmlXPathObjectPtr obj2;
9890
9891 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9892 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9893 CHECK_TYPE0(XPATH_NODESET);
9894 obj2 = valuePop(ctxt);
9895 list = obj2->nodesetval;
9896 obj2->nodesetval = NULL;
9897 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009898 if (ctxt->error != XPATH_EXPRESSION_OK) {
9899 xmlXPathFreeObject(obj);
9900 xmlXPathFreeNodeSet(list);
9901 return(0);
9902 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009903 }
9904 if (ret == NULL) {
9905 ret = list;
9906 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009907 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009908 xmlXPathFreeNodeSet(list);
9909 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009910 }
9911 ctxt->context->node = tmp;
9912#ifdef DEBUG_STEP
9913 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 "\nExamined %d nodes, found %d nodes at that step\n",
9915 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009916#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009917 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009918 if ((obj->boolval) && (obj->user != NULL)) {
9919 ctxt->value->boolval = 1;
9920 ctxt->value->user = obj->user;
9921 obj->user = NULL;
9922 obj->boolval = 0;
9923 }
9924 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009925 return(t);
9926}
9927
9928/**
9929 * xmlXPathNodeCollectAndTestNth:
9930 * @ctxt: the XPath Parser context
9931 * @op: the XPath precompiled step operation
9932 * @indx: the index to collect
9933 * @first: pointer to the first element in document order
9934 * @last: pointer to the last element in document order
9935 *
9936 * This is the function implementing a step: based on the current list
9937 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009938 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009939 *
9940 * Pushes the new NodeSet resulting from the search.
9941 * Returns the number of node traversed
9942 */
9943static int
9944xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9945 xmlXPathStepOpPtr op, int indx,
9946 xmlNodePtr * first, xmlNodePtr * last)
9947{
William M. Brack78637da2003-07-31 14:47:38 +00009948 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9949 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9950 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009951 const xmlChar *prefix = op->value4;
9952 const xmlChar *name = op->value5;
9953 const xmlChar *URI = NULL;
9954 int n = 0, t = 0;
9955
9956 int i;
9957 xmlNodeSetPtr list;
9958 xmlXPathTraversalFunction next = NULL;
9959 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9960 xmlNodePtr cur = NULL;
9961 xmlXPathObjectPtr obj;
9962 xmlNodeSetPtr nodelist;
9963 xmlNodePtr tmp;
9964
9965 CHECK_TYPE0(XPATH_NODESET);
9966 obj = valuePop(ctxt);
9967 addNode = xmlXPathNodeSetAdd;
9968 if (prefix != NULL) {
9969 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009970 if (URI == NULL) {
9971 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009973 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009974 }
9975#ifdef DEBUG_STEP_NTH
9976 xmlGenericError(xmlGenericErrorContext, "new step : ");
9977 if (first != NULL) {
9978 if (*first != NULL)
9979 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9980 (*first)->name);
9981 else
9982 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9983 }
9984 if (last != NULL) {
9985 if (*last != NULL)
9986 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9987 (*last)->name);
9988 else
9989 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9990 }
9991#endif
9992 switch (axis) {
9993 case AXIS_ANCESTOR:
9994#ifdef DEBUG_STEP_NTH
9995 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9996#endif
9997 first = NULL;
9998 next = xmlXPathNextAncestor;
9999 break;
10000 case AXIS_ANCESTOR_OR_SELF:
10001#ifdef DEBUG_STEP_NTH
10002 xmlGenericError(xmlGenericErrorContext,
10003 "axis 'ancestors-or-self' ");
10004#endif
10005 first = NULL;
10006 next = xmlXPathNextAncestorOrSelf;
10007 break;
10008 case AXIS_ATTRIBUTE:
10009#ifdef DEBUG_STEP_NTH
10010 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
10011#endif
10012 first = NULL;
10013 last = NULL;
10014 next = xmlXPathNextAttribute;
10015 break;
10016 case AXIS_CHILD:
10017#ifdef DEBUG_STEP_NTH
10018 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
10019#endif
10020 last = NULL;
10021 next = xmlXPathNextChild;
10022 break;
10023 case AXIS_DESCENDANT:
10024#ifdef DEBUG_STEP_NTH
10025 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
10026#endif
10027 last = NULL;
10028 next = xmlXPathNextDescendant;
10029 break;
10030 case AXIS_DESCENDANT_OR_SELF:
10031#ifdef DEBUG_STEP_NTH
10032 xmlGenericError(xmlGenericErrorContext,
10033 "axis 'descendant-or-self' ");
10034#endif
10035 last = NULL;
10036 next = xmlXPathNextDescendantOrSelf;
10037 break;
10038 case AXIS_FOLLOWING:
10039#ifdef DEBUG_STEP_NTH
10040 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
10041#endif
10042 last = NULL;
10043 next = xmlXPathNextFollowing;
10044 break;
10045 case AXIS_FOLLOWING_SIBLING:
10046#ifdef DEBUG_STEP_NTH
10047 xmlGenericError(xmlGenericErrorContext,
10048 "axis 'following-siblings' ");
10049#endif
10050 last = NULL;
10051 next = xmlXPathNextFollowingSibling;
10052 break;
10053 case AXIS_NAMESPACE:
10054#ifdef DEBUG_STEP_NTH
10055 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
10056#endif
10057 last = NULL;
10058 first = NULL;
10059 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10060 break;
10061 case AXIS_PARENT:
10062#ifdef DEBUG_STEP_NTH
10063 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
10064#endif
10065 first = NULL;
10066 next = xmlXPathNextParent;
10067 break;
10068 case AXIS_PRECEDING:
10069#ifdef DEBUG_STEP_NTH
10070 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
10071#endif
10072 first = NULL;
10073 next = xmlXPathNextPrecedingInternal;
10074 break;
10075 case AXIS_PRECEDING_SIBLING:
10076#ifdef DEBUG_STEP_NTH
10077 xmlGenericError(xmlGenericErrorContext,
10078 "axis 'preceding-sibling' ");
10079#endif
10080 first = NULL;
10081 next = xmlXPathNextPrecedingSibling;
10082 break;
10083 case AXIS_SELF:
10084#ifdef DEBUG_STEP_NTH
10085 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
10086#endif
10087 first = NULL;
10088 last = NULL;
10089 next = xmlXPathNextSelf;
10090 break;
10091 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000010092 if (next == NULL) {
10093 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010094 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010095 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096
10097 nodelist = obj->nodesetval;
10098 if (nodelist == NULL) {
10099 xmlXPathFreeObject(obj);
10100 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
10101 return(0);
10102 }
10103 addNode = xmlXPathNodeSetAddUnique;
10104#ifdef DEBUG_STEP_NTH
10105 xmlGenericError(xmlGenericErrorContext,
10106 " context contains %d nodes\n", nodelist->nodeNr);
10107 switch (test) {
10108 case NODE_TEST_NONE:
10109 xmlGenericError(xmlGenericErrorContext,
10110 " searching for none !!!\n");
10111 break;
10112 case NODE_TEST_TYPE:
10113 xmlGenericError(xmlGenericErrorContext,
10114 " searching for type %d\n", type);
10115 break;
10116 case NODE_TEST_PI:
10117 xmlGenericError(xmlGenericErrorContext,
10118 " searching for PI !!!\n");
10119 break;
10120 case NODE_TEST_ALL:
10121 xmlGenericError(xmlGenericErrorContext,
10122 " searching for *\n");
10123 break;
10124 case NODE_TEST_NS:
10125 xmlGenericError(xmlGenericErrorContext,
10126 " searching for namespace %s\n",
10127 prefix);
10128 break;
10129 case NODE_TEST_NAME:
10130 xmlGenericError(xmlGenericErrorContext,
10131 " searching for name %s\n", name);
10132 if (prefix != NULL)
10133 xmlGenericError(xmlGenericErrorContext,
10134 " with namespace %s\n", prefix);
10135 break;
10136 }
10137 xmlGenericError(xmlGenericErrorContext, "Testing : ");
10138#endif
10139 /*
10140 * 2.3 Node Tests
10141 * - For the attribute axis, the principal node type is attribute.
10142 * - For the namespace axis, the principal node type is namespace.
10143 * - For other axes, the principal node type is element.
10144 *
10145 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010146 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +000010147 * select all element children of the context node
10148 */
10149 tmp = ctxt->context->node;
10150 list = xmlXPathNodeSetCreate(NULL);
10151 for (i = 0; i < nodelist->nodeNr; i++) {
10152 ctxt->context->node = nodelist->nodeTab[i];
10153
10154 cur = NULL;
10155 n = 0;
10156 do {
10157 cur = next(ctxt, cur);
10158 if (cur == NULL)
10159 break;
10160 if ((first != NULL) && (*first == cur))
10161 break;
10162 if (((t % 256) == 0) &&
10163 (first != NULL) && (*first != NULL) &&
10164 (xmlXPathCmpNodes(*first, cur) >= 0))
10165 break;
10166 if ((last != NULL) && (*last == cur))
10167 break;
10168 if (((t % 256) == 0) &&
10169 (last != NULL) && (*last != NULL) &&
10170 (xmlXPathCmpNodes(cur, *last) >= 0))
10171 break;
10172 t++;
10173 switch (test) {
10174 case NODE_TEST_NONE:
10175 ctxt->context->node = tmp;
10176 STRANGE return(0);
10177 case NODE_TEST_TYPE:
10178 if ((cur->type == type) ||
10179 ((type == NODE_TYPE_NODE) &&
10180 ((cur->type == XML_DOCUMENT_NODE) ||
10181 (cur->type == XML_HTML_DOCUMENT_NODE) ||
10182 (cur->type == XML_ELEMENT_NODE) ||
10183 (cur->type == XML_PI_NODE) ||
10184 (cur->type == XML_COMMENT_NODE) ||
10185 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +000010186 (cur->type == XML_TEXT_NODE))) ||
10187 ((type == NODE_TYPE_TEXT) &&
10188 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010189 n++;
10190 if (n == indx)
10191 addNode(list, cur);
10192 }
10193 break;
10194 case NODE_TEST_PI:
10195 if (cur->type == XML_PI_NODE) {
10196 if ((name != NULL) &&
10197 (!xmlStrEqual(name, cur->name)))
10198 break;
10199 n++;
10200 if (n == indx)
10201 addNode(list, cur);
10202 }
10203 break;
10204 case NODE_TEST_ALL:
10205 if (axis == AXIS_ATTRIBUTE) {
10206 if (cur->type == XML_ATTRIBUTE_NODE) {
10207 n++;
10208 if (n == indx)
10209 addNode(list, cur);
10210 }
10211 } else if (axis == AXIS_NAMESPACE) {
10212 if (cur->type == XML_NAMESPACE_DECL) {
10213 n++;
10214 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000010215 xmlXPathNodeSetAddNs(list, ctxt->context->node,
10216 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 }
10218 } else {
10219 if (cur->type == XML_ELEMENT_NODE) {
10220 if (prefix == NULL) {
10221 n++;
10222 if (n == indx)
10223 addNode(list, cur);
10224 } else if ((cur->ns != NULL) &&
10225 (xmlStrEqual(URI, cur->ns->href))) {
10226 n++;
10227 if (n == indx)
10228 addNode(list, cur);
10229 }
10230 }
10231 }
10232 break;
10233 case NODE_TEST_NS:{
10234 TODO;
10235 break;
10236 }
10237 case NODE_TEST_NAME:
10238 switch (cur->type) {
10239 case XML_ELEMENT_NODE:
10240 if (xmlStrEqual(name, cur->name)) {
10241 if (prefix == NULL) {
10242 if (cur->ns == NULL) {
10243 n++;
10244 if (n == indx)
10245 addNode(list, cur);
10246 }
10247 } else {
10248 if ((cur->ns != NULL) &&
10249 (xmlStrEqual(URI,
10250 cur->ns->href))) {
10251 n++;
10252 if (n == indx)
10253 addNode(list, cur);
10254 }
10255 }
10256 }
10257 break;
10258 case XML_ATTRIBUTE_NODE:{
10259 xmlAttrPtr attr = (xmlAttrPtr) cur;
10260
10261 if (xmlStrEqual(name, attr->name)) {
10262 if (prefix == NULL) {
10263 if ((attr->ns == NULL) ||
10264 (attr->ns->prefix == NULL)) {
10265 n++;
10266 if (n == indx)
10267 addNode(list, cur);
10268 }
10269 } else {
10270 if ((attr->ns != NULL) &&
10271 (xmlStrEqual(URI,
10272 attr->ns->
10273 href))) {
10274 n++;
10275 if (n == indx)
10276 addNode(list, cur);
10277 }
10278 }
10279 }
10280 break;
10281 }
10282 case XML_NAMESPACE_DECL:
10283 if (cur->type == XML_NAMESPACE_DECL) {
10284 xmlNsPtr ns = (xmlNsPtr) cur;
10285
10286 if ((ns->prefix != NULL) && (name != NULL)
10287 && (xmlStrEqual(ns->prefix, name))) {
10288 n++;
10289 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000010290 xmlXPathNodeSetAddNs(list,
10291 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010292 }
10293 }
10294 break;
10295 default:
10296 break;
10297 }
10298 break;
10299 break;
10300 }
10301 } while (n < indx);
10302 }
10303 ctxt->context->node = tmp;
10304#ifdef DEBUG_STEP_NTH
10305 xmlGenericError(xmlGenericErrorContext,
10306 "\nExamined %d nodes, found %d nodes at that step\n",
10307 t, list->nodeNr);
10308#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000010309 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000010310 if ((obj->boolval) && (obj->user != NULL)) {
10311 ctxt->value->boolval = 1;
10312 ctxt->value->user = obj->user;
10313 obj->user = NULL;
10314 obj->boolval = 0;
10315 }
10316 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010317 return(t);
10318}
10319
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010320static int
10321xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10322 xmlXPathStepOpPtr op, xmlNodePtr * first);
10323
Daniel Veillardf06307e2001-07-03 10:35:50 +000010324/**
10325 * xmlXPathCompOpEvalFirst:
10326 * @ctxt: the XPath parser context with the compiled expression
10327 * @op: an XPath compiled operation
10328 * @first: the first elem found so far
10329 *
10330 * Evaluate the Precompiled XPath operation searching only the first
10331 * element in document order
10332 *
10333 * Returns the number of examined objects.
10334 */
10335static int
10336xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10337 xmlXPathStepOpPtr op, xmlNodePtr * first)
10338{
10339 int total = 0, cur;
10340 xmlXPathCompExprPtr comp;
10341 xmlXPathObjectPtr arg1, arg2;
10342
Daniel Veillard556c6682001-10-06 09:59:51 +000010343 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010344 comp = ctxt->comp;
10345 switch (op->op) {
10346 case XPATH_OP_END:
10347 return (0);
10348 case XPATH_OP_UNION:
10349 total =
10350 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10351 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010352 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010353 if ((ctxt->value != NULL)
10354 && (ctxt->value->type == XPATH_NODESET)
10355 && (ctxt->value->nodesetval != NULL)
10356 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10357 /*
10358 * limit tree traversing to first node in the result
10359 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010360 /*
10361 * OPTIMIZE TODO: This implicitely sorts
10362 * the result, even if not needed. E.g. if the argument
10363 * of the count() function, no sorting is needed.
10364 * OPTIMIZE TODO: How do we know if the node-list wasn't
10365 * aready sorted?
10366 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010367 if (ctxt->value->nodesetval->nodeNr > 1)
10368 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010369 *first = ctxt->value->nodesetval->nodeTab[0];
10370 }
10371 cur =
10372 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10373 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010374 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 CHECK_TYPE0(XPATH_NODESET);
10376 arg2 = valuePop(ctxt);
10377
10378 CHECK_TYPE0(XPATH_NODESET);
10379 arg1 = valuePop(ctxt);
10380
10381 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10382 arg2->nodesetval);
10383 valuePush(ctxt, arg1);
10384 xmlXPathFreeObject(arg2);
10385 /* optimizer */
10386 if (total > cur)
10387 xmlXPathCompSwap(op);
10388 return (total + cur);
10389 case XPATH_OP_ROOT:
10390 xmlXPathRoot(ctxt);
10391 return (0);
10392 case XPATH_OP_NODE:
10393 if (op->ch1 != -1)
10394 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010395 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010396 if (op->ch2 != -1)
10397 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010398 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010399 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10400 return (total);
10401 case XPATH_OP_RESET:
10402 if (op->ch1 != -1)
10403 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010404 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010405 if (op->ch2 != -1)
10406 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010407 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010408 ctxt->context->node = NULL;
10409 return (total);
10410 case XPATH_OP_COLLECT:{
10411 if (op->ch1 == -1)
10412 return (total);
10413
10414 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010415 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010416
10417 /*
10418 * Optimization for [n] selection where n is a number
10419 */
10420 if ((op->ch2 != -1) &&
10421 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10422 (comp->steps[op->ch2].ch1 == -1) &&
10423 (comp->steps[op->ch2].ch2 != -1) &&
10424 (comp->steps[comp->steps[op->ch2].ch2].op ==
10425 XPATH_OP_VALUE)) {
10426 xmlXPathObjectPtr val;
10427
10428 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10429 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10430 int indx = (int) val->floatval;
10431
10432 if (val->floatval == (float) indx) {
10433 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
10434 first, NULL);
10435 return (total);
10436 }
10437 }
10438 }
10439 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10440 return (total);
10441 }
10442 case XPATH_OP_VALUE:
10443 valuePush(ctxt,
10444 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10445 return (0);
10446 case XPATH_OP_SORT:
10447 if (op->ch1 != -1)
10448 total +=
10449 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10450 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010451 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010452 if ((ctxt->value != NULL)
10453 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010454 && (ctxt->value->nodesetval != NULL)
10455 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000010456 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10457 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010458#ifdef XP_OPTIMIZED_FILTER_FIRST
10459 case XPATH_OP_FILTER:
10460 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10461 return (total);
10462#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000010463 default:
10464 return (xmlXPathCompOpEval(ctxt, op));
10465 }
10466}
10467
10468/**
10469 * xmlXPathCompOpEvalLast:
10470 * @ctxt: the XPath parser context with the compiled expression
10471 * @op: an XPath compiled operation
10472 * @last: the last elem found so far
10473 *
10474 * Evaluate the Precompiled XPath operation searching only the last
10475 * element in document order
10476 *
William M. Brack08171912003-12-29 02:52:11 +000010477 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010478 */
10479static int
10480xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10481 xmlNodePtr * last)
10482{
10483 int total = 0, cur;
10484 xmlXPathCompExprPtr comp;
10485 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010486 xmlNodePtr bak;
10487 xmlDocPtr bakd;
10488 int pp;
10489 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010490
Daniel Veillard556c6682001-10-06 09:59:51 +000010491 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010492 comp = ctxt->comp;
10493 switch (op->op) {
10494 case XPATH_OP_END:
10495 return (0);
10496 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010497 bakd = ctxt->context->doc;
10498 bak = ctxt->context->node;
10499 pp = ctxt->context->proximityPosition;
10500 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010501 total =
10502 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010503 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010504 if ((ctxt->value != NULL)
10505 && (ctxt->value->type == XPATH_NODESET)
10506 && (ctxt->value->nodesetval != NULL)
10507 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10508 /*
10509 * limit tree traversing to first node in the result
10510 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010511 if (ctxt->value->nodesetval->nodeNr > 1)
10512 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010513 *last =
10514 ctxt->value->nodesetval->nodeTab[ctxt->value->
10515 nodesetval->nodeNr -
10516 1];
10517 }
William M. Brackce4fc562004-01-22 02:47:18 +000010518 ctxt->context->doc = bakd;
10519 ctxt->context->node = bak;
10520 ctxt->context->proximityPosition = pp;
10521 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010522 cur =
10523 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010524 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 if ((ctxt->value != NULL)
10526 && (ctxt->value->type == XPATH_NODESET)
10527 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010528 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010529 }
10530 CHECK_TYPE0(XPATH_NODESET);
10531 arg2 = valuePop(ctxt);
10532
10533 CHECK_TYPE0(XPATH_NODESET);
10534 arg1 = valuePop(ctxt);
10535
10536 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10537 arg2->nodesetval);
10538 valuePush(ctxt, arg1);
10539 xmlXPathFreeObject(arg2);
10540 /* optimizer */
10541 if (total > cur)
10542 xmlXPathCompSwap(op);
10543 return (total + cur);
10544 case XPATH_OP_ROOT:
10545 xmlXPathRoot(ctxt);
10546 return (0);
10547 case XPATH_OP_NODE:
10548 if (op->ch1 != -1)
10549 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010550 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010551 if (op->ch2 != -1)
10552 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010553 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010554 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10555 return (total);
10556 case XPATH_OP_RESET:
10557 if (op->ch1 != -1)
10558 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010559 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010560 if (op->ch2 != -1)
10561 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010562 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010563 ctxt->context->node = NULL;
10564 return (total);
10565 case XPATH_OP_COLLECT:{
10566 if (op->ch1 == -1)
10567 return (0);
10568
10569 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010570 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010571
10572 /*
10573 * Optimization for [n] selection where n is a number
10574 */
10575 if ((op->ch2 != -1) &&
10576 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10577 (comp->steps[op->ch2].ch1 == -1) &&
10578 (comp->steps[op->ch2].ch2 != -1) &&
10579 (comp->steps[comp->steps[op->ch2].ch2].op ==
10580 XPATH_OP_VALUE)) {
10581 xmlXPathObjectPtr val;
10582
10583 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10584 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10585 int indx = (int) val->floatval;
10586
10587 if (val->floatval == (float) indx) {
10588 total +=
10589 xmlXPathNodeCollectAndTestNth(ctxt, op,
10590 indx, NULL,
10591 last);
10592 return (total);
10593 }
10594 }
10595 }
10596 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10597 return (total);
10598 }
10599 case XPATH_OP_VALUE:
10600 valuePush(ctxt,
10601 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10602 return (0);
10603 case XPATH_OP_SORT:
10604 if (op->ch1 != -1)
10605 total +=
10606 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10607 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010608 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010609 if ((ctxt->value != NULL)
10610 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010611 && (ctxt->value->nodesetval != NULL)
10612 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000010613 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10614 return (total);
10615 default:
10616 return (xmlXPathCompOpEval(ctxt, op));
10617 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010618}
10619
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010620#ifdef XP_OPTIMIZED_FILTER_FIRST
10621static int
10622xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10623 xmlXPathStepOpPtr op, xmlNodePtr * first)
10624{
10625 int total = 0;
10626 xmlXPathCompExprPtr comp;
10627 xmlXPathObjectPtr res;
10628 xmlXPathObjectPtr obj;
10629 xmlNodeSetPtr oldset;
10630 xmlNodePtr oldnode;
10631 xmlDocPtr oldDoc;
10632 int i;
10633
10634 CHECK_ERROR0;
10635 comp = ctxt->comp;
10636 /*
10637 * Optimization for ()[last()] selection i.e. the last elem
10638 */
10639 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10640 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10641 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10642 int f = comp->steps[op->ch2].ch1;
10643
10644 if ((f != -1) &&
10645 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10646 (comp->steps[f].value5 == NULL) &&
10647 (comp->steps[f].value == 0) &&
10648 (comp->steps[f].value4 != NULL) &&
10649 (xmlStrEqual
10650 (comp->steps[f].value4, BAD_CAST "last"))) {
10651 xmlNodePtr last = NULL;
10652
10653 total +=
10654 xmlXPathCompOpEvalLast(ctxt,
10655 &comp->steps[op->ch1],
10656 &last);
10657 CHECK_ERROR0;
10658 /*
10659 * The nodeset should be in document order,
10660 * Keep only the last value
10661 */
10662 if ((ctxt->value != NULL) &&
10663 (ctxt->value->type == XPATH_NODESET) &&
10664 (ctxt->value->nodesetval != NULL) &&
10665 (ctxt->value->nodesetval->nodeTab != NULL) &&
10666 (ctxt->value->nodesetval->nodeNr > 1)) {
10667 ctxt->value->nodesetval->nodeTab[0] =
10668 ctxt->value->nodesetval->nodeTab[ctxt->
10669 value->
10670 nodesetval->
10671 nodeNr -
10672 1];
10673 ctxt->value->nodesetval->nodeNr = 1;
10674 *first = *(ctxt->value->nodesetval->nodeTab);
10675 }
10676 return (total);
10677 }
10678 }
10679
10680 if (op->ch1 != -1)
10681 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10682 CHECK_ERROR0;
10683 if (op->ch2 == -1)
10684 return (total);
10685 if (ctxt->value == NULL)
10686 return (total);
10687
10688#ifdef LIBXML_XPTR_ENABLED
10689 oldnode = ctxt->context->node;
10690 /*
10691 * Hum are we filtering the result of an XPointer expression
10692 */
10693 if (ctxt->value->type == XPATH_LOCATIONSET) {
10694 xmlXPathObjectPtr tmp = NULL;
10695 xmlLocationSetPtr newlocset = NULL;
10696 xmlLocationSetPtr oldlocset;
10697
10698 /*
10699 * Extract the old locset, and then evaluate the result of the
10700 * expression for all the element in the locset. use it to grow
10701 * up a new locset.
10702 */
10703 CHECK_TYPE0(XPATH_LOCATIONSET);
10704 obj = valuePop(ctxt);
10705 oldlocset = obj->user;
10706 ctxt->context->node = NULL;
10707
10708 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10709 ctxt->context->contextSize = 0;
10710 ctxt->context->proximityPosition = 0;
10711 if (op->ch2 != -1)
10712 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10713 res = valuePop(ctxt);
10714 if (res != NULL)
10715 xmlXPathFreeObject(res);
10716 valuePush(ctxt, obj);
10717 CHECK_ERROR0;
10718 return (total);
10719 }
10720 newlocset = xmlXPtrLocationSetCreate(NULL);
10721
10722 for (i = 0; i < oldlocset->locNr; i++) {
10723 /*
10724 * Run the evaluation with a node list made of a
10725 * single item in the nodelocset.
10726 */
10727 ctxt->context->node = oldlocset->locTab[i]->user;
10728 ctxt->context->contextSize = oldlocset->locNr;
10729 ctxt->context->proximityPosition = i + 1;
10730 if (tmp == NULL)
10731 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10732 else {
10733 *(tmp->nodesetval->nodeTab) = ctxt->context->node;
10734 tmp->nodesetval->nodeNr = 1;
10735 }
10736 valuePush(ctxt, tmp);
10737 if (op->ch2 != -1)
10738 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10739 if (ctxt->error != XPATH_EXPRESSION_OK) {
10740 xmlXPathFreeObject(obj);
10741 return(0);
10742 }
10743 /*
10744 * The result of the evaluation need to be tested to
10745 * decided whether the filter succeeded or not
10746 */
10747 res = valuePop(ctxt);
10748 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10749 xmlXPtrLocationSetAdd(newlocset,
10750 xmlXPathObjectCopy(oldlocset->locTab[i]));
10751 }
10752 /*
10753 * Cleanup
10754 */
10755 if (res != NULL)
10756 xmlXPathFreeObject(res);
10757 if (ctxt->value == tmp) {
10758 valuePop(ctxt);
10759 tmp->nodesetval->nodeNr = 0;
10760 /*
10761 * REVISIT TODO: Don't free the temporary nodeset
10762 * in order to avoid massive recreation inside this
10763 * loop.
10764 */
10765 /* xmlXPathFreeObject(res); */
10766 } else {
10767 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10768 }
10769 ctxt->context->node = NULL;
10770 /*
10771 * Only put the first node in the result, then leave.
10772 */
10773 if (newlocset->locNr > 0) {
10774 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
10775 break;
10776 }
10777 }
10778 if (tmp != NULL)
10779 xmlXPathFreeObject(tmp);
10780 /*
10781 * The result is used as the new evaluation locset.
10782 */
10783 xmlXPathFreeObject(obj);
10784 ctxt->context->node = NULL;
10785 ctxt->context->contextSize = -1;
10786 ctxt->context->proximityPosition = -1;
10787 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10788 ctxt->context->node = oldnode;
10789 return (total);
10790 }
10791#endif /* LIBXML_XPTR_ENABLED */
10792
10793 /*
10794 * Extract the old set, and then evaluate the result of the
10795 * expression for all the element in the set. use it to grow
10796 * up a new set.
10797 */
10798 CHECK_TYPE0(XPATH_NODESET);
10799 obj = valuePop(ctxt);
10800 oldset = obj->nodesetval;
10801
10802 oldnode = ctxt->context->node;
10803 oldDoc = ctxt->context->doc;
10804 ctxt->context->node = NULL;
10805
10806 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10807 ctxt->context->contextSize = 0;
10808 ctxt->context->proximityPosition = 0;
10809 /* QUESTION TODO: Why was this code commented out?
10810 if (op->ch2 != -1)
10811 total +=
10812 xmlXPathCompOpEval(ctxt,
10813 &comp->steps[op->ch2]);
10814 CHECK_ERROR0;
10815 res = valuePop(ctxt);
10816 if (res != NULL)
10817 xmlXPathFreeObject(res);
10818 */
10819 valuePush(ctxt, obj);
10820 ctxt->context->node = oldnode;
10821 CHECK_ERROR0;
10822 } else {
10823 xmlNodeSetPtr newset;
10824 xmlXPathObjectPtr tmp = NULL;
10825 /*
10826 * Initialize the new set.
10827 * Also set the xpath document in case things like
10828 * key() evaluation are attempted on the predicate
10829 */
10830 newset = xmlXPathNodeSetCreate(NULL);
10831
10832 for (i = 0; i < oldset->nodeNr; i++) {
10833 /*
10834 * Run the evaluation with a node list made of
10835 * a single item in the nodeset.
10836 */
10837 ctxt->context->node = oldset->nodeTab[i];
10838 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10839 (oldset->nodeTab[i]->doc != NULL))
10840 ctxt->context->doc = oldset->nodeTab[i]->doc;
10841 if (tmp == NULL)
10842 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10843 else {
10844 *(tmp->nodesetval->nodeTab) = ctxt->context->node;
10845 tmp->nodesetval->nodeNr = 1;
10846 }
10847 valuePush(ctxt, tmp);
10848 ctxt->context->contextSize = oldset->nodeNr;
10849 ctxt->context->proximityPosition = i + 1;
10850 if (op->ch2 != -1)
10851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10852 if (ctxt->error != XPATH_EXPRESSION_OK) {
10853 xmlXPathFreeNodeSet(newset);
10854 xmlXPathFreeObject(obj);
10855 return(0);
10856 }
10857 /*
10858 * The result of the evaluation needs to be tested to
10859 * decide whether the filter succeeded or not
10860 */
10861 res = valuePop(ctxt);
10862 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10863 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10864 }
10865 /*
10866 * Cleanup
10867 */
10868 if (res != NULL)
10869 xmlXPathFreeObject(res);
10870 if (ctxt->value == tmp) {
10871 valuePop(ctxt);
10872 tmp->nodesetval->nodeNr = 0;
10873 /*
10874 * REVISIT TODO: Don't free the temporary nodeset
10875 * in order to avoid massive recreation inside this
10876 * loop.
10877 */
10878 /* xmlXPathFreeObject(res); */
10879 } else {
10880 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10881 }
10882 ctxt->context->node = NULL;
10883 /*
10884 * Only put the first node in the result, then leave.
10885 */
10886 if (newset->nodeNr > 0) {
10887 *first = *(newset->nodeTab);
10888 break;
10889 }
10890 }
10891 if (tmp != NULL)
10892 xmlXPathFreeObject(tmp);
10893 /*
10894 * The result is used as the new evaluation set.
10895 */
10896 xmlXPathFreeObject(obj);
10897 ctxt->context->node = NULL;
10898 ctxt->context->contextSize = -1;
10899 ctxt->context->proximityPosition = -1;
10900 /* may want to move this past the '}' later */
10901 ctxt->context->doc = oldDoc;
10902 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10903 }
10904 ctxt->context->node = oldnode;
10905 return(total);
10906}
10907#endif /* XP_OPTIMIZED_FILTER_FIRST */
10908
Owen Taylor3473f882001-02-23 17:55:21 +000010909/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010910 * xmlXPathCompOpEval:
10911 * @ctxt: the XPath parser context with the compiled expression
10912 * @op: an XPath compiled operation
10913 *
10914 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010915 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010916 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010917static int
10918xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10919{
10920 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010921 int equal, ret;
10922 xmlXPathCompExprPtr comp;
10923 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010924 xmlNodePtr bak;
10925 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010926 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010927 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010928
Daniel Veillard556c6682001-10-06 09:59:51 +000010929 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010930 comp = ctxt->comp;
10931 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010932 case XPATH_OP_END:
10933 return (0);
10934 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010935 bakd = ctxt->context->doc;
10936 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010937 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010938 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010939 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010940 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010941 xmlXPathBooleanFunction(ctxt, 1);
10942 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10943 return (total);
10944 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010945 ctxt->context->doc = bakd;
10946 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010947 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010948 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010949 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010950 if (ctxt->error) {
10951 xmlXPathFreeObject(arg2);
10952 return(0);
10953 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010954 xmlXPathBooleanFunction(ctxt, 1);
10955 arg1 = valuePop(ctxt);
10956 arg1->boolval &= arg2->boolval;
10957 valuePush(ctxt, arg1);
10958 xmlXPathFreeObject(arg2);
10959 return (total);
10960 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010961 bakd = ctxt->context->doc;
10962 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010963 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010964 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010966 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010967 xmlXPathBooleanFunction(ctxt, 1);
10968 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10969 return (total);
10970 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010971 ctxt->context->doc = bakd;
10972 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010973 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010974 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010975 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010976 if (ctxt->error) {
10977 xmlXPathFreeObject(arg2);
10978 return(0);
10979 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010980 xmlXPathBooleanFunction(ctxt, 1);
10981 arg1 = valuePop(ctxt);
10982 arg1->boolval |= arg2->boolval;
10983 valuePush(ctxt, arg1);
10984 xmlXPathFreeObject(arg2);
10985 return (total);
10986 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010987 bakd = ctxt->context->doc;
10988 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010989 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010990 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010992 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010993 ctxt->context->doc = bakd;
10994 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010995 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010996 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010998 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010999 if (op->value)
11000 equal = xmlXPathEqualValues(ctxt);
11001 else
11002 equal = xmlXPathNotEqualValues(ctxt);
11003 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011004 return (total);
11005 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011006 bakd = ctxt->context->doc;
11007 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000011008 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000011009 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011010 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011011 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011012 ctxt->context->doc = bakd;
11013 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011014 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011015 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011017 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011018 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11019 valuePush(ctxt, xmlXPathNewBoolean(ret));
11020 return (total);
11021 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011022 bakd = ctxt->context->doc;
11023 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000011024 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000011025 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011026 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011027 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011028 if (op->ch2 != -1) {
11029 ctxt->context->doc = bakd;
11030 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011031 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011032 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011034 }
Daniel Veillard556c6682001-10-06 09:59:51 +000011035 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011036 if (op->value == 0)
11037 xmlXPathSubValues(ctxt);
11038 else if (op->value == 1)
11039 xmlXPathAddValues(ctxt);
11040 else if (op->value == 2)
11041 xmlXPathValueFlipSign(ctxt);
11042 else if (op->value == 3) {
11043 CAST_TO_NUMBER;
11044 CHECK_TYPE0(XPATH_NUMBER);
11045 }
11046 return (total);
11047 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011048 bakd = ctxt->context->doc;
11049 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000011050 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000011051 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011053 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011054 ctxt->context->doc = bakd;
11055 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011056 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011057 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011058 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011059 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011060 if (op->value == 0)
11061 xmlXPathMultValues(ctxt);
11062 else if (op->value == 1)
11063 xmlXPathDivValues(ctxt);
11064 else if (op->value == 2)
11065 xmlXPathModValues(ctxt);
11066 return (total);
11067 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011068 bakd = ctxt->context->doc;
11069 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000011070 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000011071 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011072 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011073 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011074 ctxt->context->doc = bakd;
11075 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011076 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011077 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011078 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011079 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011080 CHECK_TYPE0(XPATH_NODESET);
11081 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011082
Daniel Veillardf06307e2001-07-03 10:35:50 +000011083 CHECK_TYPE0(XPATH_NODESET);
11084 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011085
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011086 if ((arg1->nodesetval == NULL) ||
11087 ((arg2->nodesetval != NULL) &&
11088 (arg2->nodesetval->nodeNr != 0)))
11089 {
11090 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11091 arg2->nodesetval);
11092 }
11093
Daniel Veillardf06307e2001-07-03 10:35:50 +000011094 valuePush(ctxt, arg1);
11095 xmlXPathFreeObject(arg2);
11096 return (total);
11097 case XPATH_OP_ROOT:
11098 xmlXPathRoot(ctxt);
11099 return (total);
11100 case XPATH_OP_NODE:
11101 if (op->ch1 != -1)
11102 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011103 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011104 if (op->ch2 != -1)
11105 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011106 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011107 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
11108 return (total);
11109 case XPATH_OP_RESET:
11110 if (op->ch1 != -1)
11111 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011112 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011113 if (op->ch2 != -1)
11114 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011115 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011116 ctxt->context->node = NULL;
11117 return (total);
11118 case XPATH_OP_COLLECT:{
11119 if (op->ch1 == -1)
11120 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011121
Daniel Veillardf06307e2001-07-03 10:35:50 +000011122 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011123 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011124
Daniel Veillardf06307e2001-07-03 10:35:50 +000011125 /*
11126 * Optimization for [n] selection where n is a number
11127 */
11128 if ((op->ch2 != -1) &&
11129 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
11130 (comp->steps[op->ch2].ch1 == -1) &&
11131 (comp->steps[op->ch2].ch2 != -1) &&
11132 (comp->steps[comp->steps[op->ch2].ch2].op ==
11133 XPATH_OP_VALUE)) {
11134 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000011135
Daniel Veillardf06307e2001-07-03 10:35:50 +000011136 val = comp->steps[comp->steps[op->ch2].ch2].value4;
11137 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
11138 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011139
Daniel Veillardf06307e2001-07-03 10:35:50 +000011140 if (val->floatval == (float) indx) {
11141 total +=
11142 xmlXPathNodeCollectAndTestNth(ctxt, op,
11143 indx, NULL,
11144 NULL);
11145 return (total);
11146 }
11147 }
11148 }
11149 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
11150 return (total);
11151 }
11152 case XPATH_OP_VALUE:
11153 valuePush(ctxt,
11154 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
11155 return (total);
11156 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000011157 xmlXPathObjectPtr val;
11158
Daniel Veillardf06307e2001-07-03 10:35:50 +000011159 if (op->ch1 != -1)
11160 total +=
11161 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011162 if (op->value5 == NULL) {
11163 val = xmlXPathVariableLookup(ctxt->context, op->value4);
11164 if (val == NULL) {
11165 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
11166 return(0);
11167 }
11168 valuePush(ctxt, val);
11169 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011170 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011171
Daniel Veillardf06307e2001-07-03 10:35:50 +000011172 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11173 if (URI == NULL) {
11174 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011175 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000011176 op->value4, op->value5);
11177 return (total);
11178 }
Daniel Veillard556c6682001-10-06 09:59:51 +000011179 val = xmlXPathVariableLookupNS(ctxt->context,
11180 op->value4, URI);
11181 if (val == NULL) {
11182 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
11183 return(0);
11184 }
11185 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011186 }
11187 return (total);
11188 }
11189 case XPATH_OP_FUNCTION:{
11190 xmlXPathFunction func;
11191 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000011192 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011193
11194 if (op->ch1 != -1)
11195 total +=
11196 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011197 if (ctxt->valueNr < op->value) {
11198 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011199 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000011200 ctxt->error = XPATH_INVALID_OPERAND;
11201 return (total);
11202 }
11203 for (i = 0; i < op->value; i++)
11204 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
11205 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011206 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000011207 ctxt->error = XPATH_INVALID_OPERAND;
11208 return (total);
11209 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011210 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000011211 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011212 else {
11213 const xmlChar *URI = NULL;
11214
11215 if (op->value5 == NULL)
11216 func =
11217 xmlXPathFunctionLookup(ctxt->context,
11218 op->value4);
11219 else {
11220 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11221 if (URI == NULL) {
11222 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011223 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000011224 op->value4, op->value5);
11225 return (total);
11226 }
11227 func = xmlXPathFunctionLookupNS(ctxt->context,
11228 op->value4, URI);
11229 }
11230 if (func == NULL) {
11231 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011232 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000011233 op->value4);
11234 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011235 }
William M. Brackad0e67c2004-12-01 14:35:10 +000011236 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011237 op->cacheURI = (void *) URI;
11238 }
11239 oldFunc = ctxt->context->function;
11240 oldFuncURI = ctxt->context->functionURI;
11241 ctxt->context->function = op->value4;
11242 ctxt->context->functionURI = op->cacheURI;
11243 func(ctxt, op->value);
11244 ctxt->context->function = oldFunc;
11245 ctxt->context->functionURI = oldFuncURI;
11246 return (total);
11247 }
11248 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000011249 bakd = ctxt->context->doc;
11250 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000011251 pp = ctxt->context->proximityPosition;
11252 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011253 if (op->ch1 != -1)
11254 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000011255 ctxt->context->contextSize = cs;
11256 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000011257 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000011258 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000011259 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000011260 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000011262 ctxt->context->doc = bakd;
11263 ctxt->context->node = bak;
11264 CHECK_ERROR0;
11265 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011266 return (total);
11267 case XPATH_OP_PREDICATE:
11268 case XPATH_OP_FILTER:{
11269 xmlXPathObjectPtr res;
11270 xmlXPathObjectPtr obj, tmp;
11271 xmlNodeSetPtr newset = NULL;
11272 xmlNodeSetPtr oldset;
11273 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000011274 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011275 int i;
11276
11277 /*
11278 * Optimization for ()[1] selection i.e. the first elem
11279 */
11280 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011281#ifdef XP_OPTIMIZED_FILTER_FIRST
11282 /*
11283 * FILTER TODO: Can we assume that the inner processing
11284 * will result in an ordered list if we have an
11285 * XPATH_OP_FILTER?
11286 * What about an additional field or flag on
11287 * xmlXPathObject like @sorted ? This way we wouln'd need
11288 * to assume anything, so it would be more robust and
11289 * easier to optimize.
11290 */
11291 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11292 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11293#else
11294 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11295#endif
11296 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011297 xmlXPathObjectPtr val;
11298
11299 val = comp->steps[op->ch2].value4;
11300 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11301 (val->floatval == 1.0)) {
11302 xmlNodePtr first = NULL;
11303
11304 total +=
11305 xmlXPathCompOpEvalFirst(ctxt,
11306 &comp->steps[op->ch1],
11307 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000011308 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011309 /*
11310 * The nodeset should be in document order,
11311 * Keep only the first value
11312 */
11313 if ((ctxt->value != NULL) &&
11314 (ctxt->value->type == XPATH_NODESET) &&
11315 (ctxt->value->nodesetval != NULL) &&
11316 (ctxt->value->nodesetval->nodeNr > 1))
11317 ctxt->value->nodesetval->nodeNr = 1;
11318 return (total);
11319 }
11320 }
11321 /*
11322 * Optimization for ()[last()] selection i.e. the last elem
11323 */
11324 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11325 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11326 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11327 int f = comp->steps[op->ch2].ch1;
11328
11329 if ((f != -1) &&
11330 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11331 (comp->steps[f].value5 == NULL) &&
11332 (comp->steps[f].value == 0) &&
11333 (comp->steps[f].value4 != NULL) &&
11334 (xmlStrEqual
11335 (comp->steps[f].value4, BAD_CAST "last"))) {
11336 xmlNodePtr last = NULL;
11337
11338 total +=
11339 xmlXPathCompOpEvalLast(ctxt,
11340 &comp->steps[op->ch1],
11341 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000011342 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011343 /*
11344 * The nodeset should be in document order,
11345 * Keep only the last value
11346 */
11347 if ((ctxt->value != NULL) &&
11348 (ctxt->value->type == XPATH_NODESET) &&
11349 (ctxt->value->nodesetval != NULL) &&
11350 (ctxt->value->nodesetval->nodeTab != NULL) &&
11351 (ctxt->value->nodesetval->nodeNr > 1)) {
11352 ctxt->value->nodesetval->nodeTab[0] =
11353 ctxt->value->nodesetval->nodeTab[ctxt->
11354 value->
11355 nodesetval->
11356 nodeNr -
11357 1];
11358 ctxt->value->nodesetval->nodeNr = 1;
11359 }
11360 return (total);
11361 }
11362 }
11363
11364 if (op->ch1 != -1)
11365 total +=
11366 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011367 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011368 if (op->ch2 == -1)
11369 return (total);
11370 if (ctxt->value == NULL)
11371 return (total);
11372
11373 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011374
11375#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000011376 /*
11377 * Hum are we filtering the result of an XPointer expression
11378 */
11379 if (ctxt->value->type == XPATH_LOCATIONSET) {
11380 xmlLocationSetPtr newlocset = NULL;
11381 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011382
Daniel Veillardf06307e2001-07-03 10:35:50 +000011383 /*
11384 * Extract the old locset, and then evaluate the result of the
11385 * expression for all the element in the locset. use it to grow
11386 * up a new locset.
11387 */
11388 CHECK_TYPE0(XPATH_LOCATIONSET);
11389 obj = valuePop(ctxt);
11390 oldlocset = obj->user;
11391 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011392
Daniel Veillardf06307e2001-07-03 10:35:50 +000011393 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
11394 ctxt->context->contextSize = 0;
11395 ctxt->context->proximityPosition = 0;
11396 if (op->ch2 != -1)
11397 total +=
11398 xmlXPathCompOpEval(ctxt,
11399 &comp->steps[op->ch2]);
11400 res = valuePop(ctxt);
11401 if (res != NULL)
11402 xmlXPathFreeObject(res);
11403 valuePush(ctxt, obj);
11404 CHECK_ERROR0;
11405 return (total);
11406 }
11407 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011408
Daniel Veillardf06307e2001-07-03 10:35:50 +000011409 for (i = 0; i < oldlocset->locNr; i++) {
11410 /*
11411 * Run the evaluation with a node list made of a
11412 * single item in the nodelocset.
11413 */
11414 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011415 ctxt->context->contextSize = oldlocset->locNr;
11416 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000011417 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11418 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011419
Daniel Veillardf06307e2001-07-03 10:35:50 +000011420 if (op->ch2 != -1)
11421 total +=
11422 xmlXPathCompOpEval(ctxt,
11423 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011424 if (ctxt->error != XPATH_EXPRESSION_OK) {
11425 xmlXPathFreeObject(obj);
11426 return(0);
11427 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011428
Daniel Veillardf06307e2001-07-03 10:35:50 +000011429 /*
11430 * The result of the evaluation need to be tested to
11431 * decided whether the filter succeeded or not
11432 */
11433 res = valuePop(ctxt);
11434 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
11435 xmlXPtrLocationSetAdd(newlocset,
11436 xmlXPathObjectCopy
11437 (oldlocset->locTab[i]));
11438 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011439
Daniel Veillardf06307e2001-07-03 10:35:50 +000011440 /*
11441 * Cleanup
11442 */
11443 if (res != NULL)
11444 xmlXPathFreeObject(res);
11445 if (ctxt->value == tmp) {
11446 res = valuePop(ctxt);
11447 xmlXPathFreeObject(res);
11448 }
11449
11450 ctxt->context->node = NULL;
11451 }
11452
11453 /*
11454 * The result is used as the new evaluation locset.
11455 */
11456 xmlXPathFreeObject(obj);
11457 ctxt->context->node = NULL;
11458 ctxt->context->contextSize = -1;
11459 ctxt->context->proximityPosition = -1;
11460 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
11461 ctxt->context->node = oldnode;
11462 return (total);
11463 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011464#endif /* LIBXML_XPTR_ENABLED */
11465
Daniel Veillardf06307e2001-07-03 10:35:50 +000011466 /*
11467 * Extract the old set, and then evaluate the result of the
11468 * expression for all the element in the set. use it to grow
11469 * up a new set.
11470 */
11471 CHECK_TYPE0(XPATH_NODESET);
11472 obj = valuePop(ctxt);
11473 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000011474
Daniel Veillardf06307e2001-07-03 10:35:50 +000011475 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000011476 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011477 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011478
Daniel Veillardf06307e2001-07-03 10:35:50 +000011479 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
11480 ctxt->context->contextSize = 0;
11481 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000011482/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000011483 if (op->ch2 != -1)
11484 total +=
11485 xmlXPathCompOpEval(ctxt,
11486 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011487 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011488 res = valuePop(ctxt);
11489 if (res != NULL)
11490 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000011491*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000011492 valuePush(ctxt, obj);
11493 ctxt->context->node = oldnode;
11494 CHECK_ERROR0;
11495 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011496 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011497 /*
11498 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000011499 * Also set the xpath document in case things like
11500 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000011501 */
11502 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011503
Daniel Veillardf06307e2001-07-03 10:35:50 +000011504 for (i = 0; i < oldset->nodeNr; i++) {
11505 /*
11506 * Run the evaluation with a node list made of
11507 * a single item in the nodeset.
11508 */
11509 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000011510 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
11511 (oldset->nodeTab[i]->doc != NULL))
11512 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011513 if (tmp == NULL)
11514 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11515 else {
11516 *(tmp->nodesetval->nodeTab) = ctxt->context->node;
11517 tmp->nodesetval->nodeNr = 1;
11518 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011519 valuePush(ctxt, tmp);
11520 ctxt->context->contextSize = oldset->nodeNr;
11521 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011522
Daniel Veillardf06307e2001-07-03 10:35:50 +000011523 if (op->ch2 != -1)
11524 total +=
11525 xmlXPathCompOpEval(ctxt,
11526 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011527 if (ctxt->error != XPATH_EXPRESSION_OK) {
11528 xmlXPathFreeNodeSet(newset);
11529 xmlXPathFreeObject(obj);
11530 return(0);
11531 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011532
Daniel Veillardf06307e2001-07-03 10:35:50 +000011533 /*
William M. Brack08171912003-12-29 02:52:11 +000011534 * The result of the evaluation needs to be tested to
11535 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000011536 */
11537 res = valuePop(ctxt);
11538 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
11539 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
11540 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011541
Daniel Veillardf06307e2001-07-03 10:35:50 +000011542 /*
11543 * Cleanup
11544 */
11545 if (res != NULL)
11546 xmlXPathFreeObject(res);
11547 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011548 valuePop(ctxt);
11549 tmp->nodesetval->nodeNr = 0;
11550 /*
11551 * REVISIT TODO: Don't free the temporary nodeset
11552 * in order to avoid massive recreation inside this
11553 * loop.
11554 */
11555 /* xmlXPathFreeObject(res); */
11556 } else
11557 tmp = xmlXPathNewNodeSet(ctxt->context->node);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011558
Daniel Veillardf06307e2001-07-03 10:35:50 +000011559 ctxt->context->node = NULL;
11560 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011561 if (tmp != NULL)
11562 xmlXPathFreeObject(tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011563
11564 /*
11565 * The result is used as the new evaluation set.
11566 */
11567 xmlXPathFreeObject(obj);
11568 ctxt->context->node = NULL;
11569 ctxt->context->contextSize = -1;
11570 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000011571 /* may want to move this past the '}' later */
11572 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011573 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
11574 }
11575 ctxt->context->node = oldnode;
11576 return (total);
11577 }
11578 case XPATH_OP_SORT:
11579 if (op->ch1 != -1)
11580 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011581 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011582 if ((ctxt->value != NULL) &&
11583 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011584 (ctxt->value->nodesetval != NULL) &&
11585 (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000011586 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11587 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011588#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000011589 case XPATH_OP_RANGETO:{
11590 xmlXPathObjectPtr range;
11591 xmlXPathObjectPtr res, obj;
11592 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000011593 xmlLocationSetPtr newlocset = NULL;
11594 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011595 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000011596 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011597
Daniel Veillardf06307e2001-07-03 10:35:50 +000011598 if (op->ch1 != -1)
11599 total +=
11600 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11601 if (op->ch2 == -1)
11602 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011603
William M. Brack08171912003-12-29 02:52:11 +000011604 if (ctxt->value->type == XPATH_LOCATIONSET) {
11605 /*
11606 * Extract the old locset, and then evaluate the result of the
11607 * expression for all the element in the locset. use it to grow
11608 * up a new locset.
11609 */
11610 CHECK_TYPE0(XPATH_LOCATIONSET);
11611 obj = valuePop(ctxt);
11612 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011613
William M. Brack08171912003-12-29 02:52:11 +000011614 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000011615 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000011616 ctxt->context->contextSize = 0;
11617 ctxt->context->proximityPosition = 0;
11618 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
11619 res = valuePop(ctxt);
11620 if (res != NULL)
11621 xmlXPathFreeObject(res);
11622 valuePush(ctxt, obj);
11623 CHECK_ERROR0;
11624 return (total);
11625 }
11626 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011627
William M. Brack08171912003-12-29 02:52:11 +000011628 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011629 /*
William M. Brack08171912003-12-29 02:52:11 +000011630 * Run the evaluation with a node list made of a
11631 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000011632 */
William M. Brackf7eb7942003-12-31 07:59:17 +000011633 ctxt->context->node = oldlocset->locTab[i]->user;
11634 ctxt->context->contextSize = oldlocset->locNr;
11635 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011636 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11637 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011638
Daniel Veillardf06307e2001-07-03 10:35:50 +000011639 if (op->ch2 != -1)
11640 total +=
11641 xmlXPathCompOpEval(ctxt,
11642 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011643 if (ctxt->error != XPATH_EXPRESSION_OK) {
11644 xmlXPathFreeObject(obj);
11645 return(0);
11646 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011647
Daniel Veillardf06307e2001-07-03 10:35:50 +000011648 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000011649 if (res->type == XPATH_LOCATIONSET) {
11650 xmlLocationSetPtr rloc =
11651 (xmlLocationSetPtr)res->user;
11652 for (j=0; j<rloc->locNr; j++) {
11653 range = xmlXPtrNewRange(
11654 oldlocset->locTab[i]->user,
11655 oldlocset->locTab[i]->index,
11656 rloc->locTab[j]->user2,
11657 rloc->locTab[j]->index2);
11658 if (range != NULL) {
11659 xmlXPtrLocationSetAdd(newlocset, range);
11660 }
11661 }
11662 } else {
11663 range = xmlXPtrNewRangeNodeObject(
11664 (xmlNodePtr)oldlocset->locTab[i]->user, res);
11665 if (range != NULL) {
11666 xmlXPtrLocationSetAdd(newlocset,range);
11667 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011668 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011669
Daniel Veillardf06307e2001-07-03 10:35:50 +000011670 /*
11671 * Cleanup
11672 */
11673 if (res != NULL)
11674 xmlXPathFreeObject(res);
11675 if (ctxt->value == tmp) {
11676 res = valuePop(ctxt);
11677 xmlXPathFreeObject(res);
11678 }
11679
11680 ctxt->context->node = NULL;
11681 }
William M. Brack72ee48d2003-12-30 08:30:19 +000011682 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000011683 CHECK_TYPE0(XPATH_NODESET);
11684 obj = valuePop(ctxt);
11685 oldset = obj->nodesetval;
11686 ctxt->context->node = NULL;
11687
11688 newlocset = xmlXPtrLocationSetCreate(NULL);
11689
11690 if (oldset != NULL) {
11691 for (i = 0; i < oldset->nodeNr; i++) {
11692 /*
11693 * Run the evaluation with a node list made of a single item
11694 * in the nodeset.
11695 */
11696 ctxt->context->node = oldset->nodeTab[i];
11697 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11698 valuePush(ctxt, tmp);
11699
11700 if (op->ch2 != -1)
11701 total +=
11702 xmlXPathCompOpEval(ctxt,
11703 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011704 if (ctxt->error != XPATH_EXPRESSION_OK) {
11705 xmlXPathFreeObject(obj);
11706 return(0);
11707 }
William M. Brack08171912003-12-29 02:52:11 +000011708
William M. Brack08171912003-12-29 02:52:11 +000011709 res = valuePop(ctxt);
11710 range =
11711 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
11712 res);
11713 if (range != NULL) {
11714 xmlXPtrLocationSetAdd(newlocset, range);
11715 }
11716
11717 /*
11718 * Cleanup
11719 */
11720 if (res != NULL)
11721 xmlXPathFreeObject(res);
11722 if (ctxt->value == tmp) {
11723 res = valuePop(ctxt);
11724 xmlXPathFreeObject(res);
11725 }
11726
11727 ctxt->context->node = NULL;
11728 }
11729 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011730 }
11731
11732 /*
11733 * The result is used as the new evaluation set.
11734 */
11735 xmlXPathFreeObject(obj);
11736 ctxt->context->node = NULL;
11737 ctxt->context->contextSize = -1;
11738 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000011739 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011740 return (total);
11741 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011742#endif /* LIBXML_XPTR_ENABLED */
11743 }
11744 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011745 "XPath: unknown precompiled operation %d\n", op->op);
11746 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011747}
11748
Daniel Veillard56de87e2005-02-16 00:22:29 +000011749#ifdef XPATH_STREAMING
11750/**
11751 * xmlXPathRunStreamEval:
11752 * @ctxt: the XPath parser context with the compiled expression
11753 *
11754 * Evaluate the Precompiled Streamable XPath expression in the given context.
11755 */
11756static xmlXPathObjectPtr
11757xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011758 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011759 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011760 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011761#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11762 int eval_all_nodes;
11763#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000011764 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011765 xmlXPathObjectPtr retval;
11766 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011767
11768 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011769
11770 if ((ctxt == NULL) || (comp == NULL))
11771 return(NULL);
11772 max_depth = xmlPatternMaxDepth(comp);
11773 if (max_depth == -1)
11774 return(NULL);
11775 if (max_depth == -2)
11776 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011777 min_depth = xmlPatternMinDepth(comp);
11778 if (min_depth == -1)
11779 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011780 from_root = xmlPatternFromRoot(comp);
11781 if (from_root < 0)
11782 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011783#if 0
11784 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11785#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011786
11787 retval = xmlXPathNewNodeSet(NULL);
11788 if (retval == NULL)
11789 return(NULL);
11790
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011791 /*
11792 * handle the special cases of / amd . being matched
11793 */
11794 if (min_depth == 0) {
11795 if (from_root) {
11796 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11797 } else {
11798 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11799 }
11800 }
11801 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011802 return(retval);
11803 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011804
Daniel Veillard56de87e2005-02-16 00:22:29 +000011805 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011806 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011807 } else if (ctxt->node != NULL) {
11808 switch (ctxt->node->type) {
11809 case XML_ELEMENT_NODE:
11810 case XML_DOCUMENT_NODE:
11811 case XML_DOCUMENT_FRAG_NODE:
11812 case XML_HTML_DOCUMENT_NODE:
11813#ifdef LIBXML_DOCB_ENABLED
11814 case XML_DOCB_DOCUMENT_NODE:
11815#endif
11816 cur = ctxt->node;
11817 break;
11818 case XML_ATTRIBUTE_NODE:
11819 case XML_TEXT_NODE:
11820 case XML_CDATA_SECTION_NODE:
11821 case XML_ENTITY_REF_NODE:
11822 case XML_ENTITY_NODE:
11823 case XML_PI_NODE:
11824 case XML_COMMENT_NODE:
11825 case XML_NOTATION_NODE:
11826 case XML_DTD_NODE:
11827 case XML_DOCUMENT_TYPE_NODE:
11828 case XML_ELEMENT_DECL:
11829 case XML_ATTRIBUTE_DECL:
11830 case XML_ENTITY_DECL:
11831 case XML_NAMESPACE_DECL:
11832 case XML_XINCLUDE_START:
11833 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011834 break;
11835 }
11836 limit = cur;
11837 }
11838 if (cur == NULL)
11839 return(retval);
11840
11841 patstream = xmlPatternGetStreamCtxt(comp);
11842 if (patstream == NULL) {
11843 return(retval);
11844 }
11845
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011846#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11847 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11848#endif
11849
Daniel Veillard56de87e2005-02-16 00:22:29 +000011850 if (from_root) {
11851 ret = xmlStreamPush(patstream, NULL, NULL);
11852 if (ret < 0) {
11853 } else if (ret == 1) {
11854 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11855 }
11856 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011857 depth = 0;
11858 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011859next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000011860 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011861 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011862
11863 switch (cur->type) {
11864 case XML_ELEMENT_NODE:
11865#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11866 case XML_TEXT_NODE:
11867 case XML_CDATA_SECTION_NODE:
11868 case XML_COMMENT_NODE:
11869 case XML_PI_NODE:
11870#endif
11871 if (cur->type == XML_ELEMENT_NODE) {
11872 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000011873 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000011874 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011875#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11876 else if (eval_all_nodes)
11877 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11878 else
11879 break;
11880#endif
11881
11882 if (ret < 0) {
11883 /* NOP. */
11884 } else if (ret == 1) {
11885 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11886 }
11887 if ((cur->children == NULL) || (depth >= max_depth)) {
11888 ret = xmlStreamPop(patstream);
11889 while (cur->next != NULL) {
11890 cur = cur->next;
11891 if ((cur->type != XML_ENTITY_DECL) &&
11892 (cur->type != XML_DTD_NODE))
11893 goto next_node;
11894 }
11895 }
11896 default:
11897 break;
11898 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011899
11900scan_children:
11901 if ((cur->children != NULL) && (depth < max_depth)) {
11902 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011903 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000011904 */
11905 if (cur->children->type != XML_ENTITY_DECL) {
11906 cur = cur->children;
11907 depth++;
11908 /*
11909 * Skip DTDs
11910 */
11911 if (cur->type != XML_DTD_NODE)
11912 continue;
11913 }
11914 }
11915
11916 if (cur == limit)
11917 break;
11918
11919 while (cur->next != NULL) {
11920 cur = cur->next;
11921 if ((cur->type != XML_ENTITY_DECL) &&
11922 (cur->type != XML_DTD_NODE))
11923 goto next_node;
11924 }
11925
11926 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011927 cur = cur->parent;
11928 depth--;
11929 if ((cur == NULL) || (cur == limit))
11930 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011931 if (cur->type == XML_ELEMENT_NODE) {
11932 ret = xmlStreamPop(patstream);
11933 }
11934#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11935 else if ((eval_all_nodes) &&
11936 ((cur->type == XML_TEXT_NODE) ||
11937 (cur->type == XML_CDATA_SECTION_NODE) ||
11938 (cur->type == XML_COMMENT_NODE) ||
11939 (cur->type == XML_PI_NODE)))
11940 {
11941 ret = xmlStreamPop(patstream);
11942 }
11943#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011944 if (cur->next != NULL) {
11945 cur = cur->next;
11946 break;
11947 }
11948 } while (cur != NULL);
11949
11950 } while ((cur != NULL) && (depth >= 0));
11951done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011952#if 0
11953 printf("stream eval: checked %d nodes selected %d\n",
11954 nb_nodes, retval->nodesetval->nodeNr);
11955#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011956 xmlFreeStreamCtxt(patstream);
11957 return(retval);
11958}
11959#endif /* XPATH_STREAMING */
11960
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011961/**
11962 * xmlXPathRunEval:
11963 * @ctxt: the XPath parser context with the compiled expression
11964 *
11965 * Evaluate the Precompiled XPath expression in the given context.
11966 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011967static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011968xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11969 xmlXPathCompExprPtr comp;
11970
11971 if ((ctxt == NULL) || (ctxt->comp == NULL))
11972 return;
11973
11974 if (ctxt->valueTab == NULL) {
11975 /* Allocate the value stack */
11976 ctxt->valueTab = (xmlXPathObjectPtr *)
11977 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11978 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011979 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011980 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011981 }
11982 ctxt->valueNr = 0;
11983 ctxt->valueMax = 10;
11984 ctxt->value = NULL;
11985 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011986#ifdef XPATH_STREAMING
11987 if (ctxt->comp->stream) {
11988 xmlXPathObjectPtr ret;
11989 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11990 if (ret != NULL) {
11991 valuePush(ctxt, ret);
11992 return;
11993 }
11994 }
11995#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011996 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011997 if(comp->last < 0) {
11998 xmlGenericError(xmlGenericErrorContext,
11999 "xmlXPathRunEval: last is less than zero\n");
12000 return;
12001 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012002 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12003}
12004
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012005/************************************************************************
12006 * *
12007 * Public interfaces *
12008 * *
12009 ************************************************************************/
12010
12011/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012012 * xmlXPathEvalPredicate:
12013 * @ctxt: the XPath context
12014 * @res: the Predicate Expression evaluation result
12015 *
12016 * Evaluate a predicate result for the current node.
12017 * A PredicateExpr is evaluated by evaluating the Expr and converting
12018 * the result to a boolean. If the result is a number, the result will
12019 * be converted to true if the number is equal to the position of the
12020 * context node in the context node list (as returned by the position
12021 * function) and will be converted to false otherwise; if the result
12022 * is not a number, then the result will be converted as if by a call
12023 * to the boolean function.
12024 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012025 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012026 */
12027int
12028xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000012029 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012030 switch (res->type) {
12031 case XPATH_BOOLEAN:
12032 return(res->boolval);
12033 case XPATH_NUMBER:
12034 return(res->floatval == ctxt->proximityPosition);
12035 case XPATH_NODESET:
12036 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012037 if (res->nodesetval == NULL)
12038 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012039 return(res->nodesetval->nodeNr != 0);
12040 case XPATH_STRING:
12041 return((res->stringval != NULL) &&
12042 (xmlStrlen(res->stringval) != 0));
12043 default:
12044 STRANGE
12045 }
12046 return(0);
12047}
12048
12049/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012050 * xmlXPathEvaluatePredicateResult:
12051 * @ctxt: the XPath Parser context
12052 * @res: the Predicate Expression evaluation result
12053 *
12054 * Evaluate a predicate result for the current node.
12055 * A PredicateExpr is evaluated by evaluating the Expr and converting
12056 * the result to a boolean. If the result is a number, the result will
12057 * be converted to true if the number is equal to the position of the
12058 * context node in the context node list (as returned by the position
12059 * function) and will be converted to false otherwise; if the result
12060 * is not a number, then the result will be converted as if by a call
12061 * to the boolean function.
12062 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012063 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012064 */
12065int
12066xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12067 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000012068 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012069 switch (res->type) {
12070 case XPATH_BOOLEAN:
12071 return(res->boolval);
12072 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000012073#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000012074 return((res->floatval == ctxt->context->proximityPosition) &&
12075 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000012076#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012077 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000012078#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012079 case XPATH_NODESET:
12080 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000012081 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000012082 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012083 return(res->nodesetval->nodeNr != 0);
12084 case XPATH_STRING:
12085 return((res->stringval != NULL) &&
12086 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000012087#ifdef LIBXML_XPTR_ENABLED
12088 case XPATH_LOCATIONSET:{
12089 xmlLocationSetPtr ptr = res->user;
12090 if (ptr == NULL)
12091 return(0);
12092 return (ptr->locNr != 0);
12093 }
12094#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012095 default:
12096 STRANGE
12097 }
12098 return(0);
12099}
12100
Daniel Veillard56de87e2005-02-16 00:22:29 +000012101#ifdef XPATH_STREAMING
12102/**
12103 * xmlXPathTryStreamCompile:
12104 * @ctxt: an XPath context
12105 * @str: the XPath expression
12106 *
12107 * Try to compile the XPath expression as a streamable subset.
12108 *
12109 * Returns the compiled expression or NULL if failed to compile.
12110 */
12111static xmlXPathCompExprPtr
12112xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12113 /*
12114 * Optimization: use streaming patterns when the XPath expression can
12115 * be compiled to a stream lookup
12116 */
12117 xmlPatternPtr stream;
12118 xmlXPathCompExprPtr comp;
12119 xmlDictPtr dict = NULL;
12120 const xmlChar **namespaces = NULL;
12121 xmlNsPtr ns;
12122 int i, j;
12123
12124 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12125 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000012126 const xmlChar *tmp;
12127
12128 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000012129 * We don't try to handle expressions using the verbose axis
12130 * specifiers ("::"), just the simplied form at this point.
12131 * Additionally, if there is no list of namespaces available and
12132 * there's a ":" in the expression, indicating a prefixed QName,
12133 * then we won't try to compile either. xmlPatterncompile() needs
12134 * to have a list of namespaces at compilation time in order to
12135 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000012136 */
12137 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000012138 if ((tmp != NULL) &&
12139 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12140 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000012141
Daniel Veillard56de87e2005-02-16 00:22:29 +000012142 if (ctxt != NULL) {
12143 dict = ctxt->dict;
12144 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000012145 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000012146 if (namespaces == NULL) {
12147 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
12148 return(NULL);
12149 }
12150 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12151 ns = ctxt->namespaces[j];
12152 namespaces[i++] = ns->href;
12153 namespaces[i++] = ns->prefix;
12154 }
12155 namespaces[i++] = NULL;
12156 namespaces[i++] = NULL;
12157 }
12158 }
12159
William M. Brackea152c02005-06-09 18:12:28 +000012160 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
12161 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000012162 if (namespaces != NULL) {
12163 xmlFree((xmlChar **)namespaces);
12164 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000012165 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12166 comp = xmlXPathNewCompExpr();
12167 if (comp == NULL) {
12168 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
12169 return(NULL);
12170 }
12171 comp->stream = stream;
12172 comp->dict = dict;
12173 if (comp->dict)
12174 xmlDictReference(comp->dict);
12175 return(comp);
12176 }
12177 xmlFreePattern(stream);
12178 }
12179 return(NULL);
12180}
12181#endif /* XPATH_STREAMING */
12182
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012183/**
Daniel Veillard4773df22004-01-23 13:15:13 +000012184 * xmlXPathCtxtCompile:
12185 * @ctxt: an XPath context
12186 * @str: the XPath expression
12187 *
12188 * Compile an XPath expression
12189 *
12190 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12191 * the caller has to free the object.
12192 */
12193xmlXPathCompExprPtr
12194xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12195 xmlXPathParserContextPtr pctxt;
12196 xmlXPathCompExprPtr comp;
12197
Daniel Veillard56de87e2005-02-16 00:22:29 +000012198#ifdef XPATH_STREAMING
12199 comp = xmlXPathTryStreamCompile(ctxt, str);
12200 if (comp != NULL)
12201 return(comp);
12202#endif
12203
Daniel Veillard4773df22004-01-23 13:15:13 +000012204 xmlXPathInit();
12205
12206 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012207 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000012208
12209 if( pctxt->error != XPATH_EXPRESSION_OK )
12210 {
12211 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000012212 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000012213 }
12214
12215 if (*pctxt->cur != 0) {
12216 /*
12217 * aleksey: in some cases this line prints *second* error message
12218 * (see bug #78858) and probably this should be fixed.
12219 * However, we are not sure that all error messages are printed
12220 * out in other places. It's not critical so we leave it as-is for now
12221 */
12222 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12223 comp = NULL;
12224 } else {
12225 comp = pctxt->comp;
12226 pctxt->comp = NULL;
12227 }
12228 xmlXPathFreeParserContext(pctxt);
12229 if (comp != NULL) {
12230 comp->expr = xmlStrdup(str);
12231#ifdef DEBUG_EVAL_COUNTS
12232 comp->string = xmlStrdup(str);
12233 comp->nb = 0;
12234#endif
12235 }
12236 return(comp);
12237}
12238
12239/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012240 * xmlXPathCompile:
12241 * @str: the XPath expression
12242 *
12243 * Compile an XPath expression
12244 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000012245 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012246 * the caller has to free the object.
12247 */
12248xmlXPathCompExprPtr
12249xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000012250 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012251}
12252
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012253/**
12254 * xmlXPathCompiledEval:
12255 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000012256 * @ctx: the XPath context
12257 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012258 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000012259 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012260 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000012261 * the caller has to free the object.
12262 */
12263xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012264xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000012265 xmlXPathParserContextPtr ctxt;
12266 xmlXPathObjectPtr res, tmp, init = NULL;
12267 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000012268#ifndef LIBXML_THREAD_ENABLED
12269 static int reentance = 0;
12270#endif
Owen Taylor3473f882001-02-23 17:55:21 +000012271
William M. Brackf13f77f2004-11-12 16:03:48 +000012272 CHECK_CTXT(ctx)
12273
12274 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012275 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000012276 xmlXPathInit();
12277
Daniel Veillard81463942001-10-16 12:34:39 +000012278#ifndef LIBXML_THREAD_ENABLED
12279 reentance++;
12280 if (reentance > 1)
12281 xmlXPathDisableOptimizer = 1;
12282#endif
12283
Daniel Veillardf06307e2001-07-03 10:35:50 +000012284#ifdef DEBUG_EVAL_COUNTS
12285 comp->nb++;
12286 if ((comp->string != NULL) && (comp->nb > 100)) {
12287 fprintf(stderr, "100 x %s\n", comp->string);
12288 comp->nb = 0;
12289 }
12290#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012291 ctxt = xmlXPathCompParserContext(comp, ctx);
12292 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000012293
12294 if (ctxt->value == NULL) {
12295 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012296 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000012297 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000012298 } else {
12299 res = valuePop(ctxt);
12300 }
12301
Daniel Veillardf06307e2001-07-03 10:35:50 +000012302
Owen Taylor3473f882001-02-23 17:55:21 +000012303 do {
12304 tmp = valuePop(ctxt);
12305 if (tmp != NULL) {
12306 if (tmp != init)
12307 stack++;
12308 xmlXPathFreeObject(tmp);
12309 }
12310 } while (tmp != NULL);
12311 if ((stack != 0) && (res != NULL)) {
12312 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012313 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000012314 stack);
12315 }
12316 if (ctxt->error != XPATH_EXPRESSION_OK) {
12317 xmlXPathFreeObject(res);
12318 res = NULL;
12319 }
12320
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012321
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012322 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012323 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000012324#ifndef LIBXML_THREAD_ENABLED
12325 reentance--;
12326#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012327 return(res);
12328}
12329
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012330/**
12331 * xmlXPathEvalExpr:
12332 * @ctxt: the XPath Parser context
12333 *
12334 * Parse and evaluate an XPath expression in the given context,
12335 * then push the result on the context stack
12336 */
12337void
12338xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000012339#ifdef XPATH_STREAMING
12340 xmlXPathCompExprPtr comp;
12341#endif
12342
Daniel Veillarda82b1822004-11-08 16:24:57 +000012343 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000012344
12345#ifdef XPATH_STREAMING
12346 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12347 if (comp != NULL) {
12348 if (ctxt->comp != NULL)
12349 xmlXPathFreeCompExpr(ctxt->comp);
12350 ctxt->comp = comp;
12351 if (ctxt->cur != NULL)
12352 while (*ctxt->cur != 0) ctxt->cur++;
12353 } else
12354#endif
12355 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012356 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000012357 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000012358 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012359 xmlXPathRunEval(ctxt);
12360}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012361
12362/**
12363 * xmlXPathEval:
12364 * @str: the XPath expression
12365 * @ctx: the XPath context
12366 *
12367 * Evaluate the XPath Location Path in the given context.
12368 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012369 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012370 * the caller has to free the object.
12371 */
12372xmlXPathObjectPtr
12373xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
12374 xmlXPathParserContextPtr ctxt;
12375 xmlXPathObjectPtr res, tmp, init = NULL;
12376 int stack = 0;
12377
William M. Brackf13f77f2004-11-12 16:03:48 +000012378 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012379
William M. Brackf13f77f2004-11-12 16:03:48 +000012380 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012381
12382 ctxt = xmlXPathNewParserContext(str, ctx);
12383 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012384
12385 if (ctxt->value == NULL) {
12386 xmlGenericError(xmlGenericErrorContext,
12387 "xmlXPathEval: evaluation failed\n");
12388 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000012389 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
12390#ifdef XPATH_STREAMING
12391 && (ctxt->comp->stream == NULL)
12392#endif
12393 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012394 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12395 res = NULL;
12396 } else {
12397 res = valuePop(ctxt);
12398 }
12399
12400 do {
12401 tmp = valuePop(ctxt);
12402 if (tmp != NULL) {
12403 if (tmp != init)
12404 stack++;
12405 xmlXPathFreeObject(tmp);
12406 }
12407 } while (tmp != NULL);
12408 if ((stack != 0) && (res != NULL)) {
12409 xmlGenericError(xmlGenericErrorContext,
12410 "xmlXPathEval: %d object left on the stack\n",
12411 stack);
12412 }
12413 if (ctxt->error != XPATH_EXPRESSION_OK) {
12414 xmlXPathFreeObject(res);
12415 res = NULL;
12416 }
12417
Owen Taylor3473f882001-02-23 17:55:21 +000012418 xmlXPathFreeParserContext(ctxt);
12419 return(res);
12420}
12421
12422/**
12423 * xmlXPathEvalExpression:
12424 * @str: the XPath expression
12425 * @ctxt: the XPath context
12426 *
12427 * Evaluate the XPath expression in the given context.
12428 *
12429 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12430 * the caller has to free the object.
12431 */
12432xmlXPathObjectPtr
12433xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
12434 xmlXPathParserContextPtr pctxt;
12435 xmlXPathObjectPtr res, tmp;
12436 int stack = 0;
12437
William M. Brackf13f77f2004-11-12 16:03:48 +000012438 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000012439
William M. Brackf13f77f2004-11-12 16:03:48 +000012440 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000012441
12442 pctxt = xmlXPathNewParserContext(str, ctxt);
12443 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000012444
12445 if (*pctxt->cur != 0) {
12446 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12447 res = NULL;
12448 } else {
12449 res = valuePop(pctxt);
12450 }
12451 do {
12452 tmp = valuePop(pctxt);
12453 if (tmp != NULL) {
12454 xmlXPathFreeObject(tmp);
12455 stack++;
12456 }
12457 } while (tmp != NULL);
12458 if ((stack != 0) && (res != NULL)) {
12459 xmlGenericError(xmlGenericErrorContext,
12460 "xmlXPathEvalExpression: %d object left on the stack\n",
12461 stack);
12462 }
12463 xmlXPathFreeParserContext(pctxt);
12464 return(res);
12465}
12466
Daniel Veillard42766c02002-08-22 20:52:17 +000012467/************************************************************************
12468 * *
12469 * Extra functions not pertaining to the XPath spec *
12470 * *
12471 ************************************************************************/
12472/**
12473 * xmlXPathEscapeUriFunction:
12474 * @ctxt: the XPath Parser context
12475 * @nargs: the number of arguments
12476 *
12477 * Implement the escape-uri() XPath function
12478 * string escape-uri(string $str, bool $escape-reserved)
12479 *
12480 * This function applies the URI escaping rules defined in section 2 of [RFC
12481 * 2396] to the string supplied as $uri-part, which typically represents all
12482 * or part of a URI. The effect of the function is to replace any special
12483 * character in the string by an escape sequence of the form %xx%yy...,
12484 * where xxyy... is the hexadecimal representation of the octets used to
12485 * represent the character in UTF-8.
12486 *
12487 * The set of characters that are escaped depends on the setting of the
12488 * boolean argument $escape-reserved.
12489 *
12490 * If $escape-reserved is true, all characters are escaped other than lower
12491 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12492 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12493 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12494 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12495 * A-F).
12496 *
12497 * If $escape-reserved is false, the behavior differs in that characters
12498 * referred to in [RFC 2396] as reserved characters are not escaped. These
12499 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12500 *
12501 * [RFC 2396] does not define whether escaped URIs should use lower case or
12502 * upper case for hexadecimal digits. To ensure that escaped URIs can be
12503 * compared using string comparison functions, this function must always use
12504 * the upper-case letters A-F.
12505 *
12506 * Generally, $escape-reserved should be set to true when escaping a string
12507 * that is to form a single part of a URI, and to false when escaping an
12508 * entire URI or URI reference.
12509 *
12510 * In the case of non-ascii characters, the string is encoded according to
12511 * utf-8 and then converted according to RFC 2396.
12512 *
12513 * Examples
12514 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12515 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12516 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12517 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12518 *
12519 */
Daniel Veillard118aed72002-09-24 14:13:13 +000012520static void
Daniel Veillard42766c02002-08-22 20:52:17 +000012521xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12522 xmlXPathObjectPtr str;
12523 int escape_reserved;
12524 xmlBufferPtr target;
12525 xmlChar *cptr;
12526 xmlChar escape[4];
12527
12528 CHECK_ARITY(2);
12529
12530 escape_reserved = xmlXPathPopBoolean(ctxt);
12531
12532 CAST_TO_STRING;
12533 str = valuePop(ctxt);
12534
12535 target = xmlBufferCreate();
12536
12537 escape[0] = '%';
12538 escape[3] = 0;
12539
12540 if (target) {
12541 for (cptr = str->stringval; *cptr; cptr++) {
12542 if ((*cptr >= 'A' && *cptr <= 'Z') ||
12543 (*cptr >= 'a' && *cptr <= 'z') ||
12544 (*cptr >= '0' && *cptr <= '9') ||
12545 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
12546 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
12547 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12548 (*cptr == '%' &&
12549 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12550 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12551 (cptr[1] >= '0' && cptr[1] <= '9')) &&
12552 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12553 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12554 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12555 (!escape_reserved &&
12556 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12557 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12558 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12559 *cptr == ','))) {
12560 xmlBufferAdd(target, cptr, 1);
12561 } else {
12562 if ((*cptr >> 4) < 10)
12563 escape[1] = '0' + (*cptr >> 4);
12564 else
12565 escape[1] = 'A' - 10 + (*cptr >> 4);
12566 if ((*cptr & 0xF) < 10)
12567 escape[2] = '0' + (*cptr & 0xF);
12568 else
12569 escape[2] = 'A' - 10 + (*cptr & 0xF);
12570
12571 xmlBufferAdd(target, &escape[0], 3);
12572 }
12573 }
12574 }
12575 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
12576 xmlBufferFree(target);
12577 xmlXPathFreeObject(str);
12578}
12579
Owen Taylor3473f882001-02-23 17:55:21 +000012580/**
12581 * xmlXPathRegisterAllFunctions:
12582 * @ctxt: the XPath context
12583 *
12584 * Registers all default XPath functions in this context
12585 */
12586void
12587xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12588{
12589 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12590 xmlXPathBooleanFunction);
12591 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12592 xmlXPathCeilingFunction);
12593 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12594 xmlXPathCountFunction);
12595 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12596 xmlXPathConcatFunction);
12597 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12598 xmlXPathContainsFunction);
12599 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12600 xmlXPathIdFunction);
12601 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12602 xmlXPathFalseFunction);
12603 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12604 xmlXPathFloorFunction);
12605 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12606 xmlXPathLastFunction);
12607 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12608 xmlXPathLangFunction);
12609 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12610 xmlXPathLocalNameFunction);
12611 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12612 xmlXPathNotFunction);
12613 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12614 xmlXPathNameFunction);
12615 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12616 xmlXPathNamespaceURIFunction);
12617 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12618 xmlXPathNormalizeFunction);
12619 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12620 xmlXPathNumberFunction);
12621 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
12622 xmlXPathPositionFunction);
12623 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
12624 xmlXPathRoundFunction);
12625 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
12626 xmlXPathStringFunction);
12627 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
12628 xmlXPathStringLengthFunction);
12629 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
12630 xmlXPathStartsWithFunction);
12631 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
12632 xmlXPathSubstringFunction);
12633 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
12634 xmlXPathSubstringBeforeFunction);
12635 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
12636 xmlXPathSubstringAfterFunction);
12637 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
12638 xmlXPathSumFunction);
12639 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
12640 xmlXPathTrueFunction);
12641 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
12642 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000012643
12644 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
12645 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
12646 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000012647}
12648
12649#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000012650#define bottom_xpath
12651#include "elfgcchack.h"