blob: 2a33db29f32d72dfb9da566f1deeff2be38a94e6 [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
2144/**
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002145 * xmlXPathNodeSetCreateSize:
2146 * @val: an initial xmlNodePtr, or NULL
2147 * @size: the initial size of the node-sets
2148 *
2149 * Create a new xmlNodeSetPtr of type double and of value @val
2150 *
2151 * Returns the newly created object.
2152 */
2153static xmlNodeSetPtr
2154xmlXPathNodeSetCreateSize(int size)
2155{
2156 xmlNodeSetPtr ret;
2157
2158 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2159 if (ret == NULL) {
2160 xmlXPathErrMemory(NULL, "creating nodeset\n");
2161 return(NULL);
2162 }
2163 memset(ret, 0, (size_t) sizeof(xmlNodeSet));
2164 if (size > 0) {
2165 if (size < XML_NODESET_DEFAULT)
2166 size = XML_NODESET_DEFAULT;
2167 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
2168 if (ret->nodeTab == NULL) {
2169 xmlXPathErrMemory(NULL, "creating nodeset\n");
2170 xmlFree(ret);
2171 return(NULL);
2172 }
2173 memset(ret->nodeTab, 0, size * (size_t) sizeof(xmlNodePtr));
2174 ret->nodeMax = size;
2175 }
2176 return(ret);
2177}
2178
2179/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002180 * xmlXPathNodeSetContains:
2181 * @cur: the node-set
2182 * @val: the node
2183 *
2184 * checks whether @cur contains @val
2185 *
2186 * Returns true (1) if @cur contains @val, false (0) otherwise
2187 */
2188int
2189xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2190 int i;
2191
Daniel Veillarda82b1822004-11-08 16:24:57 +00002192 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002193 if (val->type == XML_NAMESPACE_DECL) {
2194 for (i = 0; i < cur->nodeNr; i++) {
2195 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2196 xmlNsPtr ns1, ns2;
2197
2198 ns1 = (xmlNsPtr) val;
2199 ns2 = (xmlNsPtr) cur->nodeTab[i];
2200 if (ns1 == ns2)
2201 return(1);
2202 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2203 (xmlStrEqual(ns1->prefix, ns2->prefix)))
2204 return(1);
2205 }
2206 }
2207 } else {
2208 for (i = 0; i < cur->nodeNr; i++) {
2209 if (cur->nodeTab[i] == val)
2210 return(1);
2211 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002212 }
2213 return(0);
2214}
2215
2216/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002217 * xmlXPathNodeSetAddNs:
2218 * @cur: the initial node set
2219 * @node: the hosting node
2220 * @ns: a the namespace node
2221 *
2222 * add a new namespace node to an existing NodeSet
2223 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00002224void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002225xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2226 int i;
2227
Daniel Veillarda82b1822004-11-08 16:24:57 +00002228
2229 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2230 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002231 (node->type != XML_ELEMENT_NODE))
2232 return;
2233
William M. Brack08171912003-12-29 02:52:11 +00002234 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002235 /*
William M. Brack08171912003-12-29 02:52:11 +00002236 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002237 */
2238 for (i = 0;i < cur->nodeNr;i++) {
2239 if ((cur->nodeTab[i] != NULL) &&
2240 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00002241 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002242 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2243 return;
2244 }
2245
2246 /*
2247 * grow the nodeTab if needed
2248 */
2249 if (cur->nodeMax == 0) {
2250 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2251 sizeof(xmlNodePtr));
2252 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002253 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002254 return;
2255 }
2256 memset(cur->nodeTab, 0 ,
2257 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2258 cur->nodeMax = XML_NODESET_DEFAULT;
2259 } else if (cur->nodeNr == cur->nodeMax) {
2260 xmlNodePtr *temp;
2261
2262 cur->nodeMax *= 2;
2263 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2264 sizeof(xmlNodePtr));
2265 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002266 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002267 return;
2268 }
2269 cur->nodeTab = temp;
2270 }
2271 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
2272}
2273
2274/**
Owen Taylor3473f882001-02-23 17:55:21 +00002275 * xmlXPathNodeSetAdd:
2276 * @cur: the initial node set
2277 * @val: a new xmlNodePtr
2278 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002279 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00002280 */
2281void
2282xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2283 int i;
2284
Daniel Veillarda82b1822004-11-08 16:24:57 +00002285 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002286
Daniel Veillardef0b4502003-03-24 13:57:34 +00002287#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00002288 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
2289 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00002290#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00002291
William M. Brack08171912003-12-29 02:52:11 +00002292 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002293 /*
William M. Brack08171912003-12-29 02:52:11 +00002294 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00002295 */
2296 for (i = 0;i < cur->nodeNr;i++)
2297 if (cur->nodeTab[i] == val) return;
2298
2299 /*
2300 * grow the nodeTab if needed
2301 */
2302 if (cur->nodeMax == 0) {
2303 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2304 sizeof(xmlNodePtr));
2305 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002306 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return;
2308 }
2309 memset(cur->nodeTab, 0 ,
2310 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2311 cur->nodeMax = XML_NODESET_DEFAULT;
2312 } else if (cur->nodeNr == cur->nodeMax) {
2313 xmlNodePtr *temp;
2314
2315 cur->nodeMax *= 2;
2316 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2317 sizeof(xmlNodePtr));
2318 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002319 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002320 return;
2321 }
2322 cur->nodeTab = temp;
2323 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002324 if (val->type == XML_NAMESPACE_DECL) {
2325 xmlNsPtr ns = (xmlNsPtr) val;
2326
2327 cur->nodeTab[cur->nodeNr++] =
2328 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2329 } else
2330 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002331}
2332
2333/**
2334 * xmlXPathNodeSetAddUnique:
2335 * @cur: the initial node set
2336 * @val: a new xmlNodePtr
2337 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002338 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00002339 * when we are sure the node is not already in the set.
2340 */
2341void
2342xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00002343 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002344
Daniel Veillardef0b4502003-03-24 13:57:34 +00002345#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00002346 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
2347 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00002348#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00002349
William M. Brack08171912003-12-29 02:52:11 +00002350 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002351 /*
2352 * grow the nodeTab if needed
2353 */
2354 if (cur->nodeMax == 0) {
2355 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2356 sizeof(xmlNodePtr));
2357 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002358 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002359 return;
2360 }
2361 memset(cur->nodeTab, 0 ,
2362 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2363 cur->nodeMax = XML_NODESET_DEFAULT;
2364 } else if (cur->nodeNr == cur->nodeMax) {
2365 xmlNodePtr *temp;
2366
2367 cur->nodeMax *= 2;
2368 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2369 sizeof(xmlNodePtr));
2370 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002371 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002372 return;
2373 }
2374 cur->nodeTab = temp;
2375 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002376 if (val->type == XML_NAMESPACE_DECL) {
2377 xmlNsPtr ns = (xmlNsPtr) val;
2378
2379 cur->nodeTab[cur->nodeNr++] =
2380 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2381 } else
2382 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002383}
2384
2385/**
2386 * xmlXPathNodeSetMerge:
2387 * @val1: the first NodeSet or NULL
2388 * @val2: the second NodeSet
2389 *
2390 * Merges two nodesets, all nodes from @val2 are added to @val1
2391 * if @val1 is NULL, a new set is created and copied from @val2
2392 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002393 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002394 */
2395xmlNodeSetPtr
2396xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002397 int i, j, initNr, skip;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002398 xmlNodePtr n1, n2;
Owen Taylor3473f882001-02-23 17:55:21 +00002399
2400 if (val2 == NULL) return(val1);
2401 if (val1 == NULL) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002402 /*
2403 * Optimization: Create an equally sized node-set
2404 * and memcpy the content.
2405 */
2406 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
2407 if (val1 == NULL)
2408 return(NULL);
2409 if (val2->nodeNr != 0) {
2410 if (val2->nodeNr == 1)
2411 *(val1->nodeTab) = *(val2->nodeTab);
2412 else {
2413 memcpy(val1->nodeTab, val2->nodeTab,
2414 val2->nodeNr * sizeof(xmlNodePtr));
2415 }
2416 val1->nodeNr = val2->nodeNr;
2417 }
2418 return(val1);
Owen Taylor3473f882001-02-23 17:55:21 +00002419 }
2420
William M. Brack08171912003-12-29 02:52:11 +00002421 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002422 initNr = val1->nodeNr;
2423
2424 for (i = 0;i < val2->nodeNr;i++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002425 n2 = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002426 /*
William M. Brack08171912003-12-29 02:52:11 +00002427 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002428 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002429 skip = 0;
2430 for (j = 0; j < initNr; j++) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002431 n1 = val1->nodeTab[j];
2432 if (n1 == n2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002433 skip = 1;
2434 break;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002435 } else if ((n1->type == XML_NAMESPACE_DECL) &&
2436 (n2->type == XML_NAMESPACE_DECL)) {
2437 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2438 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2439 ((xmlNsPtr) n2)->prefix)))
2440 {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002441 skip = 1;
2442 break;
2443 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002444 }
2445 }
2446 if (skip)
2447 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002448
2449 /*
2450 * grow the nodeTab if needed
2451 */
2452 if (val1->nodeMax == 0) {
2453 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2454 sizeof(xmlNodePtr));
2455 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002456 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002457 return(NULL);
2458 }
2459 memset(val1->nodeTab, 0 ,
2460 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2461 val1->nodeMax = XML_NODESET_DEFAULT;
2462 } else if (val1->nodeNr == val1->nodeMax) {
2463 xmlNodePtr *temp;
2464
2465 val1->nodeMax *= 2;
2466 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2467 sizeof(xmlNodePtr));
2468 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002469 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002470 return(NULL);
2471 }
2472 val1->nodeTab = temp;
2473 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002474 if (n2->type == XML_NAMESPACE_DECL) {
2475 xmlNsPtr ns = (xmlNsPtr) n2;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002476
2477 val1->nodeTab[val1->nodeNr++] =
2478 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2479 } else
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00002480 val1->nodeTab[val1->nodeNr++] = n2;
Owen Taylor3473f882001-02-23 17:55:21 +00002481 }
2482
2483 return(val1);
2484}
2485
2486/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002487 * xmlXPathNodeSetMergeUnique:
2488 * @val1: the first NodeSet or NULL
2489 * @val2: the second NodeSet
2490 *
2491 * Merges two nodesets, all nodes from @val2 are added to @val1
2492 * if @val1 is NULL, a new set is created and copied from @val2
2493 *
2494 * Returns @val1 once extended or NULL in case of error.
2495 */
2496static xmlNodeSetPtr
2497xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002498 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002499
2500 if (val2 == NULL) return(val1);
2501 if (val1 == NULL) {
2502 val1 = xmlXPathNodeSetCreate(NULL);
2503 }
2504
William M. Brack08171912003-12-29 02:52:11 +00002505 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002506
2507 for (i = 0;i < val2->nodeNr;i++) {
2508 /*
2509 * grow the nodeTab if needed
2510 */
2511 if (val1->nodeMax == 0) {
2512 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2513 sizeof(xmlNodePtr));
2514 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002515 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002516 return(NULL);
2517 }
2518 memset(val1->nodeTab, 0 ,
2519 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2520 val1->nodeMax = XML_NODESET_DEFAULT;
2521 } else if (val1->nodeNr == val1->nodeMax) {
2522 xmlNodePtr *temp;
2523
2524 val1->nodeMax *= 2;
2525 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2526 sizeof(xmlNodePtr));
2527 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002528 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002529 return(NULL);
2530 }
2531 val1->nodeTab = temp;
2532 }
2533 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2534 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2535
2536 val1->nodeTab[val1->nodeNr++] =
2537 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2538 } else
2539 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2540 }
2541
2542 return(val1);
2543}
2544
2545/**
Owen Taylor3473f882001-02-23 17:55:21 +00002546 * xmlXPathNodeSetDel:
2547 * @cur: the initial node set
2548 * @val: an xmlNodePtr
2549 *
2550 * Removes an xmlNodePtr from an existing NodeSet
2551 */
2552void
2553xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2554 int i;
2555
2556 if (cur == NULL) return;
2557 if (val == NULL) return;
2558
2559 /*
William M. Brack08171912003-12-29 02:52:11 +00002560 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002561 */
2562 for (i = 0;i < cur->nodeNr;i++)
2563 if (cur->nodeTab[i] == val) break;
2564
William M. Brack08171912003-12-29 02:52:11 +00002565 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002566#ifdef DEBUG
2567 xmlGenericError(xmlGenericErrorContext,
2568 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2569 val->name);
2570#endif
2571 return;
2572 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002573 if ((cur->nodeTab[i] != NULL) &&
2574 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2575 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002576 cur->nodeNr--;
2577 for (;i < cur->nodeNr;i++)
2578 cur->nodeTab[i] = cur->nodeTab[i + 1];
2579 cur->nodeTab[cur->nodeNr] = NULL;
2580}
2581
2582/**
2583 * xmlXPathNodeSetRemove:
2584 * @cur: the initial node set
2585 * @val: the index to remove
2586 *
2587 * Removes an entry from an existing NodeSet list.
2588 */
2589void
2590xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2591 if (cur == NULL) return;
2592 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002593 if ((cur->nodeTab[val] != NULL) &&
2594 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2595 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002596 cur->nodeNr--;
2597 for (;val < cur->nodeNr;val++)
2598 cur->nodeTab[val] = cur->nodeTab[val + 1];
2599 cur->nodeTab[cur->nodeNr] = NULL;
2600}
2601
2602/**
2603 * xmlXPathFreeNodeSet:
2604 * @obj: the xmlNodeSetPtr to free
2605 *
2606 * Free the NodeSet compound (not the actual nodes !).
2607 */
2608void
2609xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2610 if (obj == NULL) return;
2611 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002612 int i;
2613
William M. Brack08171912003-12-29 02:52:11 +00002614 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002615 for (i = 0;i < obj->nodeNr;i++)
2616 if ((obj->nodeTab[i] != NULL) &&
2617 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2618 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002619 xmlFree(obj->nodeTab);
2620 }
Owen Taylor3473f882001-02-23 17:55:21 +00002621 xmlFree(obj);
2622}
2623
2624/**
2625 * xmlXPathFreeValueTree:
2626 * @obj: the xmlNodeSetPtr to free
2627 *
2628 * Free the NodeSet compound and the actual tree, this is different
2629 * from xmlXPathFreeNodeSet()
2630 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002631static void
Owen Taylor3473f882001-02-23 17:55:21 +00002632xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2633 int i;
2634
2635 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002636
2637 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002638 for (i = 0;i < obj->nodeNr;i++) {
2639 if (obj->nodeTab[i] != NULL) {
2640 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2641 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2642 } else {
2643 xmlFreeNodeList(obj->nodeTab[i]);
2644 }
2645 }
2646 }
Owen Taylor3473f882001-02-23 17:55:21 +00002647 xmlFree(obj->nodeTab);
2648 }
Owen Taylor3473f882001-02-23 17:55:21 +00002649 xmlFree(obj);
2650}
2651
2652#if defined(DEBUG) || defined(DEBUG_STEP)
2653/**
2654 * xmlGenericErrorContextNodeSet:
2655 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002656 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002657 *
2658 * Quick display of a NodeSet
2659 */
2660void
2661xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2662 int i;
2663
2664 if (output == NULL) output = xmlGenericErrorContext;
2665 if (obj == NULL) {
2666 fprintf(output, "NodeSet == NULL !\n");
2667 return;
2668 }
2669 if (obj->nodeNr == 0) {
2670 fprintf(output, "NodeSet is empty\n");
2671 return;
2672 }
2673 if (obj->nodeTab == NULL) {
2674 fprintf(output, " nodeTab == NULL !\n");
2675 return;
2676 }
2677 for (i = 0; i < obj->nodeNr; i++) {
2678 if (obj->nodeTab[i] == NULL) {
2679 fprintf(output, " NULL !\n");
2680 return;
2681 }
2682 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2683 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2684 fprintf(output, " /");
2685 else if (obj->nodeTab[i]->name == NULL)
2686 fprintf(output, " noname!");
2687 else fprintf(output, " %s", obj->nodeTab[i]->name);
2688 }
2689 fprintf(output, "\n");
2690}
2691#endif
2692
2693/**
2694 * xmlXPathNewNodeSet:
2695 * @val: the NodePtr value
2696 *
2697 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2698 * it with the single Node @val
2699 *
2700 * Returns the newly created object.
2701 */
2702xmlXPathObjectPtr
2703xmlXPathNewNodeSet(xmlNodePtr val) {
2704 xmlXPathObjectPtr ret;
2705
2706 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2707 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002708 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002709 return(NULL);
2710 }
2711 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2712 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002713 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002714 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002715 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002716 return(ret);
2717}
2718
2719/**
2720 * xmlXPathNewValueTree:
2721 * @val: the NodePtr value
2722 *
2723 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2724 * it with the tree root @val
2725 *
2726 * Returns the newly created object.
2727 */
2728xmlXPathObjectPtr
2729xmlXPathNewValueTree(xmlNodePtr val) {
2730 xmlXPathObjectPtr ret;
2731
2732 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2733 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002734 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002735 return(NULL);
2736 }
2737 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2738 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002739 ret->boolval = 1;
2740 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002741 ret->nodesetval = xmlXPathNodeSetCreate(val);
2742 return(ret);
2743}
2744
2745/**
2746 * xmlXPathNewNodeSetList:
2747 * @val: an existing NodeSet
2748 *
2749 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2750 * it with the Nodeset @val
2751 *
2752 * Returns the newly created object.
2753 */
2754xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002755xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2756{
Owen Taylor3473f882001-02-23 17:55:21 +00002757 xmlXPathObjectPtr ret;
2758 int i;
2759
2760 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002761 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002762 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002763 ret = xmlXPathNewNodeSet(NULL);
2764 else {
2765 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2766 for (i = 1; i < val->nodeNr; ++i)
2767 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2768 }
Owen Taylor3473f882001-02-23 17:55:21 +00002769
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002770 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002771}
2772
2773/**
2774 * xmlXPathWrapNodeSet:
2775 * @val: the NodePtr value
2776 *
2777 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2778 *
2779 * Returns the newly created object.
2780 */
2781xmlXPathObjectPtr
2782xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2783 xmlXPathObjectPtr ret;
2784
2785 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2786 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002787 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002788 return(NULL);
2789 }
2790 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2791 ret->type = XPATH_NODESET;
2792 ret->nodesetval = val;
2793 return(ret);
2794}
2795
2796/**
2797 * xmlXPathFreeNodeSetList:
2798 * @obj: an existing NodeSetList object
2799 *
2800 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2801 * the list contrary to xmlXPathFreeObject().
2802 */
2803void
2804xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2805 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002806 xmlFree(obj);
2807}
2808
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002809/**
2810 * xmlXPathDifference:
2811 * @nodes1: a node-set
2812 * @nodes2: a node-set
2813 *
2814 * Implements the EXSLT - Sets difference() function:
2815 * node-set set:difference (node-set, node-set)
2816 *
2817 * Returns the difference between the two node sets, or nodes1 if
2818 * nodes2 is empty
2819 */
2820xmlNodeSetPtr
2821xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2822 xmlNodeSetPtr ret;
2823 int i, l1;
2824 xmlNodePtr cur;
2825
2826 if (xmlXPathNodeSetIsEmpty(nodes2))
2827 return(nodes1);
2828
2829 ret = xmlXPathNodeSetCreate(NULL);
2830 if (xmlXPathNodeSetIsEmpty(nodes1))
2831 return(ret);
2832
2833 l1 = xmlXPathNodeSetGetLength(nodes1);
2834
2835 for (i = 0; i < l1; i++) {
2836 cur = xmlXPathNodeSetItem(nodes1, i);
2837 if (!xmlXPathNodeSetContains(nodes2, cur))
2838 xmlXPathNodeSetAddUnique(ret, cur);
2839 }
2840 return(ret);
2841}
2842
2843/**
2844 * xmlXPathIntersection:
2845 * @nodes1: a node-set
2846 * @nodes2: a node-set
2847 *
2848 * Implements the EXSLT - Sets intersection() function:
2849 * node-set set:intersection (node-set, node-set)
2850 *
2851 * Returns a node set comprising the nodes that are within both the
2852 * node sets passed as arguments
2853 */
2854xmlNodeSetPtr
2855xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2856 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2857 int i, l1;
2858 xmlNodePtr cur;
2859
2860 if (xmlXPathNodeSetIsEmpty(nodes1))
2861 return(ret);
2862 if (xmlXPathNodeSetIsEmpty(nodes2))
2863 return(ret);
2864
2865 l1 = xmlXPathNodeSetGetLength(nodes1);
2866
2867 for (i = 0; i < l1; i++) {
2868 cur = xmlXPathNodeSetItem(nodes1, i);
2869 if (xmlXPathNodeSetContains(nodes2, cur))
2870 xmlXPathNodeSetAddUnique(ret, cur);
2871 }
2872 return(ret);
2873}
2874
2875/**
2876 * xmlXPathDistinctSorted:
2877 * @nodes: a node-set, sorted by document order
2878 *
2879 * Implements the EXSLT - Sets distinct() function:
2880 * node-set set:distinct (node-set)
2881 *
2882 * Returns a subset of the nodes contained in @nodes, or @nodes if
2883 * it is empty
2884 */
2885xmlNodeSetPtr
2886xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2887 xmlNodeSetPtr ret;
2888 xmlHashTablePtr hash;
2889 int i, l;
2890 xmlChar * strval;
2891 xmlNodePtr cur;
2892
2893 if (xmlXPathNodeSetIsEmpty(nodes))
2894 return(nodes);
2895
2896 ret = xmlXPathNodeSetCreate(NULL);
2897 l = xmlXPathNodeSetGetLength(nodes);
2898 hash = xmlHashCreate (l);
2899 for (i = 0; i < l; i++) {
2900 cur = xmlXPathNodeSetItem(nodes, i);
2901 strval = xmlXPathCastNodeToString(cur);
2902 if (xmlHashLookup(hash, strval) == NULL) {
2903 xmlHashAddEntry(hash, strval, strval);
2904 xmlXPathNodeSetAddUnique(ret, cur);
2905 } else {
2906 xmlFree(strval);
2907 }
2908 }
2909 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2910 return(ret);
2911}
2912
2913/**
2914 * xmlXPathDistinct:
2915 * @nodes: a node-set
2916 *
2917 * Implements the EXSLT - Sets distinct() function:
2918 * node-set set:distinct (node-set)
2919 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2920 * is called with the sorted node-set
2921 *
2922 * Returns a subset of the nodes contained in @nodes, or @nodes if
2923 * it is empty
2924 */
2925xmlNodeSetPtr
2926xmlXPathDistinct (xmlNodeSetPtr nodes) {
2927 if (xmlXPathNodeSetIsEmpty(nodes))
2928 return(nodes);
2929
2930 xmlXPathNodeSetSort(nodes);
2931 return(xmlXPathDistinctSorted(nodes));
2932}
2933
2934/**
2935 * xmlXPathHasSameNodes:
2936 * @nodes1: a node-set
2937 * @nodes2: a node-set
2938 *
2939 * Implements the EXSLT - Sets has-same-nodes function:
2940 * boolean set:has-same-node(node-set, node-set)
2941 *
2942 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2943 * otherwise
2944 */
2945int
2946xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2947 int i, l;
2948 xmlNodePtr cur;
2949
2950 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2951 xmlXPathNodeSetIsEmpty(nodes2))
2952 return(0);
2953
2954 l = xmlXPathNodeSetGetLength(nodes1);
2955 for (i = 0; i < l; i++) {
2956 cur = xmlXPathNodeSetItem(nodes1, i);
2957 if (xmlXPathNodeSetContains(nodes2, cur))
2958 return(1);
2959 }
2960 return(0);
2961}
2962
2963/**
2964 * xmlXPathNodeLeadingSorted:
2965 * @nodes: a node-set, sorted by document order
2966 * @node: a node
2967 *
2968 * Implements the EXSLT - Sets leading() function:
2969 * node-set set:leading (node-set, node-set)
2970 *
2971 * Returns the nodes in @nodes that precede @node in document order,
2972 * @nodes if @node is NULL or an empty node-set if @nodes
2973 * doesn't contain @node
2974 */
2975xmlNodeSetPtr
2976xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2977 int i, l;
2978 xmlNodePtr cur;
2979 xmlNodeSetPtr ret;
2980
2981 if (node == NULL)
2982 return(nodes);
2983
2984 ret = xmlXPathNodeSetCreate(NULL);
2985 if (xmlXPathNodeSetIsEmpty(nodes) ||
2986 (!xmlXPathNodeSetContains(nodes, node)))
2987 return(ret);
2988
2989 l = xmlXPathNodeSetGetLength(nodes);
2990 for (i = 0; i < l; i++) {
2991 cur = xmlXPathNodeSetItem(nodes, i);
2992 if (cur == node)
2993 break;
2994 xmlXPathNodeSetAddUnique(ret, cur);
2995 }
2996 return(ret);
2997}
2998
2999/**
3000 * xmlXPathNodeLeading:
3001 * @nodes: a node-set
3002 * @node: a node
3003 *
3004 * Implements the EXSLT - Sets leading() function:
3005 * node-set set:leading (node-set, node-set)
3006 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3007 * is called.
3008 *
3009 * Returns the nodes in @nodes that precede @node in document order,
3010 * @nodes if @node is NULL or an empty node-set if @nodes
3011 * doesn't contain @node
3012 */
3013xmlNodeSetPtr
3014xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3015 xmlXPathNodeSetSort(nodes);
3016 return(xmlXPathNodeLeadingSorted(nodes, node));
3017}
3018
3019/**
3020 * xmlXPathLeadingSorted:
3021 * @nodes1: a node-set, sorted by document order
3022 * @nodes2: a node-set, sorted by document order
3023 *
3024 * Implements the EXSLT - Sets leading() function:
3025 * node-set set:leading (node-set, node-set)
3026 *
3027 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3028 * in document order, @nodes1 if @nodes2 is NULL or empty or
3029 * an empty node-set if @nodes1 doesn't contain @nodes2
3030 */
3031xmlNodeSetPtr
3032xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3033 if (xmlXPathNodeSetIsEmpty(nodes2))
3034 return(nodes1);
3035 return(xmlXPathNodeLeadingSorted(nodes1,
3036 xmlXPathNodeSetItem(nodes2, 1)));
3037}
3038
3039/**
3040 * xmlXPathLeading:
3041 * @nodes1: a node-set
3042 * @nodes2: a node-set
3043 *
3044 * Implements the EXSLT - Sets leading() function:
3045 * node-set set:leading (node-set, node-set)
3046 * @nodes1 and @nodes2 are sorted by document order, then
3047 * #exslSetsLeadingSorted is called.
3048 *
3049 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3050 * in document order, @nodes1 if @nodes2 is NULL or empty or
3051 * an empty node-set if @nodes1 doesn't contain @nodes2
3052 */
3053xmlNodeSetPtr
3054xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3055 if (xmlXPathNodeSetIsEmpty(nodes2))
3056 return(nodes1);
3057 if (xmlXPathNodeSetIsEmpty(nodes1))
3058 return(xmlXPathNodeSetCreate(NULL));
3059 xmlXPathNodeSetSort(nodes1);
3060 xmlXPathNodeSetSort(nodes2);
3061 return(xmlXPathNodeLeadingSorted(nodes1,
3062 xmlXPathNodeSetItem(nodes2, 1)));
3063}
3064
3065/**
3066 * xmlXPathNodeTrailingSorted:
3067 * @nodes: a node-set, sorted by document order
3068 * @node: a node
3069 *
3070 * Implements the EXSLT - Sets trailing() function:
3071 * node-set set:trailing (node-set, node-set)
3072 *
3073 * Returns the nodes in @nodes that follow @node in document order,
3074 * @nodes if @node is NULL or an empty node-set if @nodes
3075 * doesn't contain @node
3076 */
3077xmlNodeSetPtr
3078xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3079 int i, l;
3080 xmlNodePtr cur;
3081 xmlNodeSetPtr ret;
3082
3083 if (node == NULL)
3084 return(nodes);
3085
3086 ret = xmlXPathNodeSetCreate(NULL);
3087 if (xmlXPathNodeSetIsEmpty(nodes) ||
3088 (!xmlXPathNodeSetContains(nodes, node)))
3089 return(ret);
3090
3091 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00003092 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003093 cur = xmlXPathNodeSetItem(nodes, i);
3094 if (cur == node)
3095 break;
3096 xmlXPathNodeSetAddUnique(ret, cur);
3097 }
3098 return(ret);
3099}
3100
3101/**
3102 * xmlXPathNodeTrailing:
3103 * @nodes: a node-set
3104 * @node: a node
3105 *
3106 * Implements the EXSLT - Sets trailing() function:
3107 * node-set set:trailing (node-set, node-set)
3108 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3109 * is called.
3110 *
3111 * Returns the nodes in @nodes that follow @node in document order,
3112 * @nodes if @node is NULL or an empty node-set if @nodes
3113 * doesn't contain @node
3114 */
3115xmlNodeSetPtr
3116xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3117 xmlXPathNodeSetSort(nodes);
3118 return(xmlXPathNodeTrailingSorted(nodes, node));
3119}
3120
3121/**
3122 * xmlXPathTrailingSorted:
3123 * @nodes1: a node-set, sorted by document order
3124 * @nodes2: a node-set, sorted by document order
3125 *
3126 * Implements the EXSLT - Sets trailing() function:
3127 * node-set set:trailing (node-set, node-set)
3128 *
3129 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3130 * in document order, @nodes1 if @nodes2 is NULL or empty or
3131 * an empty node-set if @nodes1 doesn't contain @nodes2
3132 */
3133xmlNodeSetPtr
3134xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3135 if (xmlXPathNodeSetIsEmpty(nodes2))
3136 return(nodes1);
3137 return(xmlXPathNodeTrailingSorted(nodes1,
3138 xmlXPathNodeSetItem(nodes2, 0)));
3139}
3140
3141/**
3142 * xmlXPathTrailing:
3143 * @nodes1: a node-set
3144 * @nodes2: a node-set
3145 *
3146 * Implements the EXSLT - Sets trailing() function:
3147 * node-set set:trailing (node-set, node-set)
3148 * @nodes1 and @nodes2 are sorted by document order, then
3149 * #xmlXPathTrailingSorted is called.
3150 *
3151 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3152 * in document order, @nodes1 if @nodes2 is NULL or empty or
3153 * an empty node-set if @nodes1 doesn't contain @nodes2
3154 */
3155xmlNodeSetPtr
3156xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3157 if (xmlXPathNodeSetIsEmpty(nodes2))
3158 return(nodes1);
3159 if (xmlXPathNodeSetIsEmpty(nodes1))
3160 return(xmlXPathNodeSetCreate(NULL));
3161 xmlXPathNodeSetSort(nodes1);
3162 xmlXPathNodeSetSort(nodes2);
3163 return(xmlXPathNodeTrailingSorted(nodes1,
3164 xmlXPathNodeSetItem(nodes2, 0)));
3165}
3166
Owen Taylor3473f882001-02-23 17:55:21 +00003167/************************************************************************
3168 * *
3169 * Routines to handle extra functions *
3170 * *
3171 ************************************************************************/
3172
3173/**
3174 * xmlXPathRegisterFunc:
3175 * @ctxt: the XPath context
3176 * @name: the function name
3177 * @f: the function implementation or NULL
3178 *
3179 * Register a new function. If @f is NULL it unregisters the function
3180 *
3181 * Returns 0 in case of success, -1 in case of error
3182 */
3183int
3184xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3185 xmlXPathFunction f) {
3186 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3187}
3188
3189/**
3190 * xmlXPathRegisterFuncNS:
3191 * @ctxt: the XPath context
3192 * @name: the function name
3193 * @ns_uri: the function namespace URI
3194 * @f: the function implementation or NULL
3195 *
3196 * Register a new function. If @f is NULL it unregisters the function
3197 *
3198 * Returns 0 in case of success, -1 in case of error
3199 */
3200int
3201xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3202 const xmlChar *ns_uri, xmlXPathFunction f) {
3203 if (ctxt == NULL)
3204 return(-1);
3205 if (name == NULL)
3206 return(-1);
3207
3208 if (ctxt->funcHash == NULL)
3209 ctxt->funcHash = xmlHashCreate(0);
3210 if (ctxt->funcHash == NULL)
3211 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00003212 if (f == NULL)
3213 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00003214 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00003215}
3216
3217/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00003218 * xmlXPathRegisterFuncLookup:
3219 * @ctxt: the XPath context
3220 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003221 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00003222 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003223 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00003224 */
3225void
3226xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3227 xmlXPathFuncLookupFunc f,
3228 void *funcCtxt) {
3229 if (ctxt == NULL)
3230 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003231 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003232 ctxt->funcLookupData = funcCtxt;
3233}
3234
3235/**
Owen Taylor3473f882001-02-23 17:55:21 +00003236 * xmlXPathFunctionLookup:
3237 * @ctxt: the XPath context
3238 * @name: the function name
3239 *
3240 * Search in the Function array of the context for the given
3241 * function.
3242 *
3243 * Returns the xmlXPathFunction or NULL if not found
3244 */
3245xmlXPathFunction
3246xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00003247 if (ctxt == NULL)
3248 return (NULL);
3249
3250 if (ctxt->funcLookupFunc != NULL) {
3251 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00003252 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003253
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003254 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00003255 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00003256 if (ret != NULL)
3257 return(ret);
3258 }
Owen Taylor3473f882001-02-23 17:55:21 +00003259 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3260}
3261
3262/**
3263 * xmlXPathFunctionLookupNS:
3264 * @ctxt: the XPath context
3265 * @name: the function name
3266 * @ns_uri: the function namespace URI
3267 *
3268 * Search in the Function array of the context for the given
3269 * function.
3270 *
3271 * Returns the xmlXPathFunction or NULL if not found
3272 */
3273xmlXPathFunction
3274xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3275 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00003276 xmlXPathFunction ret;
3277
Owen Taylor3473f882001-02-23 17:55:21 +00003278 if (ctxt == NULL)
3279 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003280 if (name == NULL)
3281 return(NULL);
3282
Thomas Broyerba4ad322001-07-26 16:55:21 +00003283 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00003284 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00003285
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003286 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00003287 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00003288 if (ret != NULL)
3289 return(ret);
3290 }
3291
3292 if (ctxt->funcHash == NULL)
3293 return(NULL);
3294
William M. Brackad0e67c2004-12-01 14:35:10 +00003295 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3296 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003297}
3298
3299/**
3300 * xmlXPathRegisteredFuncsCleanup:
3301 * @ctxt: the XPath context
3302 *
3303 * Cleanup the XPath context data associated to registered functions
3304 */
3305void
3306xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3307 if (ctxt == NULL)
3308 return;
3309
3310 xmlHashFree(ctxt->funcHash, NULL);
3311 ctxt->funcHash = NULL;
3312}
3313
3314/************************************************************************
3315 * *
William M. Brack08171912003-12-29 02:52:11 +00003316 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00003317 * *
3318 ************************************************************************/
3319
3320/**
3321 * xmlXPathRegisterVariable:
3322 * @ctxt: the XPath context
3323 * @name: the variable name
3324 * @value: the variable value or NULL
3325 *
3326 * Register a new variable value. If @value is NULL it unregisters
3327 * the variable
3328 *
3329 * Returns 0 in case of success, -1 in case of error
3330 */
3331int
3332xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3333 xmlXPathObjectPtr value) {
3334 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3335}
3336
3337/**
3338 * xmlXPathRegisterVariableNS:
3339 * @ctxt: the XPath context
3340 * @name: the variable name
3341 * @ns_uri: the variable namespace URI
3342 * @value: the variable value or NULL
3343 *
3344 * Register a new variable value. If @value is NULL it unregisters
3345 * the variable
3346 *
3347 * Returns 0 in case of success, -1 in case of error
3348 */
3349int
3350xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3351 const xmlChar *ns_uri,
3352 xmlXPathObjectPtr value) {
3353 if (ctxt == NULL)
3354 return(-1);
3355 if (name == NULL)
3356 return(-1);
3357
3358 if (ctxt->varHash == NULL)
3359 ctxt->varHash = xmlHashCreate(0);
3360 if (ctxt->varHash == NULL)
3361 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00003362 if (value == NULL)
3363 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3364 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00003365 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3366 (void *) value,
3367 (xmlHashDeallocator)xmlXPathFreeObject));
3368}
3369
3370/**
3371 * xmlXPathRegisterVariableLookup:
3372 * @ctxt: the XPath context
3373 * @f: the lookup function
3374 * @data: the lookup data
3375 *
3376 * register an external mechanism to do variable lookup
3377 */
3378void
3379xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3380 xmlXPathVariableLookupFunc f, void *data) {
3381 if (ctxt == NULL)
3382 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003383 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003384 ctxt->varLookupData = data;
3385}
3386
3387/**
3388 * xmlXPathVariableLookup:
3389 * @ctxt: the XPath context
3390 * @name: the variable name
3391 *
3392 * Search in the Variable array of the context for the given
3393 * variable value.
3394 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003395 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003396 */
3397xmlXPathObjectPtr
3398xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3399 if (ctxt == NULL)
3400 return(NULL);
3401
3402 if (ctxt->varLookupFunc != NULL) {
3403 xmlXPathObjectPtr ret;
3404
3405 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3406 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003407 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003408 }
3409 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3410}
3411
3412/**
3413 * xmlXPathVariableLookupNS:
3414 * @ctxt: the XPath context
3415 * @name: the variable name
3416 * @ns_uri: the variable namespace URI
3417 *
3418 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003419 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003420 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003421 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003422 */
3423xmlXPathObjectPtr
3424xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3425 const xmlChar *ns_uri) {
3426 if (ctxt == NULL)
3427 return(NULL);
3428
3429 if (ctxt->varLookupFunc != NULL) {
3430 xmlXPathObjectPtr ret;
3431
3432 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3433 (ctxt->varLookupData, name, ns_uri);
3434 if (ret != NULL) return(ret);
3435 }
3436
3437 if (ctxt->varHash == NULL)
3438 return(NULL);
3439 if (name == NULL)
3440 return(NULL);
3441
Daniel Veillard8c357d52001-07-03 23:43:33 +00003442 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3443 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003444}
3445
3446/**
3447 * xmlXPathRegisteredVariablesCleanup:
3448 * @ctxt: the XPath context
3449 *
3450 * Cleanup the XPath context data associated to registered variables
3451 */
3452void
3453xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3454 if (ctxt == NULL)
3455 return;
3456
Daniel Veillard76d66f42001-05-16 21:05:17 +00003457 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003458 ctxt->varHash = NULL;
3459}
3460
3461/**
3462 * xmlXPathRegisterNs:
3463 * @ctxt: the XPath context
3464 * @prefix: the namespace prefix
3465 * @ns_uri: the namespace name
3466 *
3467 * Register a new namespace. If @ns_uri is NULL it unregisters
3468 * the namespace
3469 *
3470 * Returns 0 in case of success, -1 in case of error
3471 */
3472int
3473xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3474 const xmlChar *ns_uri) {
3475 if (ctxt == NULL)
3476 return(-1);
3477 if (prefix == NULL)
3478 return(-1);
3479
3480 if (ctxt->nsHash == NULL)
3481 ctxt->nsHash = xmlHashCreate(10);
3482 if (ctxt->nsHash == NULL)
3483 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003484 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003485 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003486 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003487 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003488 (xmlHashDeallocator)xmlFree));
3489}
3490
3491/**
3492 * xmlXPathNsLookup:
3493 * @ctxt: the XPath context
3494 * @prefix: the namespace prefix value
3495 *
3496 * Search in the namespace declaration array of the context for the given
3497 * namespace name associated to the given prefix
3498 *
3499 * Returns the value or NULL if not found
3500 */
3501const xmlChar *
3502xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3503 if (ctxt == NULL)
3504 return(NULL);
3505 if (prefix == NULL)
3506 return(NULL);
3507
3508#ifdef XML_XML_NAMESPACE
3509 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3510 return(XML_XML_NAMESPACE);
3511#endif
3512
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003513 if (ctxt->namespaces != NULL) {
3514 int i;
3515
3516 for (i = 0;i < ctxt->nsNr;i++) {
3517 if ((ctxt->namespaces[i] != NULL) &&
3518 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3519 return(ctxt->namespaces[i]->href);
3520 }
3521 }
Owen Taylor3473f882001-02-23 17:55:21 +00003522
3523 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3524}
3525
3526/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003527 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003528 * @ctxt: the XPath context
3529 *
3530 * Cleanup the XPath context data associated to registered variables
3531 */
3532void
3533xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3534 if (ctxt == NULL)
3535 return;
3536
Daniel Veillard42766c02002-08-22 20:52:17 +00003537 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003538 ctxt->nsHash = NULL;
3539}
3540
3541/************************************************************************
3542 * *
3543 * Routines to handle Values *
3544 * *
3545 ************************************************************************/
3546
William M. Brack08171912003-12-29 02:52:11 +00003547/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003548
3549/**
3550 * xmlXPathNewFloat:
3551 * @val: the double value
3552 *
3553 * Create a new xmlXPathObjectPtr of type double and of value @val
3554 *
3555 * Returns the newly created object.
3556 */
3557xmlXPathObjectPtr
3558xmlXPathNewFloat(double val) {
3559 xmlXPathObjectPtr ret;
3560
3561 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3562 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003563 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003564 return(NULL);
3565 }
3566 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3567 ret->type = XPATH_NUMBER;
3568 ret->floatval = val;
3569 return(ret);
3570}
3571
3572/**
3573 * xmlXPathNewBoolean:
3574 * @val: the boolean value
3575 *
3576 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3577 *
3578 * Returns the newly created object.
3579 */
3580xmlXPathObjectPtr
3581xmlXPathNewBoolean(int val) {
3582 xmlXPathObjectPtr ret;
3583
3584 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3585 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003586 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003587 return(NULL);
3588 }
3589 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3590 ret->type = XPATH_BOOLEAN;
3591 ret->boolval = (val != 0);
3592 return(ret);
3593}
3594
3595/**
3596 * xmlXPathNewString:
3597 * @val: the xmlChar * value
3598 *
3599 * Create a new xmlXPathObjectPtr of type string and of value @val
3600 *
3601 * Returns the newly created object.
3602 */
3603xmlXPathObjectPtr
3604xmlXPathNewString(const xmlChar *val) {
3605 xmlXPathObjectPtr ret;
3606
3607 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3608 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003609 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003610 return(NULL);
3611 }
3612 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3613 ret->type = XPATH_STRING;
3614 if (val != NULL)
3615 ret->stringval = xmlStrdup(val);
3616 else
3617 ret->stringval = xmlStrdup((const xmlChar *)"");
3618 return(ret);
3619}
3620
3621/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003622 * xmlXPathWrapString:
3623 * @val: the xmlChar * value
3624 *
3625 * Wraps the @val string into an XPath object.
3626 *
3627 * Returns the newly created object.
3628 */
3629xmlXPathObjectPtr
3630xmlXPathWrapString (xmlChar *val) {
3631 xmlXPathObjectPtr ret;
3632
3633 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3634 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003635 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003636 return(NULL);
3637 }
3638 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3639 ret->type = XPATH_STRING;
3640 ret->stringval = val;
3641 return(ret);
3642}
3643
3644/**
Owen Taylor3473f882001-02-23 17:55:21 +00003645 * xmlXPathNewCString:
3646 * @val: the char * value
3647 *
3648 * Create a new xmlXPathObjectPtr of type string and of value @val
3649 *
3650 * Returns the newly created object.
3651 */
3652xmlXPathObjectPtr
3653xmlXPathNewCString(const char *val) {
3654 xmlXPathObjectPtr ret;
3655
3656 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3657 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003658 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003659 return(NULL);
3660 }
3661 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3662 ret->type = XPATH_STRING;
3663 ret->stringval = xmlStrdup(BAD_CAST val);
3664 return(ret);
3665}
3666
3667/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003668 * xmlXPathWrapCString:
3669 * @val: the char * value
3670 *
3671 * Wraps a string into an XPath object.
3672 *
3673 * Returns the newly created object.
3674 */
3675xmlXPathObjectPtr
3676xmlXPathWrapCString (char * val) {
3677 return(xmlXPathWrapString((xmlChar *)(val)));
3678}
3679
3680/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003681 * xmlXPathWrapExternal:
3682 * @val: the user data
3683 *
3684 * Wraps the @val data into an XPath object.
3685 *
3686 * Returns the newly created object.
3687 */
3688xmlXPathObjectPtr
3689xmlXPathWrapExternal (void *val) {
3690 xmlXPathObjectPtr ret;
3691
3692 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3693 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003694 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003695 return(NULL);
3696 }
3697 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3698 ret->type = XPATH_USERS;
3699 ret->user = val;
3700 return(ret);
3701}
3702
3703/**
Owen Taylor3473f882001-02-23 17:55:21 +00003704 * xmlXPathObjectCopy:
3705 * @val: the original object
3706 *
3707 * allocate a new copy of a given object
3708 *
3709 * Returns the newly created object.
3710 */
3711xmlXPathObjectPtr
3712xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3713 xmlXPathObjectPtr ret;
3714
3715 if (val == NULL)
3716 return(NULL);
3717
3718 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3719 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003720 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003721 return(NULL);
3722 }
3723 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3724 switch (val->type) {
3725 case XPATH_BOOLEAN:
3726 case XPATH_NUMBER:
3727 case XPATH_POINT:
3728 case XPATH_RANGE:
3729 break;
3730 case XPATH_STRING:
3731 ret->stringval = xmlStrdup(val->stringval);
3732 break;
3733 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003734#if 0
3735/*
3736 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3737 this previous handling is no longer correct, and can cause some serious
3738 problems (ref. bug 145547)
3739*/
Owen Taylor3473f882001-02-23 17:55:21 +00003740 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003741 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003742 xmlNodePtr cur, tmp;
3743 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003744
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003745 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003746 top = xmlNewDoc(NULL);
3747 top->name = (char *)
3748 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003749 ret->user = top;
3750 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003751 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003752 cur = val->nodesetval->nodeTab[0]->children;
3753 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003754 tmp = xmlDocCopyNode(cur, top, 1);
3755 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003756 cur = cur->next;
3757 }
3758 }
William M. Bracke9449c52004-07-11 14:41:20 +00003759
Daniel Veillard9adc0462003-03-24 18:39:54 +00003760 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003761 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003762 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003763 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003764 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003765#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003766 case XPATH_NODESET:
3767 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003768 /* Do not deallocate the copied tree value */
3769 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003770 break;
3771 case XPATH_LOCATIONSET:
3772#ifdef LIBXML_XPTR_ENABLED
3773 {
3774 xmlLocationSetPtr loc = val->user;
3775 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3776 break;
3777 }
3778#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003779 case XPATH_USERS:
3780 ret->user = val->user;
3781 break;
3782 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003783 xmlGenericError(xmlGenericErrorContext,
3784 "xmlXPathObjectCopy: unsupported type %d\n",
3785 val->type);
3786 break;
3787 }
3788 return(ret);
3789}
3790
3791/**
3792 * xmlXPathFreeObject:
3793 * @obj: the object to free
3794 *
3795 * Free up an xmlXPathObjectPtr object.
3796 */
3797void
3798xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3799 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003800 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003801 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003802#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003803 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003804 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003805 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003806 } else
3807#endif
3808 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003809 xmlXPathFreeValueTree(obj->nodesetval);
3810 } else {
3811 if (obj->nodesetval != NULL)
3812 xmlXPathFreeNodeSet(obj->nodesetval);
3813 }
Owen Taylor3473f882001-02-23 17:55:21 +00003814#ifdef LIBXML_XPTR_ENABLED
3815 } else if (obj->type == XPATH_LOCATIONSET) {
3816 if (obj->user != NULL)
3817 xmlXPtrFreeLocationSet(obj->user);
3818#endif
3819 } else if (obj->type == XPATH_STRING) {
3820 if (obj->stringval != NULL)
3821 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003822 }
3823
Owen Taylor3473f882001-02-23 17:55:21 +00003824 xmlFree(obj);
3825}
3826
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003827
3828/************************************************************************
3829 * *
3830 * Type Casting Routines *
3831 * *
3832 ************************************************************************/
3833
3834/**
3835 * xmlXPathCastBooleanToString:
3836 * @val: a boolean
3837 *
3838 * Converts a boolean to its string value.
3839 *
3840 * Returns a newly allocated string.
3841 */
3842xmlChar *
3843xmlXPathCastBooleanToString (int val) {
3844 xmlChar *ret;
3845 if (val)
3846 ret = xmlStrdup((const xmlChar *) "true");
3847 else
3848 ret = xmlStrdup((const xmlChar *) "false");
3849 return(ret);
3850}
3851
3852/**
3853 * xmlXPathCastNumberToString:
3854 * @val: a number
3855 *
3856 * Converts a number to its string value.
3857 *
3858 * Returns a newly allocated string.
3859 */
3860xmlChar *
3861xmlXPathCastNumberToString (double val) {
3862 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003863 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003864 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003865 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003866 break;
3867 case -1:
3868 ret = xmlStrdup((const xmlChar *) "-Infinity");
3869 break;
3870 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003871 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003872 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003873 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3874 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003875 } else {
3876 /* could be improved */
3877 char buf[100];
Daniel Veillard11ce4002006-03-10 00:36:23 +00003878 xmlXPathFormatNumber(val, buf, 99);
3879 buf[99] = 0;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003880 ret = xmlStrdup((const xmlChar *) buf);
3881 }
3882 }
3883 return(ret);
3884}
3885
3886/**
3887 * xmlXPathCastNodeToString:
3888 * @node: a node
3889 *
3890 * Converts a node to its string value.
3891 *
3892 * Returns a newly allocated string.
3893 */
3894xmlChar *
3895xmlXPathCastNodeToString (xmlNodePtr node) {
3896 return(xmlNodeGetContent(node));
3897}
3898
3899/**
3900 * xmlXPathCastNodeSetToString:
3901 * @ns: a node-set
3902 *
3903 * Converts a node-set to its string value.
3904 *
3905 * Returns a newly allocated string.
3906 */
3907xmlChar *
3908xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3909 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3910 return(xmlStrdup((const xmlChar *) ""));
3911
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00003912 if (ns->nodeNr > 1)
3913 xmlXPathNodeSetSort(ns);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003914 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3915}
3916
3917/**
3918 * xmlXPathCastToString:
3919 * @val: an XPath object
3920 *
3921 * Converts an existing object to its string() equivalent
3922 *
3923 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003924 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003925 * string object).
3926 */
3927xmlChar *
3928xmlXPathCastToString(xmlXPathObjectPtr val) {
3929 xmlChar *ret = NULL;
3930
3931 if (val == NULL)
3932 return(xmlStrdup((const xmlChar *) ""));
3933 switch (val->type) {
3934 case XPATH_UNDEFINED:
3935#ifdef DEBUG_EXPR
3936 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3937#endif
3938 ret = xmlStrdup((const xmlChar *) "");
3939 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003940 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003941 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003942 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3943 break;
3944 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003945 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003946 case XPATH_BOOLEAN:
3947 ret = xmlXPathCastBooleanToString(val->boolval);
3948 break;
3949 case XPATH_NUMBER: {
3950 ret = xmlXPathCastNumberToString(val->floatval);
3951 break;
3952 }
3953 case XPATH_USERS:
3954 case XPATH_POINT:
3955 case XPATH_RANGE:
3956 case XPATH_LOCATIONSET:
3957 TODO
3958 ret = xmlStrdup((const xmlChar *) "");
3959 break;
3960 }
3961 return(ret);
3962}
3963
3964/**
3965 * xmlXPathConvertString:
3966 * @val: an XPath object
3967 *
3968 * Converts an existing object to its string() equivalent
3969 *
3970 * Returns the new object, the old one is freed (or the operation
3971 * is done directly on @val)
3972 */
3973xmlXPathObjectPtr
3974xmlXPathConvertString(xmlXPathObjectPtr val) {
3975 xmlChar *res = NULL;
3976
3977 if (val == NULL)
3978 return(xmlXPathNewCString(""));
3979
3980 switch (val->type) {
3981 case XPATH_UNDEFINED:
3982#ifdef DEBUG_EXPR
3983 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3984#endif
3985 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003986 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003987 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003988 res = xmlXPathCastNodeSetToString(val->nodesetval);
3989 break;
3990 case XPATH_STRING:
3991 return(val);
3992 case XPATH_BOOLEAN:
3993 res = xmlXPathCastBooleanToString(val->boolval);
3994 break;
3995 case XPATH_NUMBER:
3996 res = xmlXPathCastNumberToString(val->floatval);
3997 break;
3998 case XPATH_USERS:
3999 case XPATH_POINT:
4000 case XPATH_RANGE:
4001 case XPATH_LOCATIONSET:
4002 TODO;
4003 break;
4004 }
4005 xmlXPathFreeObject(val);
4006 if (res == NULL)
4007 return(xmlXPathNewCString(""));
4008 return(xmlXPathWrapString(res));
4009}
4010
4011/**
4012 * xmlXPathCastBooleanToNumber:
4013 * @val: a boolean
4014 *
4015 * Converts a boolean to its number value
4016 *
4017 * Returns the number value
4018 */
4019double
4020xmlXPathCastBooleanToNumber(int val) {
4021 if (val)
4022 return(1.0);
4023 return(0.0);
4024}
4025
4026/**
4027 * xmlXPathCastStringToNumber:
4028 * @val: a string
4029 *
4030 * Converts a string to its number value
4031 *
4032 * Returns the number value
4033 */
4034double
4035xmlXPathCastStringToNumber(const xmlChar * val) {
4036 return(xmlXPathStringEvalNumber(val));
4037}
4038
4039/**
4040 * xmlXPathCastNodeToNumber:
4041 * @node: a node
4042 *
4043 * Converts a node to its number value
4044 *
4045 * Returns the number value
4046 */
4047double
4048xmlXPathCastNodeToNumber (xmlNodePtr node) {
4049 xmlChar *strval;
4050 double ret;
4051
4052 if (node == NULL)
4053 return(xmlXPathNAN);
4054 strval = xmlXPathCastNodeToString(node);
4055 if (strval == NULL)
4056 return(xmlXPathNAN);
4057 ret = xmlXPathCastStringToNumber(strval);
4058 xmlFree(strval);
4059
4060 return(ret);
4061}
4062
4063/**
4064 * xmlXPathCastNodeSetToNumber:
4065 * @ns: a node-set
4066 *
4067 * Converts a node-set to its number value
4068 *
4069 * Returns the number value
4070 */
4071double
4072xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4073 xmlChar *str;
4074 double ret;
4075
4076 if (ns == NULL)
4077 return(xmlXPathNAN);
4078 str = xmlXPathCastNodeSetToString(ns);
4079 ret = xmlXPathCastStringToNumber(str);
4080 xmlFree(str);
4081 return(ret);
4082}
4083
4084/**
4085 * xmlXPathCastToNumber:
4086 * @val: an XPath object
4087 *
4088 * Converts an XPath object to its number value
4089 *
4090 * Returns the number value
4091 */
4092double
4093xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4094 double ret = 0.0;
4095
4096 if (val == NULL)
4097 return(xmlXPathNAN);
4098 switch (val->type) {
4099 case XPATH_UNDEFINED:
4100#ifdef DEGUB_EXPR
4101 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
4102#endif
4103 ret = xmlXPathNAN;
4104 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004105 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00004106 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004107 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
4108 break;
4109 case XPATH_STRING:
4110 ret = xmlXPathCastStringToNumber(val->stringval);
4111 break;
4112 case XPATH_NUMBER:
4113 ret = val->floatval;
4114 break;
4115 case XPATH_BOOLEAN:
4116 ret = xmlXPathCastBooleanToNumber(val->boolval);
4117 break;
4118 case XPATH_USERS:
4119 case XPATH_POINT:
4120 case XPATH_RANGE:
4121 case XPATH_LOCATIONSET:
4122 TODO;
4123 ret = xmlXPathNAN;
4124 break;
4125 }
4126 return(ret);
4127}
4128
4129/**
4130 * xmlXPathConvertNumber:
4131 * @val: an XPath object
4132 *
4133 * Converts an existing object to its number() equivalent
4134 *
4135 * Returns the new object, the old one is freed (or the operation
4136 * is done directly on @val)
4137 */
4138xmlXPathObjectPtr
4139xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4140 xmlXPathObjectPtr ret;
4141
4142 if (val == NULL)
4143 return(xmlXPathNewFloat(0.0));
4144 if (val->type == XPATH_NUMBER)
4145 return(val);
4146 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4147 xmlXPathFreeObject(val);
4148 return(ret);
4149}
4150
4151/**
4152 * xmlXPathCastNumberToBoolean:
4153 * @val: a number
4154 *
4155 * Converts a number to its boolean value
4156 *
4157 * Returns the boolean value
4158 */
4159int
4160xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00004161 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004162 return(0);
4163 return(1);
4164}
4165
4166/**
4167 * xmlXPathCastStringToBoolean:
4168 * @val: a string
4169 *
4170 * Converts a string to its boolean value
4171 *
4172 * Returns the boolean value
4173 */
4174int
4175xmlXPathCastStringToBoolean (const xmlChar *val) {
4176 if ((val == NULL) || (xmlStrlen(val) == 0))
4177 return(0);
4178 return(1);
4179}
4180
4181/**
4182 * xmlXPathCastNodeSetToBoolean:
4183 * @ns: a node-set
4184 *
4185 * Converts a node-set to its boolean value
4186 *
4187 * Returns the boolean value
4188 */
4189int
4190xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4191 if ((ns == NULL) || (ns->nodeNr == 0))
4192 return(0);
4193 return(1);
4194}
4195
4196/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004197 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004198 * @val: an XPath object
4199 *
4200 * Converts an XPath object to its boolean value
4201 *
4202 * Returns the boolean value
4203 */
4204int
4205xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4206 int ret = 0;
4207
4208 if (val == NULL)
4209 return(0);
4210 switch (val->type) {
4211 case XPATH_UNDEFINED:
4212#ifdef DEBUG_EXPR
4213 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
4214#endif
4215 ret = 0;
4216 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004217 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00004218 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004219 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4220 break;
4221 case XPATH_STRING:
4222 ret = xmlXPathCastStringToBoolean(val->stringval);
4223 break;
4224 case XPATH_NUMBER:
4225 ret = xmlXPathCastNumberToBoolean(val->floatval);
4226 break;
4227 case XPATH_BOOLEAN:
4228 ret = val->boolval;
4229 break;
4230 case XPATH_USERS:
4231 case XPATH_POINT:
4232 case XPATH_RANGE:
4233 case XPATH_LOCATIONSET:
4234 TODO;
4235 ret = 0;
4236 break;
4237 }
4238 return(ret);
4239}
4240
4241
4242/**
4243 * xmlXPathConvertBoolean:
4244 * @val: an XPath object
4245 *
4246 * Converts an existing object to its boolean() equivalent
4247 *
4248 * Returns the new object, the old one is freed (or the operation
4249 * is done directly on @val)
4250 */
4251xmlXPathObjectPtr
4252xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4253 xmlXPathObjectPtr ret;
4254
4255 if (val == NULL)
4256 return(xmlXPathNewBoolean(0));
4257 if (val->type == XPATH_BOOLEAN)
4258 return(val);
4259 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4260 xmlXPathFreeObject(val);
4261 return(ret);
4262}
4263
Owen Taylor3473f882001-02-23 17:55:21 +00004264/************************************************************************
4265 * *
4266 * Routines to handle XPath contexts *
4267 * *
4268 ************************************************************************/
4269
4270/**
4271 * xmlXPathNewContext:
4272 * @doc: the XML document
4273 *
4274 * Create a new xmlXPathContext
4275 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00004276 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00004277 */
4278xmlXPathContextPtr
4279xmlXPathNewContext(xmlDocPtr doc) {
4280 xmlXPathContextPtr ret;
4281
4282 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4283 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004284 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004285 return(NULL);
4286 }
4287 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
4288 ret->doc = doc;
4289 ret->node = NULL;
4290
4291 ret->varHash = NULL;
4292
4293 ret->nb_types = 0;
4294 ret->max_types = 0;
4295 ret->types = NULL;
4296
4297 ret->funcHash = xmlHashCreate(0);
4298
4299 ret->nb_axis = 0;
4300 ret->max_axis = 0;
4301 ret->axis = NULL;
4302
4303 ret->nsHash = NULL;
4304 ret->user = NULL;
4305
4306 ret->contextSize = -1;
4307 ret->proximityPosition = -1;
4308
4309 xmlXPathRegisterAllFunctions(ret);
4310
4311 return(ret);
4312}
4313
4314/**
4315 * xmlXPathFreeContext:
4316 * @ctxt: the context to free
4317 *
4318 * Free up an xmlXPathContext
4319 */
4320void
4321xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00004322 if (ctxt == NULL) return;
4323
Owen Taylor3473f882001-02-23 17:55:21 +00004324 xmlXPathRegisteredNsCleanup(ctxt);
4325 xmlXPathRegisteredFuncsCleanup(ctxt);
4326 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00004327 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00004328 xmlFree(ctxt);
4329}
4330
4331/************************************************************************
4332 * *
4333 * Routines to handle XPath parser contexts *
4334 * *
4335 ************************************************************************/
4336
4337#define CHECK_CTXT(ctxt) \
4338 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00004339 __xmlRaiseError(NULL, NULL, NULL, \
4340 NULL, NULL, XML_FROM_XPATH, \
4341 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
4342 __FILE__, __LINE__, \
4343 NULL, NULL, NULL, 0, 0, \
4344 "NULL context pointer\n"); \
4345 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00004346 } \
4347
4348
4349#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00004350 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
4351 (ctxt->doc->children == NULL)) { \
4352 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00004353 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00004354 }
Owen Taylor3473f882001-02-23 17:55:21 +00004355
4356
4357/**
4358 * xmlXPathNewParserContext:
4359 * @str: the XPath expression
4360 * @ctxt: the XPath context
4361 *
4362 * Create a new xmlXPathParserContext
4363 *
4364 * Returns the xmlXPathParserContext just allocated.
4365 */
4366xmlXPathParserContextPtr
4367xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
4368 xmlXPathParserContextPtr ret;
4369
4370 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4371 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004372 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004373 return(NULL);
4374 }
4375 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4376 ret->cur = ret->base = str;
4377 ret->context = ctxt;
4378
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004379 ret->comp = xmlXPathNewCompExpr();
4380 if (ret->comp == NULL) {
4381 xmlFree(ret->valueTab);
4382 xmlFree(ret);
4383 return(NULL);
4384 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004385 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4386 ret->comp->dict = ctxt->dict;
4387 xmlDictReference(ret->comp->dict);
4388 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004389
4390 return(ret);
4391}
4392
4393/**
4394 * xmlXPathCompParserContext:
4395 * @comp: the XPath compiled expression
4396 * @ctxt: the XPath context
4397 *
4398 * Create a new xmlXPathParserContext when processing a compiled expression
4399 *
4400 * Returns the xmlXPathParserContext just allocated.
4401 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004402static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004403xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4404 xmlXPathParserContextPtr ret;
4405
4406 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4407 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004408 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004409 return(NULL);
4410 }
4411 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4412
Owen Taylor3473f882001-02-23 17:55:21 +00004413 /* Allocate the value stack */
4414 ret->valueTab = (xmlXPathObjectPtr *)
4415 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004416 if (ret->valueTab == NULL) {
4417 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004418 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004419 return(NULL);
4420 }
Owen Taylor3473f882001-02-23 17:55:21 +00004421 ret->valueNr = 0;
4422 ret->valueMax = 10;
4423 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004424
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004425 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004426 ret->comp = comp;
4427
Owen Taylor3473f882001-02-23 17:55:21 +00004428 return(ret);
4429}
4430
4431/**
4432 * xmlXPathFreeParserContext:
4433 * @ctxt: the context to free
4434 *
4435 * Free up an xmlXPathParserContext
4436 */
4437void
4438xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4439 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004440 xmlFree(ctxt->valueTab);
4441 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004442 if (ctxt->comp != NULL) {
4443#ifdef XPATH_STREAMING
4444 if (ctxt->comp->stream != NULL) {
4445 xmlFreePatternList(ctxt->comp->stream);
4446 ctxt->comp->stream = NULL;
4447 }
4448#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004449 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004450 }
Owen Taylor3473f882001-02-23 17:55:21 +00004451 xmlFree(ctxt);
4452}
4453
4454/************************************************************************
4455 * *
4456 * The implicit core function library *
4457 * *
4458 ************************************************************************/
4459
Owen Taylor3473f882001-02-23 17:55:21 +00004460/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004461 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004462 * @node: a node pointer
4463 *
4464 * Function computing the beginning of the string value of the node,
4465 * used to speed up comparisons
4466 *
4467 * Returns an int usable as a hash
4468 */
4469static unsigned int
4470xmlXPathNodeValHash(xmlNodePtr node) {
4471 int len = 2;
4472 const xmlChar * string = NULL;
4473 xmlNodePtr tmp = NULL;
4474 unsigned int ret = 0;
4475
4476 if (node == NULL)
4477 return(0);
4478
Daniel Veillard9adc0462003-03-24 18:39:54 +00004479 if (node->type == XML_DOCUMENT_NODE) {
4480 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4481 if (tmp == NULL)
4482 node = node->children;
4483 else
4484 node = tmp;
4485
4486 if (node == NULL)
4487 return(0);
4488 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004489
4490 switch (node->type) {
4491 case XML_COMMENT_NODE:
4492 case XML_PI_NODE:
4493 case XML_CDATA_SECTION_NODE:
4494 case XML_TEXT_NODE:
4495 string = node->content;
4496 if (string == NULL)
4497 return(0);
4498 if (string[0] == 0)
4499 return(0);
4500 return(((unsigned int) string[0]) +
4501 (((unsigned int) string[1]) << 8));
4502 case XML_NAMESPACE_DECL:
4503 string = ((xmlNsPtr)node)->href;
4504 if (string == NULL)
4505 return(0);
4506 if (string[0] == 0)
4507 return(0);
4508 return(((unsigned int) string[0]) +
4509 (((unsigned int) string[1]) << 8));
4510 case XML_ATTRIBUTE_NODE:
4511 tmp = ((xmlAttrPtr) node)->children;
4512 break;
4513 case XML_ELEMENT_NODE:
4514 tmp = node->children;
4515 break;
4516 default:
4517 return(0);
4518 }
4519 while (tmp != NULL) {
4520 switch (tmp->type) {
4521 case XML_COMMENT_NODE:
4522 case XML_PI_NODE:
4523 case XML_CDATA_SECTION_NODE:
4524 case XML_TEXT_NODE:
4525 string = tmp->content;
4526 break;
4527 case XML_NAMESPACE_DECL:
4528 string = ((xmlNsPtr)tmp)->href;
4529 break;
4530 default:
4531 break;
4532 }
4533 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004534 if (len == 1) {
4535 return(ret + (((unsigned int) string[0]) << 8));
4536 }
4537 if (string[1] == 0) {
4538 len = 1;
4539 ret = (unsigned int) string[0];
4540 } else {
4541 return(((unsigned int) string[0]) +
4542 (((unsigned int) string[1]) << 8));
4543 }
4544 }
4545 /*
4546 * Skip to next node
4547 */
4548 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4549 if (tmp->children->type != XML_ENTITY_DECL) {
4550 tmp = tmp->children;
4551 continue;
4552 }
4553 }
4554 if (tmp == node)
4555 break;
4556
4557 if (tmp->next != NULL) {
4558 tmp = tmp->next;
4559 continue;
4560 }
4561
4562 do {
4563 tmp = tmp->parent;
4564 if (tmp == NULL)
4565 break;
4566 if (tmp == node) {
4567 tmp = NULL;
4568 break;
4569 }
4570 if (tmp->next != NULL) {
4571 tmp = tmp->next;
4572 break;
4573 }
4574 } while (tmp != NULL);
4575 }
4576 return(ret);
4577}
4578
4579/**
4580 * xmlXPathStringHash:
4581 * @string: a string
4582 *
4583 * Function computing the beginning of the string value of the node,
4584 * used to speed up comparisons
4585 *
4586 * Returns an int usable as a hash
4587 */
4588static unsigned int
4589xmlXPathStringHash(const xmlChar * string) {
4590 if (string == NULL)
4591 return((unsigned int) 0);
4592 if (string[0] == 0)
4593 return(0);
4594 return(((unsigned int) string[0]) +
4595 (((unsigned int) string[1]) << 8));
4596}
4597
4598/**
Owen Taylor3473f882001-02-23 17:55:21 +00004599 * xmlXPathCompareNodeSetFloat:
4600 * @ctxt: the XPath Parser context
4601 * @inf: less than (1) or greater than (0)
4602 * @strict: is the comparison strict
4603 * @arg: the node set
4604 * @f: the value
4605 *
4606 * Implement the compare operation between a nodeset and a number
4607 * @ns < @val (1, 1, ...
4608 * @ns <= @val (1, 0, ...
4609 * @ns > @val (0, 1, ...
4610 * @ns >= @val (0, 0, ...
4611 *
4612 * If one object to be compared is a node-set and the other is a number,
4613 * then the comparison will be true if and only if there is a node in the
4614 * node-set such that the result of performing the comparison on the number
4615 * to be compared and on the result of converting the string-value of that
4616 * node to a number using the number function is true.
4617 *
4618 * Returns 0 or 1 depending on the results of the test.
4619 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004620static int
Owen Taylor3473f882001-02-23 17:55:21 +00004621xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4622 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4623 int i, ret = 0;
4624 xmlNodeSetPtr ns;
4625 xmlChar *str2;
4626
4627 if ((f == NULL) || (arg == NULL) ||
4628 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4629 xmlXPathFreeObject(arg);
4630 xmlXPathFreeObject(f);
4631 return(0);
4632 }
4633 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004634 if (ns != NULL) {
4635 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004636 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004637 if (str2 != NULL) {
4638 valuePush(ctxt,
4639 xmlXPathNewString(str2));
4640 xmlFree(str2);
4641 xmlXPathNumberFunction(ctxt, 1);
4642 valuePush(ctxt, xmlXPathObjectCopy(f));
4643 ret = xmlXPathCompareValues(ctxt, inf, strict);
4644 if (ret)
4645 break;
4646 }
4647 }
Owen Taylor3473f882001-02-23 17:55:21 +00004648 }
4649 xmlXPathFreeObject(arg);
4650 xmlXPathFreeObject(f);
4651 return(ret);
4652}
4653
4654/**
4655 * xmlXPathCompareNodeSetString:
4656 * @ctxt: the XPath Parser context
4657 * @inf: less than (1) or greater than (0)
4658 * @strict: is the comparison strict
4659 * @arg: the node set
4660 * @s: the value
4661 *
4662 * Implement the compare operation between a nodeset and a string
4663 * @ns < @val (1, 1, ...
4664 * @ns <= @val (1, 0, ...
4665 * @ns > @val (0, 1, ...
4666 * @ns >= @val (0, 0, ...
4667 *
4668 * If one object to be compared is a node-set and the other is a string,
4669 * then the comparison will be true if and only if there is a node in
4670 * the node-set such that the result of performing the comparison on the
4671 * string-value of the node and the other string is true.
4672 *
4673 * Returns 0 or 1 depending on the results of the test.
4674 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004675static int
Owen Taylor3473f882001-02-23 17:55:21 +00004676xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4677 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4678 int i, ret = 0;
4679 xmlNodeSetPtr ns;
4680 xmlChar *str2;
4681
4682 if ((s == NULL) || (arg == NULL) ||
4683 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4684 xmlXPathFreeObject(arg);
4685 xmlXPathFreeObject(s);
4686 return(0);
4687 }
4688 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004689 if (ns != NULL) {
4690 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004691 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004692 if (str2 != NULL) {
4693 valuePush(ctxt,
4694 xmlXPathNewString(str2));
4695 xmlFree(str2);
4696 valuePush(ctxt, xmlXPathObjectCopy(s));
4697 ret = xmlXPathCompareValues(ctxt, inf, strict);
4698 if (ret)
4699 break;
4700 }
4701 }
Owen Taylor3473f882001-02-23 17:55:21 +00004702 }
4703 xmlXPathFreeObject(arg);
4704 xmlXPathFreeObject(s);
4705 return(ret);
4706}
4707
4708/**
4709 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004710 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004711 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004712 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004713 * @arg2: the second node set object
4714 *
4715 * Implement the compare operation on nodesets:
4716 *
4717 * If both objects to be compared are node-sets, then the comparison
4718 * will be true if and only if there is a node in the first node-set
4719 * and a node in the second node-set such that the result of performing
4720 * the comparison on the string-values of the two nodes is true.
4721 * ....
4722 * When neither object to be compared is a node-set and the operator
4723 * is <=, <, >= or >, then the objects are compared by converting both
4724 * objects to numbers and comparing the numbers according to IEEE 754.
4725 * ....
4726 * The number function converts its argument to a number as follows:
4727 * - a string that consists of optional whitespace followed by an
4728 * optional minus sign followed by a Number followed by whitespace
4729 * is converted to the IEEE 754 number that is nearest (according
4730 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4731 * represented by the string; any other string is converted to NaN
4732 *
4733 * Conclusion all nodes need to be converted first to their string value
4734 * and then the comparison must be done when possible
4735 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004736static int
4737xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004738 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4739 int i, j, init = 0;
4740 double val1;
4741 double *values2;
4742 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004743 xmlNodeSetPtr ns1;
4744 xmlNodeSetPtr ns2;
4745
4746 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004747 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4748 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004749 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004750 }
Owen Taylor3473f882001-02-23 17:55:21 +00004751 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004752 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4753 xmlXPathFreeObject(arg1);
4754 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004755 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004756 }
Owen Taylor3473f882001-02-23 17:55:21 +00004757
4758 ns1 = arg1->nodesetval;
4759 ns2 = arg2->nodesetval;
4760
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004761 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004762 xmlXPathFreeObject(arg1);
4763 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004764 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004765 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004766 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004767 xmlXPathFreeObject(arg1);
4768 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004769 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004770 }
Owen Taylor3473f882001-02-23 17:55:21 +00004771
4772 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4773 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004774 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004775 xmlXPathFreeObject(arg1);
4776 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004777 return(0);
4778 }
4779 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004780 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004781 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004782 continue;
4783 for (j = 0;j < ns2->nodeNr;j++) {
4784 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004785 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004786 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004787 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004788 continue;
4789 if (inf && strict)
4790 ret = (val1 < values2[j]);
4791 else if (inf && !strict)
4792 ret = (val1 <= values2[j]);
4793 else if (!inf && strict)
4794 ret = (val1 > values2[j]);
4795 else if (!inf && !strict)
4796 ret = (val1 >= values2[j]);
4797 if (ret)
4798 break;
4799 }
4800 if (ret)
4801 break;
4802 init = 1;
4803 }
4804 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004805 xmlXPathFreeObject(arg1);
4806 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004807 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004808}
4809
4810/**
4811 * xmlXPathCompareNodeSetValue:
4812 * @ctxt: the XPath Parser context
4813 * @inf: less than (1) or greater than (0)
4814 * @strict: is the comparison strict
4815 * @arg: the node set
4816 * @val: the value
4817 *
4818 * Implement the compare operation between a nodeset and a value
4819 * @ns < @val (1, 1, ...
4820 * @ns <= @val (1, 0, ...
4821 * @ns > @val (0, 1, ...
4822 * @ns >= @val (0, 0, ...
4823 *
4824 * If one object to be compared is a node-set and the other is a boolean,
4825 * then the comparison will be true if and only if the result of performing
4826 * the comparison on the boolean and on the result of converting
4827 * the node-set to a boolean using the boolean function is true.
4828 *
4829 * Returns 0 or 1 depending on the results of the test.
4830 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004831static int
Owen Taylor3473f882001-02-23 17:55:21 +00004832xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4833 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4834 if ((val == NULL) || (arg == NULL) ||
4835 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4836 return(0);
4837
4838 switch(val->type) {
4839 case XPATH_NUMBER:
4840 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4841 case XPATH_NODESET:
4842 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004843 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004844 case XPATH_STRING:
4845 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4846 case XPATH_BOOLEAN:
4847 valuePush(ctxt, arg);
4848 xmlXPathBooleanFunction(ctxt, 1);
4849 valuePush(ctxt, val);
4850 return(xmlXPathCompareValues(ctxt, inf, strict));
4851 default:
4852 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004853 }
4854 return(0);
4855}
4856
4857/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004858 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004859 * @arg: the nodeset object argument
4860 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004861 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004862 *
4863 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4864 * If one object to be compared is a node-set and the other is a string,
4865 * then the comparison will be true if and only if there is a node in
4866 * the node-set such that the result of performing the comparison on the
4867 * string-value of the node and the other string is true.
4868 *
4869 * Returns 0 or 1 depending on the results of the test.
4870 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004871static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004872xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004873{
Owen Taylor3473f882001-02-23 17:55:21 +00004874 int i;
4875 xmlNodeSetPtr ns;
4876 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004877 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004878
4879 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004880 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4881 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004882 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004883 /*
4884 * A NULL nodeset compared with a string is always false
4885 * (since there is no node equal, and no node not equal)
4886 */
4887 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004888 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004889 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004890 for (i = 0; i < ns->nodeNr; i++) {
4891 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4892 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4893 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4894 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004895 if (neq)
4896 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004897 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004898 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4899 if (neq)
4900 continue;
4901 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004902 } else if (neq) {
4903 if (str2 != NULL)
4904 xmlFree(str2);
4905 return (1);
4906 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004907 if (str2 != NULL)
4908 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004909 } else if (neq)
4910 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004911 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004912 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004913}
4914
4915/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004916 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004917 * @arg: the nodeset object argument
4918 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004919 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004920 *
4921 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4922 * If one object to be compared is a node-set and the other is a number,
4923 * then the comparison will be true if and only if there is a node in
4924 * the node-set such that the result of performing the comparison on the
4925 * number to be compared and on the result of converting the string-value
4926 * of that node to a number using the number function is true.
4927 *
4928 * Returns 0 or 1 depending on the results of the test.
4929 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004930static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004931xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4932 xmlXPathObjectPtr arg, double f, int neq) {
4933 int i, ret=0;
4934 xmlNodeSetPtr ns;
4935 xmlChar *str2;
4936 xmlXPathObjectPtr val;
4937 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004938
4939 if ((arg == NULL) ||
4940 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4941 return(0);
4942
William M. Brack0c022ad2002-07-12 00:56:01 +00004943 ns = arg->nodesetval;
4944 if (ns != NULL) {
4945 for (i=0;i<ns->nodeNr;i++) {
4946 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4947 if (str2 != NULL) {
4948 valuePush(ctxt, xmlXPathNewString(str2));
4949 xmlFree(str2);
4950 xmlXPathNumberFunction(ctxt, 1);
4951 val = valuePop(ctxt);
4952 v = val->floatval;
4953 xmlXPathFreeObject(val);
4954 if (!xmlXPathIsNaN(v)) {
4955 if ((!neq) && (v==f)) {
4956 ret = 1;
4957 break;
4958 } else if ((neq) && (v!=f)) {
4959 ret = 1;
4960 break;
4961 }
William M. Brack32f0f712005-07-14 07:00:33 +00004962 } else { /* NaN is unequal to any value */
4963 if (neq)
4964 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00004965 }
4966 }
4967 }
4968 }
4969
4970 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004971}
4972
4973
4974/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004975 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004976 * @arg1: first nodeset object argument
4977 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004978 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004979 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004980 * Implement the equal / not equal operation on XPath nodesets:
4981 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004982 * If both objects to be compared are node-sets, then the comparison
4983 * will be true if and only if there is a node in the first node-set and
4984 * a node in the second node-set such that the result of performing the
4985 * comparison on the string-values of the two nodes is true.
4986 *
4987 * (needless to say, this is a costly operation)
4988 *
4989 * Returns 0 or 1 depending on the results of the test.
4990 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004991static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004992xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004993 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004994 unsigned int *hashs1;
4995 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004996 xmlChar **values1;
4997 xmlChar **values2;
4998 int ret = 0;
4999 xmlNodeSetPtr ns1;
5000 xmlNodeSetPtr ns2;
5001
5002 if ((arg1 == NULL) ||
5003 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5004 return(0);
5005 if ((arg2 == NULL) ||
5006 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5007 return(0);
5008
5009 ns1 = arg1->nodesetval;
5010 ns2 = arg2->nodesetval;
5011
Daniel Veillard911f49a2001-04-07 15:39:35 +00005012 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00005013 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00005014 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00005015 return(0);
5016
5017 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00005018 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00005019 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005020 if (neq == 0)
5021 for (i = 0;i < ns1->nodeNr;i++)
5022 for (j = 0;j < ns2->nodeNr;j++)
5023 if (ns1->nodeTab[i] == ns2->nodeTab[j])
5024 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00005025
5026 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005027 if (values1 == NULL) {
5028 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00005029 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005030 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005031 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5032 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005033 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00005034 xmlFree(values1);
5035 return(0);
5036 }
Owen Taylor3473f882001-02-23 17:55:21 +00005037 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5038 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5039 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005040 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00005041 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00005042 xmlFree(values1);
5043 return(0);
5044 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00005045 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5046 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00005047 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00005048 xmlFree(hashs1);
5049 xmlFree(values1);
5050 xmlFree(values2);
5051 return(0);
5052 }
Owen Taylor3473f882001-02-23 17:55:21 +00005053 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5054 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005055 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005056 for (j = 0;j < ns2->nodeNr;j++) {
5057 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005058 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00005059 if (hashs1[i] != hashs2[j]) {
5060 if (neq) {
5061 ret = 1;
5062 break;
5063 }
5064 }
5065 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005066 if (values1[i] == NULL)
5067 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5068 if (values2[j] == NULL)
5069 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00005070 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005071 if (ret)
5072 break;
5073 }
Owen Taylor3473f882001-02-23 17:55:21 +00005074 }
5075 if (ret)
5076 break;
5077 }
5078 for (i = 0;i < ns1->nodeNr;i++)
5079 if (values1[i] != NULL)
5080 xmlFree(values1[i]);
5081 for (j = 0;j < ns2->nodeNr;j++)
5082 if (values2[j] != NULL)
5083 xmlFree(values2[j]);
5084 xmlFree(values1);
5085 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005086 xmlFree(hashs1);
5087 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00005088 return(ret);
5089}
5090
William M. Brack0c022ad2002-07-12 00:56:01 +00005091static int
5092xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5093 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00005094 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00005095 /*
5096 *At this point we are assured neither arg1 nor arg2
5097 *is a nodeset, so we can just pick the appropriate routine.
5098 */
Owen Taylor3473f882001-02-23 17:55:21 +00005099 switch (arg1->type) {
5100 case XPATH_UNDEFINED:
5101#ifdef DEBUG_EXPR
5102 xmlGenericError(xmlGenericErrorContext,
5103 "Equal: undefined\n");
5104#endif
5105 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005106 case XPATH_BOOLEAN:
5107 switch (arg2->type) {
5108 case XPATH_UNDEFINED:
5109#ifdef DEBUG_EXPR
5110 xmlGenericError(xmlGenericErrorContext,
5111 "Equal: undefined\n");
5112#endif
5113 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005114 case XPATH_BOOLEAN:
5115#ifdef DEBUG_EXPR
5116 xmlGenericError(xmlGenericErrorContext,
5117 "Equal: %d boolean %d \n",
5118 arg1->boolval, arg2->boolval);
5119#endif
5120 ret = (arg1->boolval == arg2->boolval);
5121 break;
5122 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00005123 ret = (arg1->boolval ==
5124 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00005125 break;
5126 case XPATH_STRING:
5127 if ((arg2->stringval == NULL) ||
5128 (arg2->stringval[0] == 0)) ret = 0;
5129 else
5130 ret = 1;
5131 ret = (arg1->boolval == ret);
5132 break;
5133 case XPATH_USERS:
5134 case XPATH_POINT:
5135 case XPATH_RANGE:
5136 case XPATH_LOCATIONSET:
5137 TODO
5138 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005139 case XPATH_NODESET:
5140 case XPATH_XSLT_TREE:
5141 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005142 }
5143 break;
5144 case XPATH_NUMBER:
5145 switch (arg2->type) {
5146 case XPATH_UNDEFINED:
5147#ifdef DEBUG_EXPR
5148 xmlGenericError(xmlGenericErrorContext,
5149 "Equal: undefined\n");
5150#endif
5151 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005152 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00005153 ret = (arg2->boolval==
5154 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00005155 break;
5156 case XPATH_STRING:
5157 valuePush(ctxt, arg2);
5158 xmlXPathNumberFunction(ctxt, 1);
5159 arg2 = valuePop(ctxt);
5160 /* no break on purpose */
5161 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005162 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00005163 if (xmlXPathIsNaN(arg1->floatval) ||
5164 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00005165 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005166 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5167 if (xmlXPathIsInf(arg2->floatval) == 1)
5168 ret = 1;
5169 else
5170 ret = 0;
5171 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5172 if (xmlXPathIsInf(arg2->floatval) == -1)
5173 ret = 1;
5174 else
5175 ret = 0;
5176 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5177 if (xmlXPathIsInf(arg1->floatval) == 1)
5178 ret = 1;
5179 else
5180 ret = 0;
5181 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5182 if (xmlXPathIsInf(arg1->floatval) == -1)
5183 ret = 1;
5184 else
5185 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005186 } else {
5187 ret = (arg1->floatval == arg2->floatval);
5188 }
Owen Taylor3473f882001-02-23 17:55:21 +00005189 break;
5190 case XPATH_USERS:
5191 case XPATH_POINT:
5192 case XPATH_RANGE:
5193 case XPATH_LOCATIONSET:
5194 TODO
5195 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005196 case XPATH_NODESET:
5197 case XPATH_XSLT_TREE:
5198 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005199 }
5200 break;
5201 case XPATH_STRING:
5202 switch (arg2->type) {
5203 case XPATH_UNDEFINED:
5204#ifdef DEBUG_EXPR
5205 xmlGenericError(xmlGenericErrorContext,
5206 "Equal: undefined\n");
5207#endif
5208 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005209 case XPATH_BOOLEAN:
5210 if ((arg1->stringval == NULL) ||
5211 (arg1->stringval[0] == 0)) ret = 0;
5212 else
5213 ret = 1;
5214 ret = (arg2->boolval == ret);
5215 break;
5216 case XPATH_STRING:
5217 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5218 break;
5219 case XPATH_NUMBER:
5220 valuePush(ctxt, arg1);
5221 xmlXPathNumberFunction(ctxt, 1);
5222 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005223 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00005224 if (xmlXPathIsNaN(arg1->floatval) ||
5225 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00005226 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005227 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5228 if (xmlXPathIsInf(arg2->floatval) == 1)
5229 ret = 1;
5230 else
5231 ret = 0;
5232 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5233 if (xmlXPathIsInf(arg2->floatval) == -1)
5234 ret = 1;
5235 else
5236 ret = 0;
5237 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5238 if (xmlXPathIsInf(arg1->floatval) == 1)
5239 ret = 1;
5240 else
5241 ret = 0;
5242 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5243 if (xmlXPathIsInf(arg1->floatval) == -1)
5244 ret = 1;
5245 else
5246 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005247 } else {
5248 ret = (arg1->floatval == arg2->floatval);
5249 }
Owen Taylor3473f882001-02-23 17:55:21 +00005250 break;
5251 case XPATH_USERS:
5252 case XPATH_POINT:
5253 case XPATH_RANGE:
5254 case XPATH_LOCATIONSET:
5255 TODO
5256 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00005257 case XPATH_NODESET:
5258 case XPATH_XSLT_TREE:
5259 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005260 }
5261 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 xmlXPathFreeObject(arg1);
5273 xmlXPathFreeObject(arg2);
5274 return(ret);
5275}
5276
William M. Brack0c022ad2002-07-12 00:56:01 +00005277/**
5278 * xmlXPathEqualValues:
5279 * @ctxt: the XPath Parser context
5280 *
5281 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5282 *
5283 * Returns 0 or 1 depending on the results of the test.
5284 */
5285int
5286xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5287 xmlXPathObjectPtr arg1, arg2, argtmp;
5288 int ret = 0;
5289
Daniel Veillard6128c012004-11-08 17:16:15 +00005290 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005291 arg2 = valuePop(ctxt);
5292 arg1 = valuePop(ctxt);
5293 if ((arg1 == NULL) || (arg2 == NULL)) {
5294 if (arg1 != NULL)
5295 xmlXPathFreeObject(arg1);
5296 else
5297 xmlXPathFreeObject(arg2);
5298 XP_ERROR0(XPATH_INVALID_OPERAND);
5299 }
5300
5301 if (arg1 == arg2) {
5302#ifdef DEBUG_EXPR
5303 xmlGenericError(xmlGenericErrorContext,
5304 "Equal: by pointer\n");
5305#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005306 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005307 return(1);
5308 }
5309
5310 /*
5311 *If either argument is a nodeset, it's a 'special case'
5312 */
5313 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5314 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5315 /*
5316 *Hack it to assure arg1 is the nodeset
5317 */
5318 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5319 argtmp = arg2;
5320 arg2 = arg1;
5321 arg1 = argtmp;
5322 }
5323 switch (arg2->type) {
5324 case XPATH_UNDEFINED:
5325#ifdef DEBUG_EXPR
5326 xmlGenericError(xmlGenericErrorContext,
5327 "Equal: undefined\n");
5328#endif
5329 break;
5330 case XPATH_NODESET:
5331 case XPATH_XSLT_TREE:
5332 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
5333 break;
5334 case XPATH_BOOLEAN:
5335 if ((arg1->nodesetval == NULL) ||
5336 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5337 else
5338 ret = 1;
5339 ret = (ret == arg2->boolval);
5340 break;
5341 case XPATH_NUMBER:
5342 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5343 break;
5344 case XPATH_STRING:
5345 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
5346 break;
5347 case XPATH_USERS:
5348 case XPATH_POINT:
5349 case XPATH_RANGE:
5350 case XPATH_LOCATIONSET:
5351 TODO
5352 break;
5353 }
5354 xmlXPathFreeObject(arg1);
5355 xmlXPathFreeObject(arg2);
5356 return(ret);
5357 }
5358
5359 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5360}
5361
5362/**
5363 * xmlXPathNotEqualValues:
5364 * @ctxt: the XPath Parser context
5365 *
5366 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5367 *
5368 * Returns 0 or 1 depending on the results of the test.
5369 */
5370int
5371xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
5372 xmlXPathObjectPtr arg1, arg2, argtmp;
5373 int ret = 0;
5374
Daniel Veillard6128c012004-11-08 17:16:15 +00005375 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005376 arg2 = valuePop(ctxt);
5377 arg1 = valuePop(ctxt);
5378 if ((arg1 == NULL) || (arg2 == NULL)) {
5379 if (arg1 != NULL)
5380 xmlXPathFreeObject(arg1);
5381 else
5382 xmlXPathFreeObject(arg2);
5383 XP_ERROR0(XPATH_INVALID_OPERAND);
5384 }
5385
5386 if (arg1 == arg2) {
5387#ifdef DEBUG_EXPR
5388 xmlGenericError(xmlGenericErrorContext,
5389 "NotEqual: by pointer\n");
5390#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005391 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005392 return(0);
5393 }
5394
5395 /*
5396 *If either argument is a nodeset, it's a 'special case'
5397 */
5398 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5399 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5400 /*
5401 *Hack it to assure arg1 is the nodeset
5402 */
5403 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5404 argtmp = arg2;
5405 arg2 = arg1;
5406 arg1 = argtmp;
5407 }
5408 switch (arg2->type) {
5409 case XPATH_UNDEFINED:
5410#ifdef DEBUG_EXPR
5411 xmlGenericError(xmlGenericErrorContext,
5412 "NotEqual: undefined\n");
5413#endif
5414 break;
5415 case XPATH_NODESET:
5416 case XPATH_XSLT_TREE:
5417 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5418 break;
5419 case XPATH_BOOLEAN:
5420 if ((arg1->nodesetval == NULL) ||
5421 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5422 else
5423 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005424 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005425 break;
5426 case XPATH_NUMBER:
5427 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5428 break;
5429 case XPATH_STRING:
5430 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5431 break;
5432 case XPATH_USERS:
5433 case XPATH_POINT:
5434 case XPATH_RANGE:
5435 case XPATH_LOCATIONSET:
5436 TODO
5437 break;
5438 }
5439 xmlXPathFreeObject(arg1);
5440 xmlXPathFreeObject(arg2);
5441 return(ret);
5442 }
5443
5444 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5445}
Owen Taylor3473f882001-02-23 17:55:21 +00005446
5447/**
5448 * xmlXPathCompareValues:
5449 * @ctxt: the XPath Parser context
5450 * @inf: less than (1) or greater than (0)
5451 * @strict: is the comparison strict
5452 *
5453 * Implement the compare operation on XPath objects:
5454 * @arg1 < @arg2 (1, 1, ...
5455 * @arg1 <= @arg2 (1, 0, ...
5456 * @arg1 > @arg2 (0, 1, ...
5457 * @arg1 >= @arg2 (0, 0, ...
5458 *
5459 * When neither object to be compared is a node-set and the operator is
5460 * <=, <, >=, >, then the objects are compared by converted both objects
5461 * to numbers and comparing the numbers according to IEEE 754. The <
5462 * comparison will be true if and only if the first number is less than the
5463 * second number. The <= comparison will be true if and only if the first
5464 * number is less than or equal to the second number. The > comparison
5465 * will be true if and only if the first number is greater than the second
5466 * number. The >= comparison will be true if and only if the first number
5467 * is greater than or equal to the second number.
5468 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005469 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005470 */
5471int
5472xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005473 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005474 xmlXPathObjectPtr arg1, arg2;
5475
Daniel Veillard6128c012004-11-08 17:16:15 +00005476 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005477 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005478 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005479 if ((arg1 == NULL) || (arg2 == NULL)) {
5480 if (arg1 != NULL)
5481 xmlXPathFreeObject(arg1);
5482 else
5483 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005484 XP_ERROR0(XPATH_INVALID_OPERAND);
5485 }
5486
William M. Brack0c022ad2002-07-12 00:56:01 +00005487 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5488 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00005489 /*
5490 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5491 * are not freed from within this routine; they will be freed from the
5492 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5493 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005494 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5495 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005496 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005497 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005498 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005499 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5500 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005501 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005502 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5503 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005504 }
5505 }
5506 return(ret);
5507 }
5508
5509 if (arg1->type != XPATH_NUMBER) {
5510 valuePush(ctxt, arg1);
5511 xmlXPathNumberFunction(ctxt, 1);
5512 arg1 = valuePop(ctxt);
5513 }
5514 if (arg1->type != XPATH_NUMBER) {
5515 xmlXPathFreeObject(arg1);
5516 xmlXPathFreeObject(arg2);
5517 XP_ERROR0(XPATH_INVALID_OPERAND);
5518 }
5519 if (arg2->type != XPATH_NUMBER) {
5520 valuePush(ctxt, arg2);
5521 xmlXPathNumberFunction(ctxt, 1);
5522 arg2 = valuePop(ctxt);
5523 }
5524 if (arg2->type != XPATH_NUMBER) {
5525 xmlXPathFreeObject(arg1);
5526 xmlXPathFreeObject(arg2);
5527 XP_ERROR0(XPATH_INVALID_OPERAND);
5528 }
5529 /*
5530 * Add tests for infinity and nan
5531 * => feedback on 3.4 for Inf and NaN
5532 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005533 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005534 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005535 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005536 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005537 arg1i=xmlXPathIsInf(arg1->floatval);
5538 arg2i=xmlXPathIsInf(arg2->floatval);
5539 if (inf && strict) {
5540 if ((arg1i == -1 && arg2i != -1) ||
5541 (arg2i == 1 && arg1i != 1)) {
5542 ret = 1;
5543 } else if (arg1i == 0 && arg2i == 0) {
5544 ret = (arg1->floatval < arg2->floatval);
5545 } else {
5546 ret = 0;
5547 }
5548 }
5549 else if (inf && !strict) {
5550 if (arg1i == -1 || arg2i == 1) {
5551 ret = 1;
5552 } else if (arg1i == 0 && arg2i == 0) {
5553 ret = (arg1->floatval <= arg2->floatval);
5554 } else {
5555 ret = 0;
5556 }
5557 }
5558 else if (!inf && strict) {
5559 if ((arg1i == 1 && arg2i != 1) ||
5560 (arg2i == -1 && arg1i != -1)) {
5561 ret = 1;
5562 } else if (arg1i == 0 && arg2i == 0) {
5563 ret = (arg1->floatval > arg2->floatval);
5564 } else {
5565 ret = 0;
5566 }
5567 }
5568 else if (!inf && !strict) {
5569 if (arg1i == 1 || arg2i == -1) {
5570 ret = 1;
5571 } else if (arg1i == 0 && arg2i == 0) {
5572 ret = (arg1->floatval >= arg2->floatval);
5573 } else {
5574 ret = 0;
5575 }
5576 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005577 }
Owen Taylor3473f882001-02-23 17:55:21 +00005578 xmlXPathFreeObject(arg1);
5579 xmlXPathFreeObject(arg2);
5580 return(ret);
5581}
5582
5583/**
5584 * xmlXPathValueFlipSign:
5585 * @ctxt: the XPath Parser context
5586 *
5587 * Implement the unary - operation on an XPath object
5588 * The numeric operators convert their operands to numbers as if
5589 * by calling the number function.
5590 */
5591void
5592xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005593 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005594 CAST_TO_NUMBER;
5595 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005596 if (xmlXPathIsNaN(ctxt->value->floatval))
5597 ctxt->value->floatval=xmlXPathNAN;
5598 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5599 ctxt->value->floatval=xmlXPathNINF;
5600 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5601 ctxt->value->floatval=xmlXPathPINF;
5602 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005603 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5604 ctxt->value->floatval = xmlXPathNZERO;
5605 else
5606 ctxt->value->floatval = 0;
5607 }
5608 else
5609 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005610}
5611
5612/**
5613 * xmlXPathAddValues:
5614 * @ctxt: the XPath Parser context
5615 *
5616 * Implement the add operation on XPath objects:
5617 * The numeric operators convert their operands to numbers as if
5618 * by calling the number function.
5619 */
5620void
5621xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5622 xmlXPathObjectPtr arg;
5623 double val;
5624
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005625 arg = valuePop(ctxt);
5626 if (arg == NULL)
5627 XP_ERROR(XPATH_INVALID_OPERAND);
5628 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005629 xmlXPathFreeObject(arg);
5630
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005631 CAST_TO_NUMBER;
5632 CHECK_TYPE(XPATH_NUMBER);
5633 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005634}
5635
5636/**
5637 * xmlXPathSubValues:
5638 * @ctxt: the XPath Parser context
5639 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005640 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005641 * The numeric operators convert their operands to numbers as if
5642 * by calling the number function.
5643 */
5644void
5645xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5646 xmlXPathObjectPtr arg;
5647 double val;
5648
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005649 arg = valuePop(ctxt);
5650 if (arg == NULL)
5651 XP_ERROR(XPATH_INVALID_OPERAND);
5652 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005653 xmlXPathFreeObject(arg);
5654
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005655 CAST_TO_NUMBER;
5656 CHECK_TYPE(XPATH_NUMBER);
5657 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005658}
5659
5660/**
5661 * xmlXPathMultValues:
5662 * @ctxt: the XPath Parser context
5663 *
5664 * Implement the multiply operation on XPath objects:
5665 * The numeric operators convert their operands to numbers as if
5666 * by calling the number function.
5667 */
5668void
5669xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5670 xmlXPathObjectPtr arg;
5671 double val;
5672
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005673 arg = valuePop(ctxt);
5674 if (arg == NULL)
5675 XP_ERROR(XPATH_INVALID_OPERAND);
5676 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005677 xmlXPathFreeObject(arg);
5678
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005679 CAST_TO_NUMBER;
5680 CHECK_TYPE(XPATH_NUMBER);
5681 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005682}
5683
5684/**
5685 * xmlXPathDivValues:
5686 * @ctxt: the XPath Parser context
5687 *
5688 * Implement the div operation on XPath objects @arg1 / @arg2:
5689 * The numeric operators convert their operands to numbers as if
5690 * by calling the number function.
5691 */
5692void
5693xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5694 xmlXPathObjectPtr arg;
5695 double val;
5696
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005697 arg = valuePop(ctxt);
5698 if (arg == NULL)
5699 XP_ERROR(XPATH_INVALID_OPERAND);
5700 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005701 xmlXPathFreeObject(arg);
5702
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005703 CAST_TO_NUMBER;
5704 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005705 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5706 ctxt->value->floatval = xmlXPathNAN;
5707 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005708 if (ctxt->value->floatval == 0)
5709 ctxt->value->floatval = xmlXPathNAN;
5710 else if (ctxt->value->floatval > 0)
5711 ctxt->value->floatval = xmlXPathNINF;
5712 else if (ctxt->value->floatval < 0)
5713 ctxt->value->floatval = xmlXPathPINF;
5714 }
5715 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005716 if (ctxt->value->floatval == 0)
5717 ctxt->value->floatval = xmlXPathNAN;
5718 else if (ctxt->value->floatval > 0)
5719 ctxt->value->floatval = xmlXPathPINF;
5720 else if (ctxt->value->floatval < 0)
5721 ctxt->value->floatval = xmlXPathNINF;
5722 } else
5723 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005724}
5725
5726/**
5727 * xmlXPathModValues:
5728 * @ctxt: the XPath Parser context
5729 *
5730 * Implement the mod operation on XPath objects: @arg1 / @arg2
5731 * The numeric operators convert their operands to numbers as if
5732 * by calling the number function.
5733 */
5734void
5735xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5736 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005737 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005738
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005739 arg = valuePop(ctxt);
5740 if (arg == NULL)
5741 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005742 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005743 xmlXPathFreeObject(arg);
5744
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005745 CAST_TO_NUMBER;
5746 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005747 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005748 if (arg2 == 0)
5749 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005750 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005751 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005752 }
Owen Taylor3473f882001-02-23 17:55:21 +00005753}
5754
5755/************************************************************************
5756 * *
5757 * The traversal functions *
5758 * *
5759 ************************************************************************/
5760
Owen Taylor3473f882001-02-23 17:55:21 +00005761/*
5762 * A traversal function enumerates nodes along an axis.
5763 * Initially it must be called with NULL, and it indicates
5764 * termination on the axis by returning NULL.
5765 */
5766typedef xmlNodePtr (*xmlXPathTraversalFunction)
5767 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5768
5769/**
5770 * xmlXPathNextSelf:
5771 * @ctxt: the XPath Parser context
5772 * @cur: the current node in the traversal
5773 *
5774 * Traversal function for the "self" direction
5775 * The self axis contains just the context node itself
5776 *
5777 * Returns the next element following that axis
5778 */
5779xmlNodePtr
5780xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005781 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005782 if (cur == NULL)
5783 return(ctxt->context->node);
5784 return(NULL);
5785}
5786
5787/**
5788 * xmlXPathNextChild:
5789 * @ctxt: the XPath Parser context
5790 * @cur: the current node in the traversal
5791 *
5792 * Traversal function for the "child" direction
5793 * The child axis contains the children of the context node in document order.
5794 *
5795 * Returns the next element following that axis
5796 */
5797xmlNodePtr
5798xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005799 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005800 if (cur == NULL) {
5801 if (ctxt->context->node == NULL) return(NULL);
5802 switch (ctxt->context->node->type) {
5803 case XML_ELEMENT_NODE:
5804 case XML_TEXT_NODE:
5805 case XML_CDATA_SECTION_NODE:
5806 case XML_ENTITY_REF_NODE:
5807 case XML_ENTITY_NODE:
5808 case XML_PI_NODE:
5809 case XML_COMMENT_NODE:
5810 case XML_NOTATION_NODE:
5811 case XML_DTD_NODE:
5812 return(ctxt->context->node->children);
5813 case XML_DOCUMENT_NODE:
5814 case XML_DOCUMENT_TYPE_NODE:
5815 case XML_DOCUMENT_FRAG_NODE:
5816 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005817#ifdef LIBXML_DOCB_ENABLED
5818 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005819#endif
5820 return(((xmlDocPtr) ctxt->context->node)->children);
5821 case XML_ELEMENT_DECL:
5822 case XML_ATTRIBUTE_DECL:
5823 case XML_ENTITY_DECL:
5824 case XML_ATTRIBUTE_NODE:
5825 case XML_NAMESPACE_DECL:
5826 case XML_XINCLUDE_START:
5827 case XML_XINCLUDE_END:
5828 return(NULL);
5829 }
5830 return(NULL);
5831 }
5832 if ((cur->type == XML_DOCUMENT_NODE) ||
5833 (cur->type == XML_HTML_DOCUMENT_NODE))
5834 return(NULL);
5835 return(cur->next);
5836}
5837
5838/**
5839 * xmlXPathNextDescendant:
5840 * @ctxt: the XPath Parser context
5841 * @cur: the current node in the traversal
5842 *
5843 * Traversal function for the "descendant" direction
5844 * the descendant axis contains the descendants of the context node in document
5845 * order; a descendant is a child or a child of a child and so on.
5846 *
5847 * Returns the next element following that axis
5848 */
5849xmlNodePtr
5850xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005851 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005852 if (cur == NULL) {
5853 if (ctxt->context->node == NULL)
5854 return(NULL);
5855 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5856 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5857 return(NULL);
5858
5859 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5860 return(ctxt->context->doc->children);
5861 return(ctxt->context->node->children);
5862 }
5863
Daniel Veillard567e1b42001-08-01 15:53:47 +00005864 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005865 /*
5866 * Do not descend on entities declarations
5867 */
5868 if (cur->children->type != XML_ENTITY_DECL) {
5869 cur = cur->children;
5870 /*
5871 * Skip DTDs
5872 */
5873 if (cur->type != XML_DTD_NODE)
5874 return(cur);
5875 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005876 }
5877
5878 if (cur == ctxt->context->node) return(NULL);
5879
Daniel Veillard68e9e742002-11-16 15:35:11 +00005880 while (cur->next != NULL) {
5881 cur = cur->next;
5882 if ((cur->type != XML_ENTITY_DECL) &&
5883 (cur->type != XML_DTD_NODE))
5884 return(cur);
5885 }
Owen Taylor3473f882001-02-23 17:55:21 +00005886
5887 do {
5888 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00005889 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00005890 if (cur == ctxt->context->node) return(NULL);
5891 if (cur->next != NULL) {
5892 cur = cur->next;
5893 return(cur);
5894 }
5895 } while (cur != NULL);
5896 return(cur);
5897}
5898
5899/**
5900 * xmlXPathNextDescendantOrSelf:
5901 * @ctxt: the XPath Parser context
5902 * @cur: the current node in the traversal
5903 *
5904 * Traversal function for the "descendant-or-self" direction
5905 * the descendant-or-self axis contains the context node and the descendants
5906 * of the context node in document order; thus the context node is the first
5907 * node on the axis, and the first child of the context node is the second node
5908 * on the axis
5909 *
5910 * Returns the next element following that axis
5911 */
5912xmlNodePtr
5913xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005914 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005915 if (cur == NULL) {
5916 if (ctxt->context->node == NULL)
5917 return(NULL);
5918 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5919 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5920 return(NULL);
5921 return(ctxt->context->node);
5922 }
5923
5924 return(xmlXPathNextDescendant(ctxt, cur));
5925}
5926
5927/**
5928 * xmlXPathNextParent:
5929 * @ctxt: the XPath Parser context
5930 * @cur: the current node in the traversal
5931 *
5932 * Traversal function for the "parent" direction
5933 * The parent axis contains the parent of the context node, if there is one.
5934 *
5935 * Returns the next element following that axis
5936 */
5937xmlNodePtr
5938xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005939 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005940 /*
5941 * the parent of an attribute or namespace node is the element
5942 * to which the attribute or namespace node is attached
5943 * Namespace handling !!!
5944 */
5945 if (cur == NULL) {
5946 if (ctxt->context->node == NULL) return(NULL);
5947 switch (ctxt->context->node->type) {
5948 case XML_ELEMENT_NODE:
5949 case XML_TEXT_NODE:
5950 case XML_CDATA_SECTION_NODE:
5951 case XML_ENTITY_REF_NODE:
5952 case XML_ENTITY_NODE:
5953 case XML_PI_NODE:
5954 case XML_COMMENT_NODE:
5955 case XML_NOTATION_NODE:
5956 case XML_DTD_NODE:
5957 case XML_ELEMENT_DECL:
5958 case XML_ATTRIBUTE_DECL:
5959 case XML_XINCLUDE_START:
5960 case XML_XINCLUDE_END:
5961 case XML_ENTITY_DECL:
5962 if (ctxt->context->node->parent == NULL)
5963 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005964 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005965 ((ctxt->context->node->parent->name[0] == ' ') ||
5966 (xmlStrEqual(ctxt->context->node->parent->name,
5967 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005968 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005969 return(ctxt->context->node->parent);
5970 case XML_ATTRIBUTE_NODE: {
5971 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5972
5973 return(att->parent);
5974 }
5975 case XML_DOCUMENT_NODE:
5976 case XML_DOCUMENT_TYPE_NODE:
5977 case XML_DOCUMENT_FRAG_NODE:
5978 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005979#ifdef LIBXML_DOCB_ENABLED
5980 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005981#endif
5982 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005983 case XML_NAMESPACE_DECL: {
5984 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5985
5986 if ((ns->next != NULL) &&
5987 (ns->next->type != XML_NAMESPACE_DECL))
5988 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005989 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005990 }
Owen Taylor3473f882001-02-23 17:55:21 +00005991 }
5992 }
5993 return(NULL);
5994}
5995
5996/**
5997 * xmlXPathNextAncestor:
5998 * @ctxt: the XPath Parser context
5999 * @cur: the current node in the traversal
6000 *
6001 * Traversal function for the "ancestor" direction
6002 * the ancestor axis contains the ancestors of the context node; the ancestors
6003 * of the context node consist of the parent of context node and the parent's
6004 * parent and so on; the nodes are ordered in reverse document order; thus the
6005 * parent is the first node on the axis, and the parent's parent is the second
6006 * node on the axis
6007 *
6008 * Returns the next element following that axis
6009 */
6010xmlNodePtr
6011xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006012 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006013 /*
6014 * the parent of an attribute or namespace node is the element
6015 * to which the attribute or namespace node is attached
6016 * !!!!!!!!!!!!!
6017 */
6018 if (cur == NULL) {
6019 if (ctxt->context->node == NULL) return(NULL);
6020 switch (ctxt->context->node->type) {
6021 case XML_ELEMENT_NODE:
6022 case XML_TEXT_NODE:
6023 case XML_CDATA_SECTION_NODE:
6024 case XML_ENTITY_REF_NODE:
6025 case XML_ENTITY_NODE:
6026 case XML_PI_NODE:
6027 case XML_COMMENT_NODE:
6028 case XML_DTD_NODE:
6029 case XML_ELEMENT_DECL:
6030 case XML_ATTRIBUTE_DECL:
6031 case XML_ENTITY_DECL:
6032 case XML_NOTATION_NODE:
6033 case XML_XINCLUDE_START:
6034 case XML_XINCLUDE_END:
6035 if (ctxt->context->node->parent == NULL)
6036 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006037 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00006038 ((ctxt->context->node->parent->name[0] == ' ') ||
6039 (xmlStrEqual(ctxt->context->node->parent->name,
6040 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006041 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006042 return(ctxt->context->node->parent);
6043 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006044 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00006045
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006046 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00006047 }
6048 case XML_DOCUMENT_NODE:
6049 case XML_DOCUMENT_TYPE_NODE:
6050 case XML_DOCUMENT_FRAG_NODE:
6051 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00006052#ifdef LIBXML_DOCB_ENABLED
6053 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00006054#endif
6055 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006056 case XML_NAMESPACE_DECL: {
6057 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6058
6059 if ((ns->next != NULL) &&
6060 (ns->next->type != XML_NAMESPACE_DECL))
6061 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00006062 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00006063 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00006064 }
Owen Taylor3473f882001-02-23 17:55:21 +00006065 }
6066 return(NULL);
6067 }
6068 if (cur == ctxt->context->doc->children)
6069 return((xmlNodePtr) ctxt->context->doc);
6070 if (cur == (xmlNodePtr) ctxt->context->doc)
6071 return(NULL);
6072 switch (cur->type) {
6073 case XML_ELEMENT_NODE:
6074 case XML_TEXT_NODE:
6075 case XML_CDATA_SECTION_NODE:
6076 case XML_ENTITY_REF_NODE:
6077 case XML_ENTITY_NODE:
6078 case XML_PI_NODE:
6079 case XML_COMMENT_NODE:
6080 case XML_NOTATION_NODE:
6081 case XML_DTD_NODE:
6082 case XML_ELEMENT_DECL:
6083 case XML_ATTRIBUTE_DECL:
6084 case XML_ENTITY_DECL:
6085 case XML_XINCLUDE_START:
6086 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006087 if (cur->parent == NULL)
6088 return(NULL);
6089 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00006090 ((cur->parent->name[0] == ' ') ||
6091 (xmlStrEqual(cur->parent->name,
6092 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00006093 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006094 return(cur->parent);
6095 case XML_ATTRIBUTE_NODE: {
6096 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6097
6098 return(att->parent);
6099 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00006100 case XML_NAMESPACE_DECL: {
6101 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6102
6103 if ((ns->next != NULL) &&
6104 (ns->next->type != XML_NAMESPACE_DECL))
6105 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00006106 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00006107 return(NULL);
6108 }
Owen Taylor3473f882001-02-23 17:55:21 +00006109 case XML_DOCUMENT_NODE:
6110 case XML_DOCUMENT_TYPE_NODE:
6111 case XML_DOCUMENT_FRAG_NODE:
6112 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00006113#ifdef LIBXML_DOCB_ENABLED
6114 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00006115#endif
6116 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006117 }
6118 return(NULL);
6119}
6120
6121/**
6122 * xmlXPathNextAncestorOrSelf:
6123 * @ctxt: the XPath Parser context
6124 * @cur: the current node in the traversal
6125 *
6126 * Traversal function for the "ancestor-or-self" direction
6127 * he ancestor-or-self axis contains the context node and ancestors of
6128 * the context node in reverse document order; thus the context node is
6129 * the first node on the axis, and the context node's parent the second;
6130 * parent here is defined the same as with the parent axis.
6131 *
6132 * Returns the next element following that axis
6133 */
6134xmlNodePtr
6135xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006136 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006137 if (cur == NULL)
6138 return(ctxt->context->node);
6139 return(xmlXPathNextAncestor(ctxt, cur));
6140}
6141
6142/**
6143 * xmlXPathNextFollowingSibling:
6144 * @ctxt: the XPath Parser context
6145 * @cur: the current node in the traversal
6146 *
6147 * Traversal function for the "following-sibling" direction
6148 * The following-sibling axis contains the following siblings of the context
6149 * node in document order.
6150 *
6151 * Returns the next element following that axis
6152 */
6153xmlNodePtr
6154xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006155 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006156 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6157 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6158 return(NULL);
6159 if (cur == (xmlNodePtr) ctxt->context->doc)
6160 return(NULL);
6161 if (cur == NULL)
6162 return(ctxt->context->node->next);
6163 return(cur->next);
6164}
6165
6166/**
6167 * xmlXPathNextPrecedingSibling:
6168 * @ctxt: the XPath Parser context
6169 * @cur: the current node in the traversal
6170 *
6171 * Traversal function for the "preceding-sibling" direction
6172 * The preceding-sibling axis contains the preceding siblings of the context
6173 * node in reverse document order; the first preceding sibling is first on the
6174 * axis; the sibling preceding that node is the second on the axis and so on.
6175 *
6176 * Returns the next element following that axis
6177 */
6178xmlNodePtr
6179xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006180 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006181 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6182 (ctxt->context->node->type == XML_NAMESPACE_DECL))
6183 return(NULL);
6184 if (cur == (xmlNodePtr) ctxt->context->doc)
6185 return(NULL);
6186 if (cur == NULL)
6187 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006188 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6189 cur = cur->prev;
6190 if (cur == NULL)
6191 return(ctxt->context->node->prev);
6192 }
Owen Taylor3473f882001-02-23 17:55:21 +00006193 return(cur->prev);
6194}
6195
6196/**
6197 * xmlXPathNextFollowing:
6198 * @ctxt: the XPath Parser context
6199 * @cur: the current node in the traversal
6200 *
6201 * Traversal function for the "following" direction
6202 * The following axis contains all nodes in the same document as the context
6203 * node that are after the context node in document order, excluding any
6204 * descendants and excluding attribute nodes and namespace nodes; the nodes
6205 * are ordered in document order
6206 *
6207 * Returns the next element following that axis
6208 */
6209xmlNodePtr
6210xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006211 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006212 if (cur != NULL && cur->children != NULL)
6213 return cur->children ;
6214 if (cur == NULL) cur = ctxt->context->node;
6215 if (cur == NULL) return(NULL) ; /* ERROR */
6216 if (cur->next != NULL) return(cur->next) ;
6217 do {
6218 cur = cur->parent;
Daniel Veillard11ce4002006-03-10 00:36:23 +00006219 if (cur == NULL) break;
Owen Taylor3473f882001-02-23 17:55:21 +00006220 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6221 if (cur->next != NULL) return(cur->next);
6222 } while (cur != NULL);
6223 return(cur);
6224}
6225
6226/*
6227 * xmlXPathIsAncestor:
6228 * @ancestor: the ancestor node
6229 * @node: the current node
6230 *
6231 * Check that @ancestor is a @node's ancestor
6232 *
6233 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
6234 */
6235static int
6236xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6237 if ((ancestor == NULL) || (node == NULL)) return(0);
6238 /* nodes need to be in the same document */
6239 if (ancestor->doc != node->doc) return(0);
6240 /* avoid searching if ancestor or node is the root node */
6241 if (ancestor == (xmlNodePtr) node->doc) return(1);
6242 if (node == (xmlNodePtr) ancestor->doc) return(0);
6243 while (node->parent != NULL) {
6244 if (node->parent == ancestor)
6245 return(1);
6246 node = node->parent;
6247 }
6248 return(0);
6249}
6250
6251/**
6252 * xmlXPathNextPreceding:
6253 * @ctxt: the XPath Parser context
6254 * @cur: the current node in the traversal
6255 *
6256 * Traversal function for the "preceding" direction
6257 * the preceding axis contains all nodes in the same document as the context
6258 * node that are before the context node in document order, excluding any
6259 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6260 * ordered in reverse document order
6261 *
6262 * Returns the next element following that axis
6263 */
6264xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00006265xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
6266{
Daniel Veillarda82b1822004-11-08 16:24:57 +00006267 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006268 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00006269 cur = ctxt->context->node;
6270 if (cur == NULL)
6271 return (NULL);
6272 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6273 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00006274 do {
6275 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00006276 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6277 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006278 }
6279
6280 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006281 if (cur == NULL)
6282 return (NULL);
6283 if (cur == ctxt->context->doc->children)
6284 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006285 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00006286 return (cur);
6287}
6288
6289/**
6290 * xmlXPathNextPrecedingInternal:
6291 * @ctxt: the XPath Parser context
6292 * @cur: the current node in the traversal
6293 *
6294 * Traversal function for the "preceding" direction
6295 * the preceding axis contains all nodes in the same document as the context
6296 * node that are before the context node in document order, excluding any
6297 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6298 * ordered in reverse document order
6299 * This is a faster implementation but internal only since it requires a
6300 * state kept in the parser context: ctxt->ancestor.
6301 *
6302 * Returns the next element following that axis
6303 */
6304static xmlNodePtr
6305xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6306 xmlNodePtr cur)
6307{
Daniel Veillarda82b1822004-11-08 16:24:57 +00006308 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00006309 if (cur == NULL) {
6310 cur = ctxt->context->node;
6311 if (cur == NULL)
6312 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00006313 if (cur->type == XML_NAMESPACE_DECL)
6314 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00006315 ctxt->ancestor = cur->parent;
6316 }
6317 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6318 cur = cur->prev;
6319 while (cur->prev == NULL) {
6320 cur = cur->parent;
6321 if (cur == NULL)
6322 return (NULL);
6323 if (cur == ctxt->context->doc->children)
6324 return (NULL);
6325 if (cur != ctxt->ancestor)
6326 return (cur);
6327 ctxt->ancestor = cur->parent;
6328 }
6329 cur = cur->prev;
6330 while (cur->last != NULL)
6331 cur = cur->last;
6332 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006333}
6334
6335/**
6336 * xmlXPathNextNamespace:
6337 * @ctxt: the XPath Parser context
6338 * @cur: the current attribute in the traversal
6339 *
6340 * Traversal function for the "namespace" direction
6341 * the namespace axis contains the namespace nodes of the context node;
6342 * the order of nodes on this axis is implementation-defined; the axis will
6343 * be empty unless the context node is an element
6344 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00006345 * We keep the XML namespace node at the end of the list.
6346 *
Owen Taylor3473f882001-02-23 17:55:21 +00006347 * Returns the next element following that axis
6348 */
6349xmlNodePtr
6350xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006351 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006352 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00006353 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006354 if (ctxt->context->tmpNsList != NULL)
6355 xmlFree(ctxt->context->tmpNsList);
6356 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00006357 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006358 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00006359 if (ctxt->context->tmpNsList != NULL) {
6360 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6361 ctxt->context->tmpNsNr++;
6362 }
6363 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00006364 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00006365 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00006366 if (ctxt->context->tmpNsNr > 0) {
6367 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6368 } else {
6369 if (ctxt->context->tmpNsList != NULL)
6370 xmlFree(ctxt->context->tmpNsList);
6371 ctxt->context->tmpNsList = NULL;
6372 return(NULL);
6373 }
Owen Taylor3473f882001-02-23 17:55:21 +00006374}
6375
6376/**
6377 * xmlXPathNextAttribute:
6378 * @ctxt: the XPath Parser context
6379 * @cur: the current attribute in the traversal
6380 *
6381 * Traversal function for the "attribute" direction
6382 * TODO: support DTD inherited default attributes
6383 *
6384 * Returns the next element following that axis
6385 */
6386xmlNodePtr
6387xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006388 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006389 if (ctxt->context->node == NULL)
6390 return(NULL);
6391 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6392 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006393 if (cur == NULL) {
6394 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6395 return(NULL);
6396 return((xmlNodePtr)ctxt->context->node->properties);
6397 }
6398 return((xmlNodePtr)cur->next);
6399}
6400
6401/************************************************************************
6402 * *
6403 * NodeTest Functions *
6404 * *
6405 ************************************************************************/
6406
Owen Taylor3473f882001-02-23 17:55:21 +00006407#define IS_FUNCTION 200
6408
Owen Taylor3473f882001-02-23 17:55:21 +00006409
6410/************************************************************************
6411 * *
6412 * Implicit tree core function library *
6413 * *
6414 ************************************************************************/
6415
6416/**
6417 * xmlXPathRoot:
6418 * @ctxt: the XPath Parser context
6419 *
6420 * Initialize the context to the root of the document
6421 */
6422void
6423xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006424 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006425 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6426 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6427}
6428
6429/************************************************************************
6430 * *
6431 * The explicit core function library *
6432 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6433 * *
6434 ************************************************************************/
6435
6436
6437/**
6438 * xmlXPathLastFunction:
6439 * @ctxt: the XPath Parser context
6440 * @nargs: the number of arguments
6441 *
6442 * Implement the last() XPath function
6443 * number last()
6444 * The last function returns the number of nodes in the context node list.
6445 */
6446void
6447xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6448 CHECK_ARITY(0);
6449 if (ctxt->context->contextSize >= 0) {
6450 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6451#ifdef DEBUG_EXPR
6452 xmlGenericError(xmlGenericErrorContext,
6453 "last() : %d\n", ctxt->context->contextSize);
6454#endif
6455 } else {
6456 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6457 }
6458}
6459
6460/**
6461 * xmlXPathPositionFunction:
6462 * @ctxt: the XPath Parser context
6463 * @nargs: the number of arguments
6464 *
6465 * Implement the position() XPath function
6466 * number position()
6467 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006468 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006469 * will be equal to last().
6470 */
6471void
6472xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6473 CHECK_ARITY(0);
6474 if (ctxt->context->proximityPosition >= 0) {
6475 valuePush(ctxt,
6476 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6477#ifdef DEBUG_EXPR
6478 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6479 ctxt->context->proximityPosition);
6480#endif
6481 } else {
6482 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6483 }
6484}
6485
6486/**
6487 * xmlXPathCountFunction:
6488 * @ctxt: the XPath Parser context
6489 * @nargs: the number of arguments
6490 *
6491 * Implement the count() XPath function
6492 * number count(node-set)
6493 */
6494void
6495xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6496 xmlXPathObjectPtr cur;
6497
6498 CHECK_ARITY(1);
6499 if ((ctxt->value == NULL) ||
6500 ((ctxt->value->type != XPATH_NODESET) &&
6501 (ctxt->value->type != XPATH_XSLT_TREE)))
6502 XP_ERROR(XPATH_INVALID_TYPE);
6503 cur = valuePop(ctxt);
6504
Daniel Veillard911f49a2001-04-07 15:39:35 +00006505 if ((cur == NULL) || (cur->nodesetval == NULL))
6506 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006507 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006508 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006509 } else {
6510 if ((cur->nodesetval->nodeNr != 1) ||
6511 (cur->nodesetval->nodeTab == NULL)) {
6512 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6513 } else {
6514 xmlNodePtr tmp;
6515 int i = 0;
6516
6517 tmp = cur->nodesetval->nodeTab[0];
6518 if (tmp != NULL) {
6519 tmp = tmp->children;
6520 while (tmp != NULL) {
6521 tmp = tmp->next;
6522 i++;
6523 }
6524 }
6525 valuePush(ctxt, xmlXPathNewFloat((double) i));
6526 }
6527 }
Owen Taylor3473f882001-02-23 17:55:21 +00006528 xmlXPathFreeObject(cur);
6529}
6530
6531/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006532 * xmlXPathGetElementsByIds:
6533 * @doc: the document
6534 * @ids: a whitespace separated list of IDs
6535 *
6536 * Selects elements by their unique ID.
6537 *
6538 * Returns a node-set of selected elements.
6539 */
6540static xmlNodeSetPtr
6541xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6542 xmlNodeSetPtr ret;
6543 const xmlChar *cur = ids;
6544 xmlChar *ID;
6545 xmlAttrPtr attr;
6546 xmlNodePtr elem = NULL;
6547
Daniel Veillard7a985a12003-07-06 17:57:42 +00006548 if (ids == NULL) return(NULL);
6549
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006550 ret = xmlXPathNodeSetCreate(NULL);
6551
William M. Brack76e95df2003-10-18 16:20:14 +00006552 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006553 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006554 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006555 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006556
6557 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006558 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006559 /*
6560 * We used to check the fact that the value passed
6561 * was an NCName, but this generated much troubles for
6562 * me and Aleksey Sanin, people blatantly violated that
6563 * constaint, like Visa3D spec.
6564 * if (xmlValidateNCName(ID, 1) == 0)
6565 */
6566 attr = xmlGetID(doc, ID);
6567 if (attr != NULL) {
6568 if (attr->type == XML_ATTRIBUTE_NODE)
6569 elem = attr->parent;
6570 else if (attr->type == XML_ELEMENT_NODE)
6571 elem = (xmlNodePtr) attr;
6572 else
6573 elem = NULL;
6574 if (elem != NULL)
6575 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006576 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006577 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006578 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006579
William M. Brack76e95df2003-10-18 16:20:14 +00006580 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006581 ids = cur;
6582 }
6583 return(ret);
6584}
6585
6586/**
Owen Taylor3473f882001-02-23 17:55:21 +00006587 * xmlXPathIdFunction:
6588 * @ctxt: the XPath Parser context
6589 * @nargs: the number of arguments
6590 *
6591 * Implement the id() XPath function
6592 * node-set id(object)
6593 * The id function selects elements by their unique ID
6594 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6595 * then the result is the union of the result of applying id to the
6596 * string value of each of the nodes in the argument node-set. When the
6597 * argument to id is of any other type, the argument is converted to a
6598 * string as if by a call to the string function; the string is split
6599 * into a whitespace-separated list of tokens (whitespace is any sequence
6600 * of characters matching the production S); the result is a node-set
6601 * containing the elements in the same document as the context node that
6602 * have a unique ID equal to any of the tokens in the list.
6603 */
6604void
6605xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006606 xmlChar *tokens;
6607 xmlNodeSetPtr ret;
6608 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006609
6610 CHECK_ARITY(1);
6611 obj = valuePop(ctxt);
6612 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006613 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006614 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006615 int i;
6616
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006617 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006618
Daniel Veillard911f49a2001-04-07 15:39:35 +00006619 if (obj->nodesetval != NULL) {
6620 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006621 tokens =
6622 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6623 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6624 ret = xmlXPathNodeSetMerge(ret, ns);
6625 xmlXPathFreeNodeSet(ns);
6626 if (tokens != NULL)
6627 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006628 }
Owen Taylor3473f882001-02-23 17:55:21 +00006629 }
6630
6631 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006632 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006633 return;
6634 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006635 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006636
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006637 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6638 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006639
Owen Taylor3473f882001-02-23 17:55:21 +00006640 xmlXPathFreeObject(obj);
6641 return;
6642}
6643
6644/**
6645 * xmlXPathLocalNameFunction:
6646 * @ctxt: the XPath Parser context
6647 * @nargs: the number of arguments
6648 *
6649 * Implement the local-name() XPath function
6650 * string local-name(node-set?)
6651 * The local-name function returns a string containing the local part
6652 * of the name of the node in the argument node-set that is first in
6653 * document order. If the node-set is empty or the first node has no
6654 * name, an empty string is returned. If the argument is omitted it
6655 * defaults to the context node.
6656 */
6657void
6658xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6659 xmlXPathObjectPtr cur;
6660
Daniel Veillarda82b1822004-11-08 16:24:57 +00006661 if (ctxt == NULL) return;
6662
Owen Taylor3473f882001-02-23 17:55:21 +00006663 if (nargs == 0) {
6664 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6665 nargs = 1;
6666 }
6667
6668 CHECK_ARITY(1);
6669 if ((ctxt->value == NULL) ||
6670 ((ctxt->value->type != XPATH_NODESET) &&
6671 (ctxt->value->type != XPATH_XSLT_TREE)))
6672 XP_ERROR(XPATH_INVALID_TYPE);
6673 cur = valuePop(ctxt);
6674
Daniel Veillard911f49a2001-04-07 15:39:35 +00006675 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006676 valuePush(ctxt, xmlXPathNewCString(""));
6677 } else {
6678 int i = 0; /* Should be first in document order !!!!! */
6679 switch (cur->nodesetval->nodeTab[i]->type) {
6680 case XML_ELEMENT_NODE:
6681 case XML_ATTRIBUTE_NODE:
6682 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006683 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6684 valuePush(ctxt, xmlXPathNewCString(""));
6685 else
6686 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006687 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6688 break;
6689 case XML_NAMESPACE_DECL:
6690 valuePush(ctxt, xmlXPathNewString(
6691 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6692 break;
6693 default:
6694 valuePush(ctxt, xmlXPathNewCString(""));
6695 }
6696 }
6697 xmlXPathFreeObject(cur);
6698}
6699
6700/**
6701 * xmlXPathNamespaceURIFunction:
6702 * @ctxt: the XPath Parser context
6703 * @nargs: the number of arguments
6704 *
6705 * Implement the namespace-uri() XPath function
6706 * string namespace-uri(node-set?)
6707 * The namespace-uri function returns a string containing the
6708 * namespace URI of the expanded name of the node in the argument
6709 * node-set that is first in document order. If the node-set is empty,
6710 * the first node has no name, or the expanded name has no namespace
6711 * URI, an empty string is returned. If the argument is omitted it
6712 * defaults to the context node.
6713 */
6714void
6715xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6716 xmlXPathObjectPtr cur;
6717
Daniel Veillarda82b1822004-11-08 16:24:57 +00006718 if (ctxt == NULL) return;
6719
Owen Taylor3473f882001-02-23 17:55:21 +00006720 if (nargs == 0) {
6721 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6722 nargs = 1;
6723 }
6724 CHECK_ARITY(1);
6725 if ((ctxt->value == NULL) ||
6726 ((ctxt->value->type != XPATH_NODESET) &&
6727 (ctxt->value->type != XPATH_XSLT_TREE)))
6728 XP_ERROR(XPATH_INVALID_TYPE);
6729 cur = valuePop(ctxt);
6730
Daniel Veillard911f49a2001-04-07 15:39:35 +00006731 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006732 valuePush(ctxt, xmlXPathNewCString(""));
6733 } else {
6734 int i = 0; /* Should be first in document order !!!!! */
6735 switch (cur->nodesetval->nodeTab[i]->type) {
6736 case XML_ELEMENT_NODE:
6737 case XML_ATTRIBUTE_NODE:
6738 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6739 valuePush(ctxt, xmlXPathNewCString(""));
6740 else
6741 valuePush(ctxt, xmlXPathNewString(
6742 cur->nodesetval->nodeTab[i]->ns->href));
6743 break;
6744 default:
6745 valuePush(ctxt, xmlXPathNewCString(""));
6746 }
6747 }
6748 xmlXPathFreeObject(cur);
6749}
6750
6751/**
6752 * xmlXPathNameFunction:
6753 * @ctxt: the XPath Parser context
6754 * @nargs: the number of arguments
6755 *
6756 * Implement the name() XPath function
6757 * string name(node-set?)
6758 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006759 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006760 * order. The QName must represent the name with respect to the namespace
6761 * declarations in effect on the node whose name is being represented.
6762 * Typically, this will be the form in which the name occurred in the XML
6763 * source. This need not be the case if there are namespace declarations
6764 * in effect on the node that associate multiple prefixes with the same
6765 * namespace. However, an implementation may include information about
6766 * the original prefix in its representation of nodes; in this case, an
6767 * implementation can ensure that the returned string is always the same
6768 * as the QName used in the XML source. If the argument it omitted it
6769 * defaults to the context node.
6770 * Libxml keep the original prefix so the "real qualified name" used is
6771 * returned.
6772 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006773static void
Daniel Veillard04383752001-07-08 14:27:15 +00006774xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6775{
Owen Taylor3473f882001-02-23 17:55:21 +00006776 xmlXPathObjectPtr cur;
6777
6778 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006779 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6780 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006781 }
6782
6783 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006784 if ((ctxt->value == NULL) ||
6785 ((ctxt->value->type != XPATH_NODESET) &&
6786 (ctxt->value->type != XPATH_XSLT_TREE)))
6787 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006788 cur = valuePop(ctxt);
6789
Daniel Veillard911f49a2001-04-07 15:39:35 +00006790 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006791 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006792 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006793 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006794
Daniel Veillard04383752001-07-08 14:27:15 +00006795 switch (cur->nodesetval->nodeTab[i]->type) {
6796 case XML_ELEMENT_NODE:
6797 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006798 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6799 valuePush(ctxt, xmlXPathNewCString(""));
6800 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6801 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006802 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006803 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006804
Daniel Veillard652d8a92003-02-04 19:28:49 +00006805 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006806 xmlChar *fullname;
6807
6808 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6809 cur->nodesetval->nodeTab[i]->ns->prefix,
6810 NULL, 0);
6811 if (fullname == cur->nodesetval->nodeTab[i]->name)
6812 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6813 if (fullname == NULL) {
6814 XP_ERROR(XPATH_MEMORY_ERROR);
6815 }
6816 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006817 }
6818 break;
6819 default:
6820 valuePush(ctxt,
6821 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6822 xmlXPathLocalNameFunction(ctxt, 1);
6823 }
Owen Taylor3473f882001-02-23 17:55:21 +00006824 }
6825 xmlXPathFreeObject(cur);
6826}
6827
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006828
6829/**
Owen Taylor3473f882001-02-23 17:55:21 +00006830 * xmlXPathStringFunction:
6831 * @ctxt: the XPath Parser context
6832 * @nargs: the number of arguments
6833 *
6834 * Implement the string() XPath function
6835 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006836 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006837 * - A node-set is converted to a string by returning the value of
6838 * the node in the node-set that is first in document order.
6839 * If the node-set is empty, an empty string is returned.
6840 * - A number is converted to a string as follows
6841 * + NaN is converted to the string NaN
6842 * + positive zero is converted to the string 0
6843 * + negative zero is converted to the string 0
6844 * + positive infinity is converted to the string Infinity
6845 * + negative infinity is converted to the string -Infinity
6846 * + if the number is an integer, the number is represented in
6847 * decimal form as a Number with no decimal point and no leading
6848 * zeros, preceded by a minus sign (-) if the number is negative
6849 * + otherwise, the number is represented in decimal form as a
6850 * Number including a decimal point with at least one digit
6851 * before the decimal point and at least one digit after the
6852 * decimal point, preceded by a minus sign (-) if the number
6853 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006854 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006855 * before the decimal point; beyond the one required digit
6856 * after the decimal point there must be as many, but only as
6857 * many, more digits as are needed to uniquely distinguish the
6858 * number from all other IEEE 754 numeric values.
6859 * - The boolean false value is converted to the string false.
6860 * The boolean true value is converted to the string true.
6861 *
6862 * If the argument is omitted, it defaults to a node-set with the
6863 * context node as its only member.
6864 */
6865void
6866xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6867 xmlXPathObjectPtr cur;
6868
Daniel Veillarda82b1822004-11-08 16:24:57 +00006869 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006870 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006871 valuePush(ctxt,
6872 xmlXPathWrapString(
6873 xmlXPathCastNodeToString(ctxt->context->node)));
6874 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006875 }
6876
6877 CHECK_ARITY(1);
6878 cur = valuePop(ctxt);
6879 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006880 cur = xmlXPathConvertString(cur);
6881 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006882}
6883
6884/**
6885 * xmlXPathStringLengthFunction:
6886 * @ctxt: the XPath Parser context
6887 * @nargs: the number of arguments
6888 *
6889 * Implement the string-length() XPath function
6890 * number string-length(string?)
6891 * The string-length returns the number of characters in the string
6892 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6893 * the context node converted to a string, in other words the value
6894 * of the context node.
6895 */
6896void
6897xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6898 xmlXPathObjectPtr cur;
6899
6900 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006901 if ((ctxt == NULL) || (ctxt->context == NULL))
6902 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006903 if (ctxt->context->node == NULL) {
6904 valuePush(ctxt, xmlXPathNewFloat(0));
6905 } else {
6906 xmlChar *content;
6907
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006908 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006909 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006910 xmlFree(content);
6911 }
6912 return;
6913 }
6914 CHECK_ARITY(1);
6915 CAST_TO_STRING;
6916 CHECK_TYPE(XPATH_STRING);
6917 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006918 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006919 xmlXPathFreeObject(cur);
6920}
6921
6922/**
6923 * xmlXPathConcatFunction:
6924 * @ctxt: the XPath Parser context
6925 * @nargs: the number of arguments
6926 *
6927 * Implement the concat() XPath function
6928 * string concat(string, string, string*)
6929 * The concat function returns the concatenation of its arguments.
6930 */
6931void
6932xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6933 xmlXPathObjectPtr cur, newobj;
6934 xmlChar *tmp;
6935
Daniel Veillarda82b1822004-11-08 16:24:57 +00006936 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006937 if (nargs < 2) {
6938 CHECK_ARITY(2);
6939 }
6940
6941 CAST_TO_STRING;
6942 cur = valuePop(ctxt);
6943 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6944 xmlXPathFreeObject(cur);
6945 return;
6946 }
6947 nargs--;
6948
6949 while (nargs > 0) {
6950 CAST_TO_STRING;
6951 newobj = valuePop(ctxt);
6952 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6953 xmlXPathFreeObject(newobj);
6954 xmlXPathFreeObject(cur);
6955 XP_ERROR(XPATH_INVALID_TYPE);
6956 }
6957 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6958 newobj->stringval = cur->stringval;
6959 cur->stringval = tmp;
6960
6961 xmlXPathFreeObject(newobj);
6962 nargs--;
6963 }
6964 valuePush(ctxt, cur);
6965}
6966
6967/**
6968 * xmlXPathContainsFunction:
6969 * @ctxt: the XPath Parser context
6970 * @nargs: the number of arguments
6971 *
6972 * Implement the contains() XPath function
6973 * boolean contains(string, string)
6974 * The contains function returns true if the first argument string
6975 * contains the second argument string, and otherwise returns false.
6976 */
6977void
6978xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6979 xmlXPathObjectPtr hay, needle;
6980
6981 CHECK_ARITY(2);
6982 CAST_TO_STRING;
6983 CHECK_TYPE(XPATH_STRING);
6984 needle = valuePop(ctxt);
6985 CAST_TO_STRING;
6986 hay = valuePop(ctxt);
6987 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6988 xmlXPathFreeObject(hay);
6989 xmlXPathFreeObject(needle);
6990 XP_ERROR(XPATH_INVALID_TYPE);
6991 }
6992 if (xmlStrstr(hay->stringval, needle->stringval))
6993 valuePush(ctxt, xmlXPathNewBoolean(1));
6994 else
6995 valuePush(ctxt, xmlXPathNewBoolean(0));
6996 xmlXPathFreeObject(hay);
6997 xmlXPathFreeObject(needle);
6998}
6999
7000/**
7001 * xmlXPathStartsWithFunction:
7002 * @ctxt: the XPath Parser context
7003 * @nargs: the number of arguments
7004 *
7005 * Implement the starts-with() XPath function
7006 * boolean starts-with(string, string)
7007 * The starts-with function returns true if the first argument string
7008 * starts with the second argument string, and otherwise returns false.
7009 */
7010void
7011xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7012 xmlXPathObjectPtr hay, needle;
7013 int n;
7014
7015 CHECK_ARITY(2);
7016 CAST_TO_STRING;
7017 CHECK_TYPE(XPATH_STRING);
7018 needle = valuePop(ctxt);
7019 CAST_TO_STRING;
7020 hay = valuePop(ctxt);
7021 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7022 xmlXPathFreeObject(hay);
7023 xmlXPathFreeObject(needle);
7024 XP_ERROR(XPATH_INVALID_TYPE);
7025 }
7026 n = xmlStrlen(needle->stringval);
7027 if (xmlStrncmp(hay->stringval, needle->stringval, n))
7028 valuePush(ctxt, xmlXPathNewBoolean(0));
7029 else
7030 valuePush(ctxt, xmlXPathNewBoolean(1));
7031 xmlXPathFreeObject(hay);
7032 xmlXPathFreeObject(needle);
7033}
7034
7035/**
7036 * xmlXPathSubstringFunction:
7037 * @ctxt: the XPath Parser context
7038 * @nargs: the number of arguments
7039 *
7040 * Implement the substring() XPath function
7041 * string substring(string, number, number?)
7042 * The substring function returns the substring of the first argument
7043 * starting at the position specified in the second argument with
7044 * length specified in the third argument. For example,
7045 * substring("12345",2,3) returns "234". If the third argument is not
7046 * specified, it returns the substring starting at the position specified
7047 * in the second argument and continuing to the end of the string. For
7048 * example, substring("12345",2) returns "2345". More precisely, each
7049 * character in the string (see [3.6 Strings]) is considered to have a
7050 * numeric position: the position of the first character is 1, the position
7051 * of the second character is 2 and so on. The returned substring contains
7052 * those characters for which the position of the character is greater than
7053 * or equal to the second argument and, if the third argument is specified,
7054 * less than the sum of the second and third arguments; the comparisons
7055 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7056 * - substring("12345", 1.5, 2.6) returns "234"
7057 * - substring("12345", 0, 3) returns "12"
7058 * - substring("12345", 0 div 0, 3) returns ""
7059 * - substring("12345", 1, 0 div 0) returns ""
7060 * - substring("12345", -42, 1 div 0) returns "12345"
7061 * - substring("12345", -1 div 0, 1 div 0) returns ""
7062 */
7063void
7064xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7065 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007066 double le=0, in;
7067 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00007068 xmlChar *ret;
7069
Owen Taylor3473f882001-02-23 17:55:21 +00007070 if (nargs < 2) {
7071 CHECK_ARITY(2);
7072 }
7073 if (nargs > 3) {
7074 CHECK_ARITY(3);
7075 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007076 /*
7077 * take care of possible last (position) argument
7078 */
Owen Taylor3473f882001-02-23 17:55:21 +00007079 if (nargs == 3) {
7080 CAST_TO_NUMBER;
7081 CHECK_TYPE(XPATH_NUMBER);
7082 len = valuePop(ctxt);
7083 le = len->floatval;
7084 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00007085 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007086
Owen Taylor3473f882001-02-23 17:55:21 +00007087 CAST_TO_NUMBER;
7088 CHECK_TYPE(XPATH_NUMBER);
7089 start = valuePop(ctxt);
7090 in = start->floatval;
7091 xmlXPathFreeObject(start);
7092 CAST_TO_STRING;
7093 CHECK_TYPE(XPATH_STRING);
7094 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00007095 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00007096
Daniel Veillard97ac1312001-05-30 19:14:17 +00007097 /*
7098 * If last pos not present, calculate last position
7099 */
Daniel Veillard9e412302002-06-10 15:59:44 +00007100 if (nargs != 3) {
7101 le = (double)m;
7102 if (in < 1.0)
7103 in = 1.0;
7104 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007105
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007106 /* Need to check for the special cases where either
7107 * the index is NaN, the length is NaN, or both
7108 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00007109 */
Daniel Veillard9e412302002-06-10 15:59:44 +00007110 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007111 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00007112 * To meet the requirements of the spec, the arguments
7113 * must be converted to integer format before
7114 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007115 *
Daniel Veillard9e412302002-06-10 15:59:44 +00007116 * First we go to integer form, rounding up
7117 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007118 */
7119 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00007120 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00007121
Daniel Veillard9e412302002-06-10 15:59:44 +00007122 if (xmlXPathIsInf(le) == 1) {
7123 l = m;
7124 if (i < 1)
7125 i = 1;
7126 }
7127 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
7128 l = 0;
7129 else {
7130 l = (int) le;
7131 if (((double)l)+0.5 <= le) l++;
7132 }
7133
7134 /* Now we normalize inidices */
7135 i -= 1;
7136 l += i;
7137 if (i < 0)
7138 i = 0;
7139 if (l > m)
7140 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00007141
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007142 /* number of chars to copy */
7143 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00007144
Daniel Veillard0eafdef2002-04-10 16:14:34 +00007145 ret = xmlUTF8Strsub(str->stringval, i, l);
7146 }
7147 else {
7148 ret = NULL;
7149 }
7150
Owen Taylor3473f882001-02-23 17:55:21 +00007151 if (ret == NULL)
7152 valuePush(ctxt, xmlXPathNewCString(""));
7153 else {
7154 valuePush(ctxt, xmlXPathNewString(ret));
7155 xmlFree(ret);
7156 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00007157
Owen Taylor3473f882001-02-23 17:55:21 +00007158 xmlXPathFreeObject(str);
7159}
7160
7161/**
7162 * xmlXPathSubstringBeforeFunction:
7163 * @ctxt: the XPath Parser context
7164 * @nargs: the number of arguments
7165 *
7166 * Implement the substring-before() XPath function
7167 * string substring-before(string, string)
7168 * The substring-before function returns the substring of the first
7169 * argument string that precedes the first occurrence of the second
7170 * argument string in the first argument string, or the empty string
7171 * if the first argument string does not contain the second argument
7172 * string. For example, substring-before("1999/04/01","/") returns 1999.
7173 */
7174void
7175xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7176 xmlXPathObjectPtr str;
7177 xmlXPathObjectPtr find;
7178 xmlBufferPtr target;
7179 const xmlChar *point;
7180 int offset;
7181
7182 CHECK_ARITY(2);
7183 CAST_TO_STRING;
7184 find = valuePop(ctxt);
7185 CAST_TO_STRING;
7186 str = valuePop(ctxt);
7187
7188 target = xmlBufferCreate();
7189 if (target) {
7190 point = xmlStrstr(str->stringval, find->stringval);
7191 if (point) {
7192 offset = (int)(point - str->stringval);
7193 xmlBufferAdd(target, str->stringval, offset);
7194 }
7195 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7196 xmlBufferFree(target);
7197 }
7198
7199 xmlXPathFreeObject(str);
7200 xmlXPathFreeObject(find);
7201}
7202
7203/**
7204 * xmlXPathSubstringAfterFunction:
7205 * @ctxt: the XPath Parser context
7206 * @nargs: the number of arguments
7207 *
7208 * Implement the substring-after() XPath function
7209 * string substring-after(string, string)
7210 * The substring-after function returns the substring of the first
7211 * argument string that follows the first occurrence of the second
7212 * argument string in the first argument string, or the empty stringi
7213 * if the first argument string does not contain the second argument
7214 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7215 * and substring-after("1999/04/01","19") returns 99/04/01.
7216 */
7217void
7218xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7219 xmlXPathObjectPtr str;
7220 xmlXPathObjectPtr find;
7221 xmlBufferPtr target;
7222 const xmlChar *point;
7223 int offset;
7224
7225 CHECK_ARITY(2);
7226 CAST_TO_STRING;
7227 find = valuePop(ctxt);
7228 CAST_TO_STRING;
7229 str = valuePop(ctxt);
7230
7231 target = xmlBufferCreate();
7232 if (target) {
7233 point = xmlStrstr(str->stringval, find->stringval);
7234 if (point) {
7235 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
7236 xmlBufferAdd(target, &str->stringval[offset],
7237 xmlStrlen(str->stringval) - offset);
7238 }
7239 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7240 xmlBufferFree(target);
7241 }
7242
7243 xmlXPathFreeObject(str);
7244 xmlXPathFreeObject(find);
7245}
7246
7247/**
7248 * xmlXPathNormalizeFunction:
7249 * @ctxt: the XPath Parser context
7250 * @nargs: the number of arguments
7251 *
7252 * Implement the normalize-space() XPath function
7253 * string normalize-space(string?)
7254 * The normalize-space function returns the argument string with white
7255 * space normalized by stripping leading and trailing whitespace
7256 * and replacing sequences of whitespace characters by a single
7257 * space. Whitespace characters are the same allowed by the S production
7258 * in XML. If the argument is omitted, it defaults to the context
7259 * node converted to a string, in other words the value of the context node.
7260 */
7261void
7262xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7263 xmlXPathObjectPtr obj = NULL;
7264 xmlChar *source = NULL;
7265 xmlBufferPtr target;
7266 xmlChar blank;
7267
Daniel Veillarda82b1822004-11-08 16:24:57 +00007268 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007269 if (nargs == 0) {
7270 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007271 valuePush(ctxt,
7272 xmlXPathWrapString(
7273 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00007274 nargs = 1;
7275 }
7276
7277 CHECK_ARITY(1);
7278 CAST_TO_STRING;
7279 CHECK_TYPE(XPATH_STRING);
7280 obj = valuePop(ctxt);
7281 source = obj->stringval;
7282
7283 target = xmlBufferCreate();
7284 if (target && source) {
7285
7286 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00007287 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00007288 source++;
7289
7290 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7291 blank = 0;
7292 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00007293 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00007294 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00007295 } else {
7296 if (blank) {
7297 xmlBufferAdd(target, &blank, 1);
7298 blank = 0;
7299 }
7300 xmlBufferAdd(target, source, 1);
7301 }
7302 source++;
7303 }
7304
7305 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7306 xmlBufferFree(target);
7307 }
7308 xmlXPathFreeObject(obj);
7309}
7310
7311/**
7312 * xmlXPathTranslateFunction:
7313 * @ctxt: the XPath Parser context
7314 * @nargs: the number of arguments
7315 *
7316 * Implement the translate() XPath function
7317 * string translate(string, string, string)
7318 * The translate function returns the first argument string with
7319 * occurrences of characters in the second argument string replaced
7320 * by the character at the corresponding position in the third argument
7321 * string. For example, translate("bar","abc","ABC") returns the string
7322 * BAr. If there is a character in the second argument string with no
7323 * character at a corresponding position in the third argument string
7324 * (because the second argument string is longer than the third argument
7325 * string), then occurrences of that character in the first argument
7326 * string are removed. For example, translate("--aaa--","abc-","ABC")
7327 * returns "AAA". If a character occurs more than once in second
7328 * argument string, then the first occurrence determines the replacement
7329 * character. If the third argument string is longer than the second
7330 * argument string, then excess characters are ignored.
7331 */
7332void
7333xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00007334 xmlXPathObjectPtr str;
7335 xmlXPathObjectPtr from;
7336 xmlXPathObjectPtr to;
7337 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007338 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007339 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00007340 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00007341 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00007342
Daniel Veillarde043ee12001-04-16 14:08:07 +00007343 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00007344
Daniel Veillarde043ee12001-04-16 14:08:07 +00007345 CAST_TO_STRING;
7346 to = valuePop(ctxt);
7347 CAST_TO_STRING;
7348 from = valuePop(ctxt);
7349 CAST_TO_STRING;
7350 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007351
Daniel Veillarde043ee12001-04-16 14:08:07 +00007352 target = xmlBufferCreate();
7353 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00007354 max = xmlUTF8Strlen(to->stringval);
7355 for (cptr = str->stringval; (ch=*cptr); ) {
7356 offset = xmlUTF8Strloc(from->stringval, cptr);
7357 if (offset >= 0) {
7358 if (offset < max) {
7359 point = xmlUTF8Strpos(to->stringval, offset);
7360 if (point)
7361 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
7362 }
7363 } else
7364 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7365
7366 /* Step to next character in input */
7367 cptr++;
7368 if ( ch & 0x80 ) {
7369 /* if not simple ascii, verify proper format */
7370 if ( (ch & 0xc0) != 0xc0 ) {
7371 xmlGenericError(xmlGenericErrorContext,
7372 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7373 break;
7374 }
7375 /* then skip over remaining bytes for this char */
7376 while ( (ch <<= 1) & 0x80 )
7377 if ( (*cptr++ & 0xc0) != 0x80 ) {
7378 xmlGenericError(xmlGenericErrorContext,
7379 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7380 break;
7381 }
7382 if (ch & 0x80) /* must have had error encountered */
7383 break;
7384 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007385 }
Owen Taylor3473f882001-02-23 17:55:21 +00007386 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007387 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7388 xmlBufferFree(target);
7389 xmlXPathFreeObject(str);
7390 xmlXPathFreeObject(from);
7391 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007392}
7393
7394/**
7395 * xmlXPathBooleanFunction:
7396 * @ctxt: the XPath Parser context
7397 * @nargs: the number of arguments
7398 *
7399 * Implement the boolean() XPath function
7400 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007401 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007402 * - a number is true if and only if it is neither positive or
7403 * negative zero nor NaN
7404 * - a node-set is true if and only if it is non-empty
7405 * - a string is true if and only if its length is non-zero
7406 */
7407void
7408xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7409 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007410
7411 CHECK_ARITY(1);
7412 cur = valuePop(ctxt);
7413 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007414 cur = xmlXPathConvertBoolean(cur);
7415 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007416}
7417
7418/**
7419 * xmlXPathNotFunction:
7420 * @ctxt: the XPath Parser context
7421 * @nargs: the number of arguments
7422 *
7423 * Implement the not() XPath function
7424 * boolean not(boolean)
7425 * The not function returns true if its argument is false,
7426 * and false otherwise.
7427 */
7428void
7429xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7430 CHECK_ARITY(1);
7431 CAST_TO_BOOLEAN;
7432 CHECK_TYPE(XPATH_BOOLEAN);
7433 ctxt->value->boolval = ! ctxt->value->boolval;
7434}
7435
7436/**
7437 * xmlXPathTrueFunction:
7438 * @ctxt: the XPath Parser context
7439 * @nargs: the number of arguments
7440 *
7441 * Implement the true() XPath function
7442 * boolean true()
7443 */
7444void
7445xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7446 CHECK_ARITY(0);
7447 valuePush(ctxt, xmlXPathNewBoolean(1));
7448}
7449
7450/**
7451 * xmlXPathFalseFunction:
7452 * @ctxt: the XPath Parser context
7453 * @nargs: the number of arguments
7454 *
7455 * Implement the false() XPath function
7456 * boolean false()
7457 */
7458void
7459xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7460 CHECK_ARITY(0);
7461 valuePush(ctxt, xmlXPathNewBoolean(0));
7462}
7463
7464/**
7465 * xmlXPathLangFunction:
7466 * @ctxt: the XPath Parser context
7467 * @nargs: the number of arguments
7468 *
7469 * Implement the lang() XPath function
7470 * boolean lang(string)
7471 * The lang function returns true or false depending on whether the
7472 * language of the context node as specified by xml:lang attributes
7473 * is the same as or is a sublanguage of the language specified by
7474 * the argument string. The language of the context node is determined
7475 * by the value of the xml:lang attribute on the context node, or, if
7476 * the context node has no xml:lang attribute, by the value of the
7477 * xml:lang attribute on the nearest ancestor of the context node that
7478 * has an xml:lang attribute. If there is no such attribute, then lang
7479 * returns false. If there is such an attribute, then lang returns
7480 * true if the attribute value is equal to the argument ignoring case,
7481 * or if there is some suffix starting with - such that the attribute
7482 * value is equal to the argument ignoring that suffix of the attribute
7483 * value and ignoring case.
7484 */
7485void
7486xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007487 xmlXPathObjectPtr val = NULL;
7488 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007489 const xmlChar *lang;
7490 int ret = 0;
7491 int i;
7492
7493 CHECK_ARITY(1);
7494 CAST_TO_STRING;
7495 CHECK_TYPE(XPATH_STRING);
7496 val = valuePop(ctxt);
7497 lang = val->stringval;
7498 theLang = xmlNodeGetLang(ctxt->context->node);
7499 if ((theLang != NULL) && (lang != NULL)) {
7500 for (i = 0;lang[i] != 0;i++)
7501 if (toupper(lang[i]) != toupper(theLang[i]))
7502 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007503 if ((theLang[i] == 0) || (theLang[i] == '-'))
7504 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007505 }
7506not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007507 if (theLang != NULL)
7508 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007509 xmlXPathFreeObject(val);
7510 valuePush(ctxt, xmlXPathNewBoolean(ret));
7511}
7512
7513/**
7514 * xmlXPathNumberFunction:
7515 * @ctxt: the XPath Parser context
7516 * @nargs: the number of arguments
7517 *
7518 * Implement the number() XPath function
7519 * number number(object?)
7520 */
7521void
7522xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7523 xmlXPathObjectPtr cur;
7524 double res;
7525
Daniel Veillarda82b1822004-11-08 16:24:57 +00007526 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007527 if (nargs == 0) {
7528 if (ctxt->context->node == NULL) {
7529 valuePush(ctxt, xmlXPathNewFloat(0.0));
7530 } else {
7531 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7532
7533 res = xmlXPathStringEvalNumber(content);
7534 valuePush(ctxt, xmlXPathNewFloat(res));
7535 xmlFree(content);
7536 }
7537 return;
7538 }
7539
7540 CHECK_ARITY(1);
7541 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007542 cur = xmlXPathConvertNumber(cur);
7543 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007544}
7545
7546/**
7547 * xmlXPathSumFunction:
7548 * @ctxt: the XPath Parser context
7549 * @nargs: the number of arguments
7550 *
7551 * Implement the sum() XPath function
7552 * number sum(node-set)
7553 * The sum function returns the sum of the values of the nodes in
7554 * the argument node-set.
7555 */
7556void
7557xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7558 xmlXPathObjectPtr cur;
7559 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007560 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007561
7562 CHECK_ARITY(1);
7563 if ((ctxt->value == NULL) ||
7564 ((ctxt->value->type != XPATH_NODESET) &&
7565 (ctxt->value->type != XPATH_XSLT_TREE)))
7566 XP_ERROR(XPATH_INVALID_TYPE);
7567 cur = valuePop(ctxt);
7568
William M. Brack08171912003-12-29 02:52:11 +00007569 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007570 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7571 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007572 }
7573 }
William M. Brack08171912003-12-29 02:52:11 +00007574 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007575 xmlXPathFreeObject(cur);
7576}
7577
William M. Brack3d426662005-04-19 14:40:28 +00007578/*
7579 * To assure working code on multiple platforms, we want to only depend
7580 * upon the characteristic truncation of converting a floating point value
7581 * to an integer. Unfortunately, because of the different storage sizes
7582 * of our internal floating point value (double) and integer (int), we
7583 * can't directly convert (see bug 301162). This macro is a messy
7584 * 'workaround'
7585 */
7586#define XTRUNC(f, v) \
7587 f = fmod((v), INT_MAX); \
7588 f = (v) - (f) + (double)((int)(f));
7589
Owen Taylor3473f882001-02-23 17:55:21 +00007590/**
7591 * xmlXPathFloorFunction:
7592 * @ctxt: the XPath Parser context
7593 * @nargs: the number of arguments
7594 *
7595 * Implement the floor() XPath function
7596 * number floor(number)
7597 * The floor function returns the largest (closest to positive infinity)
7598 * number that is not greater than the argument and that is an integer.
7599 */
7600void
7601xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007602 double f;
7603
Owen Taylor3473f882001-02-23 17:55:21 +00007604 CHECK_ARITY(1);
7605 CAST_TO_NUMBER;
7606 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007607
William M. Brack3d426662005-04-19 14:40:28 +00007608 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007609 if (f != ctxt->value->floatval) {
7610 if (ctxt->value->floatval > 0)
7611 ctxt->value->floatval = f;
7612 else
7613 ctxt->value->floatval = f - 1;
7614 }
Owen Taylor3473f882001-02-23 17:55:21 +00007615}
7616
7617/**
7618 * xmlXPathCeilingFunction:
7619 * @ctxt: the XPath Parser context
7620 * @nargs: the number of arguments
7621 *
7622 * Implement the ceiling() XPath function
7623 * number ceiling(number)
7624 * The ceiling function returns the smallest (closest to negative infinity)
7625 * number that is not less than the argument and that is an integer.
7626 */
7627void
7628xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7629 double f;
7630
7631 CHECK_ARITY(1);
7632 CAST_TO_NUMBER;
7633 CHECK_TYPE(XPATH_NUMBER);
7634
7635#if 0
7636 ctxt->value->floatval = ceil(ctxt->value->floatval);
7637#else
William M. Brack3d426662005-04-19 14:40:28 +00007638 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007639 if (f != ctxt->value->floatval) {
7640 if (ctxt->value->floatval > 0)
7641 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007642 else {
7643 if (ctxt->value->floatval < 0 && f == 0)
7644 ctxt->value->floatval = xmlXPathNZERO;
7645 else
7646 ctxt->value->floatval = f;
7647 }
7648
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007649 }
Owen Taylor3473f882001-02-23 17:55:21 +00007650#endif
7651}
7652
7653/**
7654 * xmlXPathRoundFunction:
7655 * @ctxt: the XPath Parser context
7656 * @nargs: the number of arguments
7657 *
7658 * Implement the round() XPath function
7659 * number round(number)
7660 * The round function returns the number that is closest to the
7661 * argument and that is an integer. If there are two such numbers,
7662 * then the one that is even is returned.
7663 */
7664void
7665xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7666 double f;
7667
7668 CHECK_ARITY(1);
7669 CAST_TO_NUMBER;
7670 CHECK_TYPE(XPATH_NUMBER);
7671
Daniel Veillardcda96922001-08-21 10:56:31 +00007672 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7673 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7674 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007675 (ctxt->value->floatval == 0.0))
7676 return;
7677
William M. Brack3d426662005-04-19 14:40:28 +00007678 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007679 if (ctxt->value->floatval < 0) {
7680 if (ctxt->value->floatval < f - 0.5)
7681 ctxt->value->floatval = f - 1;
7682 else
7683 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007684 if (ctxt->value->floatval == 0)
7685 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007686 } else {
7687 if (ctxt->value->floatval < f + 0.5)
7688 ctxt->value->floatval = f;
7689 else
7690 ctxt->value->floatval = f + 1;
7691 }
Owen Taylor3473f882001-02-23 17:55:21 +00007692}
7693
7694/************************************************************************
7695 * *
7696 * The Parser *
7697 * *
7698 ************************************************************************/
7699
7700/*
William M. Brack08171912003-12-29 02:52:11 +00007701 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007702 * implementation.
7703 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00007704static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007705static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007706static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007707static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007708static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7709 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007710
7711/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007712 * xmlXPathCurrentChar:
7713 * @ctxt: the XPath parser context
7714 * @cur: pointer to the beginning of the char
7715 * @len: pointer to the length of the char read
7716 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007717 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007718 * bytes in the input buffer.
7719 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007720 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007721 */
7722
7723static int
7724xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7725 unsigned char c;
7726 unsigned int val;
7727 const xmlChar *cur;
7728
7729 if (ctxt == NULL)
7730 return(0);
7731 cur = ctxt->cur;
7732
7733 /*
7734 * We are supposed to handle UTF8, check it's valid
7735 * From rfc2044: encoding of the Unicode values on UTF-8:
7736 *
7737 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7738 * 0000 0000-0000 007F 0xxxxxxx
7739 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7740 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7741 *
7742 * Check for the 0x110000 limit too
7743 */
7744 c = *cur;
7745 if (c & 0x80) {
7746 if ((cur[1] & 0xc0) != 0x80)
7747 goto encoding_error;
7748 if ((c & 0xe0) == 0xe0) {
7749
7750 if ((cur[2] & 0xc0) != 0x80)
7751 goto encoding_error;
7752 if ((c & 0xf0) == 0xf0) {
7753 if (((c & 0xf8) != 0xf0) ||
7754 ((cur[3] & 0xc0) != 0x80))
7755 goto encoding_error;
7756 /* 4-byte code */
7757 *len = 4;
7758 val = (cur[0] & 0x7) << 18;
7759 val |= (cur[1] & 0x3f) << 12;
7760 val |= (cur[2] & 0x3f) << 6;
7761 val |= cur[3] & 0x3f;
7762 } else {
7763 /* 3-byte code */
7764 *len = 3;
7765 val = (cur[0] & 0xf) << 12;
7766 val |= (cur[1] & 0x3f) << 6;
7767 val |= cur[2] & 0x3f;
7768 }
7769 } else {
7770 /* 2-byte code */
7771 *len = 2;
7772 val = (cur[0] & 0x1f) << 6;
7773 val |= cur[1] & 0x3f;
7774 }
7775 if (!IS_CHAR(val)) {
7776 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7777 }
7778 return(val);
7779 } else {
7780 /* 1-byte code */
7781 *len = 1;
7782 return((int) *cur);
7783 }
7784encoding_error:
7785 /*
William M. Brack08171912003-12-29 02:52:11 +00007786 * If we detect an UTF8 error that probably means that the
7787 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007788 * declaration header. Report the error and switch the encoding
7789 * to ISO-Latin-1 (if you don't like this policy, just declare the
7790 * encoding !)
7791 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007792 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007793 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007794}
7795
7796/**
Owen Taylor3473f882001-02-23 17:55:21 +00007797 * xmlXPathParseNCName:
7798 * @ctxt: the XPath Parser context
7799 *
7800 * parse an XML namespace non qualified name.
7801 *
7802 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7803 *
7804 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7805 * CombiningChar | Extender
7806 *
7807 * Returns the namespace name or NULL
7808 */
7809
7810xmlChar *
7811xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007812 const xmlChar *in;
7813 xmlChar *ret;
7814 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007815
Daniel Veillarda82b1822004-11-08 16:24:57 +00007816 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007817 /*
7818 * Accelerator for simple ASCII names
7819 */
7820 in = ctxt->cur;
7821 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7822 ((*in >= 0x41) && (*in <= 0x5A)) ||
7823 (*in == '_')) {
7824 in++;
7825 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7826 ((*in >= 0x41) && (*in <= 0x5A)) ||
7827 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007828 (*in == '_') || (*in == '.') ||
7829 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007830 in++;
7831 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7832 (*in == '[') || (*in == ']') || (*in == ':') ||
7833 (*in == '@') || (*in == '*')) {
7834 count = in - ctxt->cur;
7835 if (count == 0)
7836 return(NULL);
7837 ret = xmlStrndup(ctxt->cur, count);
7838 ctxt->cur = in;
7839 return(ret);
7840 }
7841 }
7842 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007843}
7844
Daniel Veillard2156a562001-04-28 12:24:34 +00007845
Owen Taylor3473f882001-02-23 17:55:21 +00007846/**
7847 * xmlXPathParseQName:
7848 * @ctxt: the XPath Parser context
7849 * @prefix: a xmlChar **
7850 *
7851 * parse an XML qualified name
7852 *
7853 * [NS 5] QName ::= (Prefix ':')? LocalPart
7854 *
7855 * [NS 6] Prefix ::= NCName
7856 *
7857 * [NS 7] LocalPart ::= NCName
7858 *
7859 * Returns the function returns the local part, and prefix is updated
7860 * to get the Prefix if any.
7861 */
7862
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007863static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007864xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7865 xmlChar *ret = NULL;
7866
7867 *prefix = NULL;
7868 ret = xmlXPathParseNCName(ctxt);
7869 if (CUR == ':') {
7870 *prefix = ret;
7871 NEXT;
7872 ret = xmlXPathParseNCName(ctxt);
7873 }
7874 return(ret);
7875}
7876
7877/**
7878 * xmlXPathParseName:
7879 * @ctxt: the XPath Parser context
7880 *
7881 * parse an XML name
7882 *
7883 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7884 * CombiningChar | Extender
7885 *
7886 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7887 *
7888 * Returns the namespace name or NULL
7889 */
7890
7891xmlChar *
7892xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007893 const xmlChar *in;
7894 xmlChar *ret;
7895 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007896
Daniel Veillarda82b1822004-11-08 16:24:57 +00007897 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007898 /*
7899 * Accelerator for simple ASCII names
7900 */
7901 in = ctxt->cur;
7902 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7903 ((*in >= 0x41) && (*in <= 0x5A)) ||
7904 (*in == '_') || (*in == ':')) {
7905 in++;
7906 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7907 ((*in >= 0x41) && (*in <= 0x5A)) ||
7908 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007909 (*in == '_') || (*in == '-') ||
7910 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007911 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007912 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007913 count = in - ctxt->cur;
7914 ret = xmlStrndup(ctxt->cur, count);
7915 ctxt->cur = in;
7916 return(ret);
7917 }
7918 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007919 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007920}
7921
Daniel Veillard61d80a22001-04-27 17:13:01 +00007922static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007923xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007924 xmlChar buf[XML_MAX_NAMELEN + 5];
7925 int len = 0, l;
7926 int c;
7927
7928 /*
7929 * Handler for more complex cases
7930 */
7931 c = CUR_CHAR(l);
7932 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007933 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7934 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007935 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007936 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007937 return(NULL);
7938 }
7939
7940 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7941 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7942 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007943 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007944 (IS_COMBINING(c)) ||
7945 (IS_EXTENDER(c)))) {
7946 COPY_BUF(l,buf,len,c);
7947 NEXTL(l);
7948 c = CUR_CHAR(l);
7949 if (len >= XML_MAX_NAMELEN) {
7950 /*
7951 * Okay someone managed to make a huge name, so he's ready to pay
7952 * for the processing speed.
7953 */
7954 xmlChar *buffer;
7955 int max = len * 2;
7956
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007957 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007958 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007959 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007960 }
7961 memcpy(buffer, buf, len);
7962 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7963 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007964 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007965 (IS_COMBINING(c)) ||
7966 (IS_EXTENDER(c))) {
7967 if (len + 10 > max) {
7968 max *= 2;
7969 buffer = (xmlChar *) xmlRealloc(buffer,
7970 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007971 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007972 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007973 }
7974 }
7975 COPY_BUF(l,buffer,len,c);
7976 NEXTL(l);
7977 c = CUR_CHAR(l);
7978 }
7979 buffer[len] = 0;
7980 return(buffer);
7981 }
7982 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007983 if (len == 0)
7984 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007985 return(xmlStrndup(buf, len));
7986}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007987
7988#define MAX_FRAC 20
7989
William M. Brack372a4452004-02-17 13:09:23 +00007990/*
7991 * These are used as divisors for the fractional part of a number.
7992 * Since the table includes 1.0 (representing '0' fractional digits),
7993 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7994 */
7995static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007996 1.0, 10.0, 100.0, 1000.0, 10000.0,
7997 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7998 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7999 100000000000000.0,
8000 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00008001 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00008002};
8003
Owen Taylor3473f882001-02-23 17:55:21 +00008004/**
8005 * xmlXPathStringEvalNumber:
8006 * @str: A string to scan
8007 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00008008 * [30a] Float ::= Number ('e' Digits?)?
8009 *
Owen Taylor3473f882001-02-23 17:55:21 +00008010 * [30] Number ::= Digits ('.' Digits?)?
8011 * | '.' Digits
8012 * [31] Digits ::= [0-9]+
8013 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008014 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00008015 * In complement of the Number expression, this function also handles
8016 * negative values : '-' Number.
8017 *
8018 * Returns the double value.
8019 */
8020double
8021xmlXPathStringEvalNumber(const xmlChar *str) {
8022 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00008023 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008024 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008025 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008026 int exponent = 0;
8027 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008028#ifdef __GNUC__
8029 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00008030 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008031#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00008032 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00008033 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008034 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
8035 return(xmlXPathNAN);
8036 }
8037 if (*cur == '-') {
8038 isneg = 1;
8039 cur++;
8040 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00008041
8042#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008043 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00008044 * tmp/temp is a workaround against a gcc compiler bug
8045 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008046 */
Daniel Veillard7b416132002-03-07 08:36:03 +00008047 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008048 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00008049 ret = ret * 10;
8050 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00008051 ok = 1;
8052 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00008053 temp = (double) tmp;
8054 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00008055 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00008056#else
Daniel Veillard7b416132002-03-07 08:36:03 +00008057 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00008058 while ((*cur >= '0') && (*cur <= '9')) {
8059 ret = ret * 10 + (*cur - '0');
8060 ok = 1;
8061 cur++;
8062 }
8063#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008064
Owen Taylor3473f882001-02-23 17:55:21 +00008065 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00008066 int v, frac = 0;
8067 double fraction = 0;
8068
Owen Taylor3473f882001-02-23 17:55:21 +00008069 cur++;
8070 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8071 return(xmlXPathNAN);
8072 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00008073 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
8074 v = (*cur - '0');
8075 fraction = fraction * 10 + v;
8076 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008077 cur++;
8078 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00008079 fraction /= my_pow10[frac];
8080 ret = ret + fraction;
8081 while ((*cur >= '0') && (*cur <= '9'))
8082 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008083 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00008084 if ((*cur == 'e') || (*cur == 'E')) {
8085 cur++;
8086 if (*cur == '-') {
8087 is_exponent_negative = 1;
8088 cur++;
William M. Brack99127052004-05-24 02:52:28 +00008089 } else if (*cur == '+') {
8090 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008091 }
8092 while ((*cur >= '0') && (*cur <= '9')) {
8093 exponent = exponent * 10 + (*cur - '0');
8094 cur++;
8095 }
8096 }
William M. Brack76e95df2003-10-18 16:20:14 +00008097 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00008098 if (*cur != 0) return(xmlXPathNAN);
8099 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008100 if (is_exponent_negative) exponent = -exponent;
8101 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00008102 return(ret);
8103}
8104
8105/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008106 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00008107 * @ctxt: the XPath Parser context
8108 *
8109 * [30] Number ::= Digits ('.' Digits?)?
8110 * | '.' Digits
8111 * [31] Digits ::= [0-9]+
8112 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008113 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00008114 *
8115 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008116static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008117xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8118{
Owen Taylor3473f882001-02-23 17:55:21 +00008119 double ret = 0.0;
8120 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00008121 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00008122 int exponent = 0;
8123 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00008124#ifdef __GNUC__
8125 unsigned long tmp = 0;
8126 double temp;
8127#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008128
8129 CHECK_ERROR;
8130 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8131 XP_ERROR(XPATH_NUMBER_ERROR);
8132 }
Daniel Veillard7b416132002-03-07 08:36:03 +00008133#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008134 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00008135 * tmp/temp is a workaround against a gcc compiler bug
8136 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008137 */
Daniel Veillard7b416132002-03-07 08:36:03 +00008138 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008139 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00008140 ret = ret * 10;
8141 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008142 ok = 1;
8143 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00008144 temp = (double) tmp;
8145 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00008146 }
Daniel Veillard7b416132002-03-07 08:36:03 +00008147#else
8148 ret = 0;
8149 while ((CUR >= '0') && (CUR <= '9')) {
8150 ret = ret * 10 + (CUR - '0');
8151 ok = 1;
8152 NEXT;
8153 }
8154#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008155 if (CUR == '.') {
8156 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008157 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8158 XP_ERROR(XPATH_NUMBER_ERROR);
8159 }
8160 while ((CUR >= '0') && (CUR <= '9')) {
8161 mult /= 10;
8162 ret = ret + (CUR - '0') * mult;
8163 NEXT;
8164 }
Owen Taylor3473f882001-02-23 17:55:21 +00008165 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00008166 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008167 NEXT;
8168 if (CUR == '-') {
8169 is_exponent_negative = 1;
8170 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00008171 } else if (CUR == '+') {
8172 NEXT;
8173 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008174 while ((CUR >= '0') && (CUR <= '9')) {
8175 exponent = exponent * 10 + (CUR - '0');
8176 NEXT;
8177 }
8178 if (is_exponent_negative)
8179 exponent = -exponent;
8180 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00008181 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008182 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00008183 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008184}
8185
8186/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008187 * xmlXPathParseLiteral:
8188 * @ctxt: the XPath Parser context
8189 *
8190 * Parse a Literal
8191 *
8192 * [29] Literal ::= '"' [^"]* '"'
8193 * | "'" [^']* "'"
8194 *
8195 * Returns the value found or NULL in case of error
8196 */
8197static xmlChar *
8198xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8199 const xmlChar *q;
8200 xmlChar *ret = NULL;
8201
8202 if (CUR == '"') {
8203 NEXT;
8204 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008205 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008206 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008207 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008208 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008209 } else {
8210 ret = xmlStrndup(q, CUR_PTR - q);
8211 NEXT;
8212 }
8213 } else 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 {
Daniel Veillard24505b02005-07-28 23:49:35 +00008225 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008226 }
8227 return(ret);
8228}
8229
8230/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008231 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00008232 * @ctxt: the XPath Parser context
8233 *
8234 * Parse a Literal and push it on the stack.
8235 *
8236 * [29] Literal ::= '"' [^"]* '"'
8237 * | "'" [^']* "'"
8238 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008239 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00008240 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008241static void
8242xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008243 const xmlChar *q;
8244 xmlChar *ret = NULL;
8245
8246 if (CUR == '"') {
8247 NEXT;
8248 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00008249 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00008250 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00008251 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00008252 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
8253 } else {
8254 ret = xmlStrndup(q, CUR_PTR - q);
8255 NEXT;
8256 }
8257 } else 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 {
8269 XP_ERROR(XPATH_START_LITERAL_ERROR);
8270 }
8271 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008272 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
8273 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008274 xmlFree(ret);
8275}
8276
8277/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00008279 * @ctxt: the XPath Parser context
8280 *
8281 * Parse a VariableReference, evaluate it and push it on the stack.
8282 *
8283 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00008284 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00008285 * of any of the types that are possible for the value of an expression,
8286 * and may also be of additional types not specified here.
8287 *
8288 * Early evaluation is possible since:
8289 * The variable bindings [...] used to evaluate a subexpression are
8290 * always the same as those used to evaluate the containing expression.
8291 *
8292 * [36] VariableReference ::= '$' QName
8293 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294static void
8295xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008296 xmlChar *name;
8297 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00008298
8299 SKIP_BLANKS;
8300 if (CUR != '$') {
8301 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8302 }
8303 NEXT;
8304 name = xmlXPathParseQName(ctxt, &prefix);
8305 if (name == NULL) {
8306 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8307 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008308 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008309 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
8310 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008311 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00008312 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8313 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
8314 }
Owen Taylor3473f882001-02-23 17:55:21 +00008315}
8316
8317/**
8318 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00008319 * @name: a name string
8320 *
8321 * Is the name given a NodeType one.
8322 *
8323 * [38] NodeType ::= 'comment'
8324 * | 'text'
8325 * | 'processing-instruction'
8326 * | 'node'
8327 *
8328 * Returns 1 if true 0 otherwise
8329 */
8330int
8331xmlXPathIsNodeType(const xmlChar *name) {
8332 if (name == NULL)
8333 return(0);
8334
Daniel Veillard1971ee22002-01-31 20:29:19 +00008335 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00008336 return(1);
8337 if (xmlStrEqual(name, BAD_CAST "text"))
8338 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00008339 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00008340 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00008341 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00008342 return(1);
8343 return(0);
8344}
8345
8346/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008347 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00008348 * @ctxt: the XPath Parser context
8349 *
8350 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8351 * [17] Argument ::= Expr
8352 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008353 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00008354 * pushed on the stack
8355 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008356static void
8357xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008358 xmlChar *name;
8359 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00008360 int nbargs = 0;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008361 int sort = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008362
8363 name = xmlXPathParseQName(ctxt, &prefix);
8364 if (name == NULL) {
8365 XP_ERROR(XPATH_EXPR_ERROR);
8366 }
8367 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008368#ifdef DEBUG_EXPR
8369 if (prefix == NULL)
8370 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
8371 name);
8372 else
8373 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
8374 prefix, name);
8375#endif
8376
Owen Taylor3473f882001-02-23 17:55:21 +00008377 if (CUR != '(') {
8378 XP_ERROR(XPATH_EXPR_ERROR);
8379 }
8380 NEXT;
8381 SKIP_BLANKS;
8382
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008383 /*
8384 * Optimization for count(): we don't need the node-set to be sorted.
8385 */
8386 if ((prefix == NULL) && (name[0] == 'c') &&
8387 xmlStrEqual(name, BAD_CAST "count"))
8388 {
8389 sort = 0;
8390 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008391 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00008392 if (CUR != ')') {
8393 while (CUR != 0) {
8394 int op1 = ctxt->comp->last;
8395 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008396 xmlXPathCompileExpr(ctxt, sort);
Daniel Veillard71f9d732003-01-14 16:07:16 +00008397 CHECK_ERROR;
8398 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8399 nbargs++;
8400 if (CUR == ')') break;
8401 if (CUR != ',') {
8402 XP_ERROR(XPATH_EXPR_ERROR);
8403 }
8404 NEXT;
8405 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008406 }
Owen Taylor3473f882001-02-23 17:55:21 +00008407 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008408 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8409 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008410 NEXT;
8411 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008412}
8413
8414/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008415 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008416 * @ctxt: the XPath Parser context
8417 *
8418 * [15] PrimaryExpr ::= VariableReference
8419 * | '(' Expr ')'
8420 * | Literal
8421 * | Number
8422 * | FunctionCall
8423 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008424 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008425 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008426static void
8427xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008428 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008429 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008430 else if (CUR == '(') {
8431 NEXT;
8432 SKIP_BLANKS;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008433 xmlXPathCompileExpr(ctxt, 1);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008434 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008435 if (CUR != ')') {
8436 XP_ERROR(XPATH_EXPR_ERROR);
8437 }
8438 NEXT;
8439 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008440 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008441 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008442 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008443 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008444 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008445 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008446 }
8447 SKIP_BLANKS;
8448}
8449
8450/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008451 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008452 * @ctxt: the XPath Parser context
8453 *
8454 * [20] FilterExpr ::= PrimaryExpr
8455 * | FilterExpr Predicate
8456 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008457 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008458 * Square brackets are used to filter expressions in the same way that
8459 * they are used in location paths. It is an error if the expression to
8460 * be filtered does not evaluate to a node-set. The context node list
8461 * used for evaluating the expression in square brackets is the node-set
8462 * to be filtered listed in document order.
8463 */
8464
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008465static void
8466xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8467 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008468 CHECK_ERROR;
8469 SKIP_BLANKS;
8470
8471 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008472 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008473 SKIP_BLANKS;
8474 }
8475
8476
8477}
8478
8479/**
8480 * xmlXPathScanName:
8481 * @ctxt: the XPath Parser context
8482 *
8483 * Trickery: parse an XML name but without consuming the input flow
8484 * Needed to avoid insanity in the parser state.
8485 *
8486 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8487 * CombiningChar | Extender
8488 *
8489 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8490 *
8491 * [6] Names ::= Name (S Name)*
8492 *
8493 * Returns the Name parsed or NULL
8494 */
8495
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008496static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008497xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008498 int len = 0, l;
8499 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008500 const xmlChar *cur;
8501 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008502
Daniel Veillard03226812004-11-01 14:55:21 +00008503 cur = ctxt->cur;
8504
8505 c = CUR_CHAR(l);
8506 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8507 (!IS_LETTER(c) && (c != '_') &&
8508 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008509 return(NULL);
8510 }
8511
Daniel Veillard03226812004-11-01 14:55:21 +00008512 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8513 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8514 (c == '.') || (c == '-') ||
8515 (c == '_') || (c == ':') ||
8516 (IS_COMBINING(c)) ||
8517 (IS_EXTENDER(c)))) {
8518 len += l;
8519 NEXTL(l);
8520 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008521 }
Daniel Veillard03226812004-11-01 14:55:21 +00008522 ret = xmlStrndup(cur, ctxt->cur - cur);
8523 ctxt->cur = cur;
8524 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008525}
8526
8527/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008528 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008529 * @ctxt: the XPath Parser context
8530 *
8531 * [19] PathExpr ::= LocationPath
8532 * | FilterExpr
8533 * | FilterExpr '/' RelativeLocationPath
8534 * | FilterExpr '//' RelativeLocationPath
8535 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008536 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008537 * The / operator and // operators combine an arbitrary expression
8538 * and a relative location path. It is an error if the expression
8539 * does not evaluate to a node-set.
8540 * The / operator does composition in the same way as when / is
8541 * used in a location path. As in location paths, // is short for
8542 * /descendant-or-self::node()/.
8543 */
8544
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008545static void
8546xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008547 int lc = 1; /* Should we branch to LocationPath ? */
8548 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8549
8550 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008551 if ((CUR == '$') || (CUR == '(') ||
8552 (IS_ASCII_DIGIT(CUR)) ||
8553 (CUR == '\'') || (CUR == '"') ||
8554 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008555 lc = 0;
8556 } else if (CUR == '*') {
8557 /* relative or absolute location path */
8558 lc = 1;
8559 } else if (CUR == '/') {
8560 /* relative or absolute location path */
8561 lc = 1;
8562 } else if (CUR == '@') {
8563 /* relative abbreviated attribute location path */
8564 lc = 1;
8565 } else if (CUR == '.') {
8566 /* relative abbreviated attribute location path */
8567 lc = 1;
8568 } else {
8569 /*
8570 * Problem is finding if we have a name here whether it's:
8571 * - a nodetype
8572 * - a function call in which case it's followed by '('
8573 * - an axis in which case it's followed by ':'
8574 * - a element name
8575 * We do an a priori analysis here rather than having to
8576 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008577 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008578 * read/write/debug.
8579 */
8580 SKIP_BLANKS;
8581 name = xmlXPathScanName(ctxt);
8582 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8583#ifdef DEBUG_STEP
8584 xmlGenericError(xmlGenericErrorContext,
8585 "PathExpr: Axis\n");
8586#endif
8587 lc = 1;
8588 xmlFree(name);
8589 } else if (name != NULL) {
8590 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008591
8592
8593 while (NXT(len) != 0) {
8594 if (NXT(len) == '/') {
8595 /* element name */
8596#ifdef DEBUG_STEP
8597 xmlGenericError(xmlGenericErrorContext,
8598 "PathExpr: AbbrRelLocation\n");
8599#endif
8600 lc = 1;
8601 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008602 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008603 /* ignore blanks */
8604 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008605 } else if (NXT(len) == ':') {
8606#ifdef DEBUG_STEP
8607 xmlGenericError(xmlGenericErrorContext,
8608 "PathExpr: AbbrRelLocation\n");
8609#endif
8610 lc = 1;
8611 break;
8612 } else if ((NXT(len) == '(')) {
8613 /* Note Type or Function */
8614 if (xmlXPathIsNodeType(name)) {
8615#ifdef DEBUG_STEP
8616 xmlGenericError(xmlGenericErrorContext,
8617 "PathExpr: Type search\n");
8618#endif
8619 lc = 1;
8620 } else {
8621#ifdef DEBUG_STEP
8622 xmlGenericError(xmlGenericErrorContext,
8623 "PathExpr: function call\n");
8624#endif
8625 lc = 0;
8626 }
8627 break;
8628 } else if ((NXT(len) == '[')) {
8629 /* element name */
8630#ifdef DEBUG_STEP
8631 xmlGenericError(xmlGenericErrorContext,
8632 "PathExpr: AbbrRelLocation\n");
8633#endif
8634 lc = 1;
8635 break;
8636 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8637 (NXT(len) == '=')) {
8638 lc = 1;
8639 break;
8640 } else {
8641 lc = 1;
8642 break;
8643 }
8644 len++;
8645 }
8646 if (NXT(len) == 0) {
8647#ifdef DEBUG_STEP
8648 xmlGenericError(xmlGenericErrorContext,
8649 "PathExpr: AbbrRelLocation\n");
8650#endif
8651 /* element name */
8652 lc = 1;
8653 }
8654 xmlFree(name);
8655 } else {
William M. Brack08171912003-12-29 02:52:11 +00008656 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008657 XP_ERROR(XPATH_EXPR_ERROR);
8658 }
8659 }
8660
8661 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008662 if (CUR == '/') {
8663 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8664 } else {
8665 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008666 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008667 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008668 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008669 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008670 CHECK_ERROR;
8671 if ((CUR == '/') && (NXT(1) == '/')) {
8672 SKIP(2);
8673 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008674
8675 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8676 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8677 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8678
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008679 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008680 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008681 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008682 }
8683 }
8684 SKIP_BLANKS;
8685}
8686
8687/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008688 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008689 * @ctxt: the XPath Parser context
8690 *
8691 * [18] UnionExpr ::= PathExpr
8692 * | UnionExpr '|' PathExpr
8693 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008694 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008695 */
8696
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008697static void
8698xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8699 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008700 CHECK_ERROR;
8701 SKIP_BLANKS;
8702 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008703 int op1 = ctxt->comp->last;
8704 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008705
8706 NEXT;
8707 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008708 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008709
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008710 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8711
Owen Taylor3473f882001-02-23 17:55:21 +00008712 SKIP_BLANKS;
8713 }
Owen Taylor3473f882001-02-23 17:55:21 +00008714}
8715
8716/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008717 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008718 * @ctxt: the XPath Parser context
8719 *
8720 * [27] UnaryExpr ::= UnionExpr
8721 * | '-' UnaryExpr
8722 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008723 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008724 */
8725
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008726static void
8727xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008728 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008729 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008730
8731 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008732 while (CUR == '-') {
8733 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008734 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008735 NEXT;
8736 SKIP_BLANKS;
8737 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008738
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008739 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008740 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008741 if (found) {
8742 if (minus)
8743 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8744 else
8745 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008746 }
8747}
8748
8749/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008750 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008751 * @ctxt: the XPath Parser context
8752 *
8753 * [26] MultiplicativeExpr ::= UnaryExpr
8754 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8755 * | MultiplicativeExpr 'div' UnaryExpr
8756 * | MultiplicativeExpr 'mod' UnaryExpr
8757 * [34] MultiplyOperator ::= '*'
8758 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008759 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008760 */
8761
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008762static void
8763xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8764 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008765 CHECK_ERROR;
8766 SKIP_BLANKS;
8767 while ((CUR == '*') ||
8768 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8769 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8770 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008771 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008772
8773 if (CUR == '*') {
8774 op = 0;
8775 NEXT;
8776 } else if (CUR == 'd') {
8777 op = 1;
8778 SKIP(3);
8779 } else if (CUR == 'm') {
8780 op = 2;
8781 SKIP(3);
8782 }
8783 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008784 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008785 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008786 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008787 SKIP_BLANKS;
8788 }
8789}
8790
8791/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008792 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008793 * @ctxt: the XPath Parser context
8794 *
8795 * [25] AdditiveExpr ::= MultiplicativeExpr
8796 * | AdditiveExpr '+' MultiplicativeExpr
8797 * | AdditiveExpr '-' MultiplicativeExpr
8798 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008799 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008800 */
8801
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008802static void
8803xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008804
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008805 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008806 CHECK_ERROR;
8807 SKIP_BLANKS;
8808 while ((CUR == '+') || (CUR == '-')) {
8809 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008810 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008811
8812 if (CUR == '+') plus = 1;
8813 else plus = 0;
8814 NEXT;
8815 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008816 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008817 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008818 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008819 SKIP_BLANKS;
8820 }
8821}
8822
8823/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008824 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008825 * @ctxt: the XPath Parser context
8826 *
8827 * [24] RelationalExpr ::= AdditiveExpr
8828 * | RelationalExpr '<' AdditiveExpr
8829 * | RelationalExpr '>' AdditiveExpr
8830 * | RelationalExpr '<=' AdditiveExpr
8831 * | RelationalExpr '>=' AdditiveExpr
8832 *
8833 * A <= B > C is allowed ? Answer from James, yes with
8834 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8835 * which is basically what got implemented.
8836 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008837 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008838 * on the stack
8839 */
8840
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008841static void
8842xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8843 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008844 CHECK_ERROR;
8845 SKIP_BLANKS;
8846 while ((CUR == '<') ||
8847 (CUR == '>') ||
8848 ((CUR == '<') && (NXT(1) == '=')) ||
8849 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008850 int inf, strict;
8851 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008852
8853 if (CUR == '<') inf = 1;
8854 else inf = 0;
8855 if (NXT(1) == '=') strict = 0;
8856 else strict = 1;
8857 NEXT;
8858 if (!strict) NEXT;
8859 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008860 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008861 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008862 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008863 SKIP_BLANKS;
8864 }
8865}
8866
8867/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008868 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008869 * @ctxt: the XPath Parser context
8870 *
8871 * [23] EqualityExpr ::= RelationalExpr
8872 * | EqualityExpr '=' RelationalExpr
8873 * | EqualityExpr '!=' RelationalExpr
8874 *
8875 * A != B != C is allowed ? Answer from James, yes with
8876 * (RelationalExpr = RelationalExpr) = RelationalExpr
8877 * (RelationalExpr != RelationalExpr) != RelationalExpr
8878 * which is basically what got implemented.
8879 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008880 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008881 *
8882 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008883static void
8884xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8885 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008886 CHECK_ERROR;
8887 SKIP_BLANKS;
8888 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008889 int eq;
8890 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008891
8892 if (CUR == '=') eq = 1;
8893 else eq = 0;
8894 NEXT;
8895 if (!eq) NEXT;
8896 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008897 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008898 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008899 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008900 SKIP_BLANKS;
8901 }
8902}
8903
8904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008905 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008906 * @ctxt: the XPath Parser context
8907 *
8908 * [22] AndExpr ::= EqualityExpr
8909 * | AndExpr 'and' EqualityExpr
8910 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008911 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008912 *
8913 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008914static void
8915xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8916 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008917 CHECK_ERROR;
8918 SKIP_BLANKS;
8919 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008920 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008921 SKIP(3);
8922 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008923 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008924 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008925 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008926 SKIP_BLANKS;
8927 }
8928}
8929
8930/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008931 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008932 * @ctxt: the XPath Parser context
8933 *
8934 * [14] Expr ::= OrExpr
8935 * [21] OrExpr ::= AndExpr
8936 * | OrExpr 'or' AndExpr
8937 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008938 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008939 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008940static void
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008941xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008942 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008943 CHECK_ERROR;
8944 SKIP_BLANKS;
8945 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008946 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008947 SKIP(2);
8948 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008949 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008950 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008951 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8952 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008953 SKIP_BLANKS;
8954 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008955 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008956 /* more ops could be optimized too */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008957 /*
8958 * This is the main place to eliminate sorting for
8959 * operations which don't require a sorted node-set.
8960 * E.g. count().
8961 */
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008962 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8963 }
Owen Taylor3473f882001-02-23 17:55:21 +00008964}
8965
8966/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008967 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008968 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008970 *
8971 * [8] Predicate ::= '[' PredicateExpr ']'
8972 * [9] PredicateExpr ::= Expr
8973 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008974 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008975 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008976static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008977xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008978 int op1 = ctxt->comp->last;
8979
8980 SKIP_BLANKS;
8981 if (CUR != '[') {
8982 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8983 }
8984 NEXT;
8985 SKIP_BLANKS;
8986
8987 ctxt->comp->last = -1;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00008988 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008989 CHECK_ERROR;
8990
8991 if (CUR != ']') {
8992 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8993 }
8994
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008995 if (filter)
8996 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8997 else
8998 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008999
9000 NEXT;
9001 SKIP_BLANKS;
9002}
9003
9004/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009005 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00009006 * @ctxt: the XPath Parser context
9007 * @test: pointer to a xmlXPathTestVal
9008 * @type: pointer to a xmlXPathTypeVal
9009 * @prefix: placeholder for a possible name prefix
9010 *
9011 * [7] NodeTest ::= NameTest
9012 * | NodeType '(' ')'
9013 * | 'processing-instruction' '(' Literal ')'
9014 *
9015 * [37] NameTest ::= '*'
9016 * | NCName ':' '*'
9017 * | QName
9018 * [38] NodeType ::= 'comment'
9019 * | 'text'
9020 * | 'processing-instruction'
9021 * | 'node'
9022 *
William M. Brack08171912003-12-29 02:52:11 +00009023 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00009024 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009025static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009026xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9027 xmlXPathTypeVal *type, const xmlChar **prefix,
9028 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00009029 int blanks;
9030
9031 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9032 STRANGE;
9033 return(NULL);
9034 }
William M. Brack78637da2003-07-31 14:47:38 +00009035 *type = (xmlXPathTypeVal) 0;
9036 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009037 *prefix = NULL;
9038 SKIP_BLANKS;
9039
9040 if ((name == NULL) && (CUR == '*')) {
9041 /*
9042 * All elements
9043 */
9044 NEXT;
9045 *test = NODE_TEST_ALL;
9046 return(NULL);
9047 }
9048
9049 if (name == NULL)
9050 name = xmlXPathParseNCName(ctxt);
9051 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009052 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009053 }
9054
William M. Brack76e95df2003-10-18 16:20:14 +00009055 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00009056 SKIP_BLANKS;
9057 if (CUR == '(') {
9058 NEXT;
9059 /*
9060 * NodeType or PI search
9061 */
9062 if (xmlStrEqual(name, BAD_CAST "comment"))
9063 *type = NODE_TYPE_COMMENT;
9064 else if (xmlStrEqual(name, BAD_CAST "node"))
9065 *type = NODE_TYPE_NODE;
9066 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9067 *type = NODE_TYPE_PI;
9068 else if (xmlStrEqual(name, BAD_CAST "text"))
9069 *type = NODE_TYPE_TEXT;
9070 else {
9071 if (name != NULL)
9072 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00009073 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009074 }
9075
9076 *test = NODE_TEST_TYPE;
9077
9078 SKIP_BLANKS;
9079 if (*type == NODE_TYPE_PI) {
9080 /*
9081 * Specific case: search a PI by name.
9082 */
Owen Taylor3473f882001-02-23 17:55:21 +00009083 if (name != NULL)
9084 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00009085 name = NULL;
9086 if (CUR != ')') {
9087 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +00009088 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00009089 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00009090 SKIP_BLANKS;
9091 }
Owen Taylor3473f882001-02-23 17:55:21 +00009092 }
9093 if (CUR != ')') {
9094 if (name != NULL)
9095 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00009096 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009097 }
9098 NEXT;
9099 return(name);
9100 }
9101 *test = NODE_TEST_NAME;
9102 if ((!blanks) && (CUR == ':')) {
9103 NEXT;
9104
9105 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009106 * Since currently the parser context don't have a
9107 * namespace list associated:
9108 * The namespace name for this prefix can be computed
9109 * only at evaluation time. The compilation is done
9110 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00009111 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009112#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00009113 *prefix = xmlXPathNsLookup(ctxt->context, name);
9114 if (name != NULL)
9115 xmlFree(name);
9116 if (*prefix == NULL) {
9117 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9118 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009119#else
9120 *prefix = name;
9121#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009122
9123 if (CUR == '*') {
9124 /*
9125 * All elements
9126 */
9127 NEXT;
9128 *test = NODE_TEST_ALL;
9129 return(NULL);
9130 }
9131
9132 name = xmlXPathParseNCName(ctxt);
9133 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00009134 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00009135 }
9136 }
9137 return(name);
9138}
9139
9140/**
9141 * xmlXPathIsAxisName:
9142 * @name: a preparsed name token
9143 *
9144 * [6] AxisName ::= 'ancestor'
9145 * | 'ancestor-or-self'
9146 * | 'attribute'
9147 * | 'child'
9148 * | 'descendant'
9149 * | 'descendant-or-self'
9150 * | 'following'
9151 * | 'following-sibling'
9152 * | 'namespace'
9153 * | 'parent'
9154 * | 'preceding'
9155 * | 'preceding-sibling'
9156 * | 'self'
9157 *
9158 * Returns the axis or 0
9159 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00009160static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00009161xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00009162 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00009163 switch (name[0]) {
9164 case 'a':
9165 if (xmlStrEqual(name, BAD_CAST "ancestor"))
9166 ret = AXIS_ANCESTOR;
9167 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9168 ret = AXIS_ANCESTOR_OR_SELF;
9169 if (xmlStrEqual(name, BAD_CAST "attribute"))
9170 ret = AXIS_ATTRIBUTE;
9171 break;
9172 case 'c':
9173 if (xmlStrEqual(name, BAD_CAST "child"))
9174 ret = AXIS_CHILD;
9175 break;
9176 case 'd':
9177 if (xmlStrEqual(name, BAD_CAST "descendant"))
9178 ret = AXIS_DESCENDANT;
9179 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9180 ret = AXIS_DESCENDANT_OR_SELF;
9181 break;
9182 case 'f':
9183 if (xmlStrEqual(name, BAD_CAST "following"))
9184 ret = AXIS_FOLLOWING;
9185 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9186 ret = AXIS_FOLLOWING_SIBLING;
9187 break;
9188 case 'n':
9189 if (xmlStrEqual(name, BAD_CAST "namespace"))
9190 ret = AXIS_NAMESPACE;
9191 break;
9192 case 'p':
9193 if (xmlStrEqual(name, BAD_CAST "parent"))
9194 ret = AXIS_PARENT;
9195 if (xmlStrEqual(name, BAD_CAST "preceding"))
9196 ret = AXIS_PRECEDING;
9197 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9198 ret = AXIS_PRECEDING_SIBLING;
9199 break;
9200 case 's':
9201 if (xmlStrEqual(name, BAD_CAST "self"))
9202 ret = AXIS_SELF;
9203 break;
9204 }
9205 return(ret);
9206}
9207
9208/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009209 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00009210 * @ctxt: the XPath Parser context
9211 *
9212 * [4] Step ::= AxisSpecifier NodeTest Predicate*
9213 * | AbbreviatedStep
9214 *
9215 * [12] AbbreviatedStep ::= '.' | '..'
9216 *
9217 * [5] AxisSpecifier ::= AxisName '::'
9218 * | AbbreviatedAxisSpecifier
9219 *
9220 * [13] AbbreviatedAxisSpecifier ::= '@'?
9221 *
9222 * Modified for XPtr range support as:
9223 *
9224 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9225 * | AbbreviatedStep
9226 * | 'range-to' '(' Expr ')' Predicate*
9227 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009228 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00009229 * A location step of . is short for self::node(). This is
9230 * particularly useful in conjunction with //. For example, the
9231 * location path .//para is short for
9232 * self::node()/descendant-or-self::node()/child::para
9233 * and so will select all para descendant elements of the context
9234 * node.
9235 * Similarly, a location step of .. is short for parent::node().
9236 * For example, ../title is short for parent::node()/child::title
9237 * and so will select the title children of the parent of the context
9238 * node.
9239 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009240static void
9241xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009242#ifdef LIBXML_XPTR_ENABLED
9243 int rangeto = 0;
9244 int op2 = -1;
9245#endif
9246
Owen Taylor3473f882001-02-23 17:55:21 +00009247 SKIP_BLANKS;
9248 if ((CUR == '.') && (NXT(1) == '.')) {
9249 SKIP(2);
9250 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009251 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9252 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009253 } else if (CUR == '.') {
9254 NEXT;
9255 SKIP_BLANKS;
9256 } else {
9257 xmlChar *name = NULL;
9258 const xmlChar *prefix = NULL;
Daniel Veillardaac7c682006-03-10 13:40:16 +00009259 xmlXPathTestVal test = (xmlXPathTestVal) 0;
William M. Brack78637da2003-07-31 14:47:38 +00009260 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Daniel Veillardaac7c682006-03-10 13:40:16 +00009261 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009262 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00009263
9264 /*
9265 * The modification needed for XPointer change to the production
9266 */
9267#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00009268 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00009269 name = xmlXPathParseNCName(ctxt);
9270 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009271 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00009272 xmlFree(name);
9273 SKIP_BLANKS;
9274 if (CUR != '(') {
9275 XP_ERROR(XPATH_EXPR_ERROR);
9276 }
9277 NEXT;
9278 SKIP_BLANKS;
9279
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009280 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009281 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00009282 CHECK_ERROR;
9283
9284 SKIP_BLANKS;
9285 if (CUR != ')') {
9286 XP_ERROR(XPATH_EXPR_ERROR);
9287 }
9288 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009289 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00009290 goto eval_predicates;
9291 }
9292 }
9293#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00009294 if (CUR == '*') {
9295 axis = AXIS_CHILD;
9296 } else {
9297 if (name == NULL)
9298 name = xmlXPathParseNCName(ctxt);
9299 if (name != NULL) {
9300 axis = xmlXPathIsAxisName(name);
9301 if (axis != 0) {
9302 SKIP_BLANKS;
9303 if ((CUR == ':') && (NXT(1) == ':')) {
9304 SKIP(2);
9305 xmlFree(name);
9306 name = NULL;
9307 } else {
9308 /* an element name can conflict with an axis one :-\ */
9309 axis = AXIS_CHILD;
9310 }
Owen Taylor3473f882001-02-23 17:55:21 +00009311 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00009312 axis = AXIS_CHILD;
9313 }
Daniel Veillard2156a562001-04-28 12:24:34 +00009314 } else if (CUR == '@') {
9315 NEXT;
9316 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00009317 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00009318 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00009319 }
Owen Taylor3473f882001-02-23 17:55:21 +00009320 }
9321
9322 CHECK_ERROR;
9323
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009324 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00009325 if (test == 0)
9326 return;
9327
Daniel Veillarded6c5492005-07-23 15:00:22 +00009328 if ((prefix != NULL) && (ctxt->context != NULL) &&
9329 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9330 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9331 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
9332 }
9333 }
Owen Taylor3473f882001-02-23 17:55:21 +00009334#ifdef DEBUG_STEP
9335 xmlGenericError(xmlGenericErrorContext,
9336 "Basis : computing new set\n");
9337#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009338
Owen Taylor3473f882001-02-23 17:55:21 +00009339#ifdef DEBUG_STEP
9340 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009341 if (ctxt->value == NULL)
9342 xmlGenericError(xmlGenericErrorContext, "no value\n");
9343 else if (ctxt->value->nodesetval == NULL)
9344 xmlGenericError(xmlGenericErrorContext, "Empty\n");
9345 else
9346 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00009347#endif
Owen Taylor3473f882001-02-23 17:55:21 +00009348
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00009349#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00009350eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00009351#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009352 op1 = ctxt->comp->last;
9353 ctxt->comp->last = -1;
9354
Owen Taylor3473f882001-02-23 17:55:21 +00009355 SKIP_BLANKS;
9356 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009357 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00009358 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009359
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009360#ifdef LIBXML_XPTR_ENABLED
9361 if (rangeto) {
9362 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
9363 } else
9364#endif
9365 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9366 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009367
Owen Taylor3473f882001-02-23 17:55:21 +00009368 }
9369#ifdef DEBUG_STEP
9370 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00009371 if (ctxt->value == NULL)
9372 xmlGenericError(xmlGenericErrorContext, "no value\n");
9373 else if (ctxt->value->nodesetval == NULL)
9374 xmlGenericError(xmlGenericErrorContext, "Empty\n");
9375 else
9376 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
9377 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00009378#endif
9379}
9380
9381/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009382 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009383 * @ctxt: the XPath Parser context
9384 *
9385 * [3] RelativeLocationPath ::= Step
9386 * | RelativeLocationPath '/' Step
9387 * | AbbreviatedRelativeLocationPath
9388 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
9389 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009390 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00009391 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009392static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009393xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00009394(xmlXPathParserContextPtr ctxt) {
9395 SKIP_BLANKS;
9396 if ((CUR == '/') && (NXT(1) == '/')) {
9397 SKIP(2);
9398 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009399 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9400 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009401 } else if (CUR == '/') {
9402 NEXT;
9403 SKIP_BLANKS;
9404 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009405 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009406 SKIP_BLANKS;
9407 while (CUR == '/') {
9408 if ((CUR == '/') && (NXT(1) == '/')) {
9409 SKIP(2);
9410 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009411 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009412 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009413 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009414 } else if (CUR == '/') {
9415 NEXT;
9416 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009417 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009418 }
9419 SKIP_BLANKS;
9420 }
9421}
9422
9423/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009424 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009425 * @ctxt: the XPath Parser context
9426 *
9427 * [1] LocationPath ::= RelativeLocationPath
9428 * | AbsoluteLocationPath
9429 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9430 * | AbbreviatedAbsoluteLocationPath
9431 * [10] AbbreviatedAbsoluteLocationPath ::=
9432 * '//' RelativeLocationPath
9433 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009434 * Compile a location path
9435 *
Owen Taylor3473f882001-02-23 17:55:21 +00009436 * // is short for /descendant-or-self::node()/. For example,
9437 * //para is short for /descendant-or-self::node()/child::para and
9438 * so will select any para element in the document (even a para element
9439 * that is a document element will be selected by //para since the
9440 * document element node is a child of the root node); div//para is
9441 * short for div/descendant-or-self::node()/child::para and so will
9442 * select all para descendants of div children.
9443 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009444static void
9445xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009446 SKIP_BLANKS;
9447 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009448 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009449 } else {
9450 while (CUR == '/') {
9451 if ((CUR == '/') && (NXT(1) == '/')) {
9452 SKIP(2);
9453 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009454 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9455 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009456 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009457 } else if (CUR == '/') {
9458 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009459 SKIP_BLANKS;
9460 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009461 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009462 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009463 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009464 }
9465 }
9466 }
9467}
9468
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009469/************************************************************************
9470 * *
9471 * XPath precompiled expression evaluation *
9472 * *
9473 ************************************************************************/
9474
Daniel Veillardf06307e2001-07-03 10:35:50 +00009475static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009476xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9477
9478/**
9479 * xmlXPathNodeCollectAndTest:
9480 * @ctxt: the XPath Parser context
9481 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009482 * @first: pointer to the first element in document order
9483 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009484 *
9485 * This is the function implementing a step: based on the current list
9486 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009487 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009488 *
9489 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 *
William M. Brack08171912003-12-29 02:52:11 +00009491 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009492 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009493static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009494xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009495 xmlXPathStepOpPtr op,
9496 xmlNodePtr * first, xmlNodePtr * last)
9497{
William M. Brack78637da2003-07-31 14:47:38 +00009498 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9499 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9500 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009501 const xmlChar *prefix = op->value4;
9502 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009503 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009504
9505#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009506 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009507#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009508 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009509 xmlNodeSetPtr ret, list;
9510 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009511 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009512 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009513 xmlNodePtr cur = NULL;
9514 xmlXPathObjectPtr obj;
9515 xmlNodeSetPtr nodelist;
9516 xmlNodePtr tmp;
9517
Daniel Veillardf06307e2001-07-03 10:35:50 +00009518 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009519 obj = valuePop(ctxt);
9520 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009521 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009522 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009523 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009524 if (URI == NULL) {
9525 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009526 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009527 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009528 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009529#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009530 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009531#endif
9532 switch (axis) {
9533 case AXIS_ANCESTOR:
9534#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009535 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009536#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009537 first = NULL;
9538 next = xmlXPathNextAncestor;
9539 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009540 case AXIS_ANCESTOR_OR_SELF:
9541#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009542 xmlGenericError(xmlGenericErrorContext,
9543 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009544#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009545 first = NULL;
9546 next = xmlXPathNextAncestorOrSelf;
9547 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009548 case AXIS_ATTRIBUTE:
9549#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009550 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009551#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009552 first = NULL;
9553 last = NULL;
9554 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009555 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009556 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009557 case AXIS_CHILD:
9558#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009559 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009560#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009561 last = NULL;
9562 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009563 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009564 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009565 case AXIS_DESCENDANT:
9566#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009568#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009569 last = NULL;
9570 next = xmlXPathNextDescendant;
9571 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009572 case AXIS_DESCENDANT_OR_SELF:
9573#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009574 xmlGenericError(xmlGenericErrorContext,
9575 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009576#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009577 last = NULL;
9578 next = xmlXPathNextDescendantOrSelf;
9579 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009580 case AXIS_FOLLOWING:
9581#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009582 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009583#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009584 last = NULL;
9585 next = xmlXPathNextFollowing;
9586 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009587 case AXIS_FOLLOWING_SIBLING:
9588#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009589 xmlGenericError(xmlGenericErrorContext,
9590 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009591#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009592 last = NULL;
9593 next = xmlXPathNextFollowingSibling;
9594 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009595 case AXIS_NAMESPACE:
9596#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009597 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009598#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009599 first = NULL;
9600 last = NULL;
9601 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009602 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009603 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009604 case AXIS_PARENT:
9605#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009606 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009607#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009608 first = NULL;
9609 next = xmlXPathNextParent;
9610 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009611 case AXIS_PRECEDING:
9612#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009613 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009614#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009615 first = NULL;
9616 next = xmlXPathNextPrecedingInternal;
9617 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009618 case AXIS_PRECEDING_SIBLING:
9619#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009620 xmlGenericError(xmlGenericErrorContext,
9621 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009622#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009623 first = NULL;
9624 next = xmlXPathNextPrecedingSibling;
9625 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009626 case AXIS_SELF:
9627#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009628 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009629#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009630 first = NULL;
9631 last = NULL;
9632 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009633 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009634 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009635 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009636 if (next == NULL) {
9637 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009638 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009639 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009640
9641 nodelist = obj->nodesetval;
9642 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009643 xmlXPathFreeObject(obj);
9644 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9645 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009646 }
9647 addNode = xmlXPathNodeSetAddUnique;
9648 ret = NULL;
9649#ifdef DEBUG_STEP
9650 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009651 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009652 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009653 case NODE_TEST_NONE:
9654 xmlGenericError(xmlGenericErrorContext,
9655 " searching for none !!!\n");
9656 break;
9657 case NODE_TEST_TYPE:
9658 xmlGenericError(xmlGenericErrorContext,
9659 " searching for type %d\n", type);
9660 break;
9661 case NODE_TEST_PI:
9662 xmlGenericError(xmlGenericErrorContext,
9663 " searching for PI !!!\n");
9664 break;
9665 case NODE_TEST_ALL:
9666 xmlGenericError(xmlGenericErrorContext,
9667 " searching for *\n");
9668 break;
9669 case NODE_TEST_NS:
9670 xmlGenericError(xmlGenericErrorContext,
9671 " searching for namespace %s\n",
9672 prefix);
9673 break;
9674 case NODE_TEST_NAME:
9675 xmlGenericError(xmlGenericErrorContext,
9676 " searching for name %s\n", name);
9677 if (prefix != NULL)
9678 xmlGenericError(xmlGenericErrorContext,
9679 " with namespace %s\n", prefix);
9680 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009681 }
9682 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9683#endif
9684 /*
9685 * 2.3 Node Tests
9686 * - For the attribute axis, the principal node type is attribute.
9687 * - For the namespace axis, the principal node type is namespace.
9688 * - For other axes, the principal node type is element.
9689 *
9690 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009691 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009692 * select all element children of the context node
9693 */
9694 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009695 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009696 ctxt->context->node = nodelist->nodeTab[i];
9697
Daniel Veillardf06307e2001-07-03 10:35:50 +00009698 cur = NULL;
9699 list = xmlXPathNodeSetCreate(NULL);
9700 do {
9701 cur = next(ctxt, cur);
9702 if (cur == NULL)
9703 break;
9704 if ((first != NULL) && (*first == cur))
9705 break;
9706 if (((t % 256) == 0) &&
9707 (first != NULL) && (*first != NULL) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009708#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009709 (xmlXPathCmpNodesExt(*first, cur) >= 0))
9710#else
Daniel Veillardf06307e2001-07-03 10:35:50 +00009711 (xmlXPathCmpNodes(*first, cur) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009712#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009713 break;
9714 if ((last != NULL) && (*last == cur))
9715 break;
9716 if (((t % 256) == 0) &&
9717 (last != NULL) && (*last != NULL) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +00009718#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009719 (xmlXPathCmpNodesExt(cur, *last) >= 0))
9720#else
Daniel Veillardf06307e2001-07-03 10:35:50 +00009721 (xmlXPathCmpNodes(cur, *last) >= 0))
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +00009722#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009723 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009724 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009725#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009726 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9727#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009728 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009729 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009730 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009731 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009732 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009733 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009734 if ((cur->type == type) ||
9735 ((type == NODE_TYPE_NODE) &&
9736 ((cur->type == XML_DOCUMENT_NODE) ||
9737 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9738 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009739 (cur->type == XML_NAMESPACE_DECL) ||
9740 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009741 (cur->type == XML_PI_NODE) ||
9742 (cur->type == XML_COMMENT_NODE) ||
9743 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009744 (cur->type == XML_TEXT_NODE))) ||
9745 ((type == NODE_TYPE_TEXT) &&
9746 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009747#ifdef DEBUG_STEP
9748 n++;
9749#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009750 addNode(list, cur);
9751 }
9752 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009753 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009754 if (cur->type == XML_PI_NODE) {
9755 if ((name != NULL) &&
9756 (!xmlStrEqual(name, cur->name)))
9757 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009758#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009759 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009760#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_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009765 if (axis == AXIS_ATTRIBUTE) {
9766 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009767#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009768 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009769#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009770 addNode(list, cur);
9771 }
9772 } else if (axis == AXIS_NAMESPACE) {
9773 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009774#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009776#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009777 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9778 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009779 }
9780 } else {
9781 if (cur->type == XML_ELEMENT_NODE) {
9782 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009783#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009784 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009785#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009786 addNode(list, cur);
9787 } else if ((cur->ns != NULL) &&
9788 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009789#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009790 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009791#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009792 addNode(list, cur);
9793 }
9794 }
9795 }
9796 break;
9797 case NODE_TEST_NS:{
9798 TODO;
9799 break;
9800 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009801 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009802 switch (cur->type) {
9803 case XML_ELEMENT_NODE:
9804 if (xmlStrEqual(name, cur->name)) {
9805 if (prefix == NULL) {
9806 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009807#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009808 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009809#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009810 addNode(list, cur);
9811 }
9812 } else {
9813 if ((cur->ns != NULL) &&
9814 (xmlStrEqual(URI,
9815 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009816#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009817 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009818#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009819 addNode(list, cur);
9820 }
9821 }
9822 }
9823 break;
9824 case XML_ATTRIBUTE_NODE:{
9825 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009826
Daniel Veillardf06307e2001-07-03 10:35:50 +00009827 if (xmlStrEqual(name, attr->name)) {
9828 if (prefix == NULL) {
9829 if ((attr->ns == NULL) ||
9830 (attr->ns->prefix == NULL)) {
9831#ifdef DEBUG_STEP
9832 n++;
9833#endif
9834 addNode(list,
9835 (xmlNodePtr) attr);
9836 }
9837 } else {
9838 if ((attr->ns != NULL) &&
9839 (xmlStrEqual(URI,
9840 attr->ns->
9841 href))) {
9842#ifdef DEBUG_STEP
9843 n++;
9844#endif
9845 addNode(list,
9846 (xmlNodePtr) attr);
9847 }
9848 }
9849 }
9850 break;
9851 }
9852 case XML_NAMESPACE_DECL:
9853 if (cur->type == XML_NAMESPACE_DECL) {
9854 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009855
Daniel Veillardf06307e2001-07-03 10:35:50 +00009856 if ((ns->prefix != NULL) && (name != NULL)
9857 && (xmlStrEqual(ns->prefix, name))) {
9858#ifdef DEBUG_STEP
9859 n++;
9860#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009861 xmlXPathNodeSetAddNs(list,
9862 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009863 }
9864 }
9865 break;
9866 default:
9867 break;
9868 }
9869 break;
9870 break;
9871 }
9872 } while (cur != NULL);
9873
9874 /*
9875 * If there is some predicate filtering do it now
9876 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009877 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009878 xmlXPathObjectPtr obj2;
9879
9880 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9881 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9882 CHECK_TYPE0(XPATH_NODESET);
9883 obj2 = valuePop(ctxt);
9884 list = obj2->nodesetval;
9885 obj2->nodesetval = NULL;
9886 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009887 if (ctxt->error != XPATH_EXPRESSION_OK) {
9888 xmlXPathFreeObject(obj);
9889 xmlXPathFreeNodeSet(list);
9890 return(0);
9891 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009892 }
9893 if (ret == NULL) {
9894 ret = list;
9895 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009896 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009897 xmlXPathFreeNodeSet(list);
9898 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009899 }
9900 ctxt->context->node = tmp;
9901#ifdef DEBUG_STEP
9902 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009903 "\nExamined %d nodes, found %d nodes at that step\n",
9904 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009905#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009906 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009907 if ((obj->boolval) && (obj->user != NULL)) {
9908 ctxt->value->boolval = 1;
9909 ctxt->value->user = obj->user;
9910 obj->user = NULL;
9911 obj->boolval = 0;
9912 }
9913 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009914 return(t);
9915}
9916
9917/**
9918 * xmlXPathNodeCollectAndTestNth:
9919 * @ctxt: the XPath Parser context
9920 * @op: the XPath precompiled step operation
9921 * @indx: the index to collect
9922 * @first: pointer to the first element in document order
9923 * @last: pointer to the last element in document order
9924 *
9925 * This is the function implementing a step: based on the current list
9926 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009927 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009928 *
9929 * Pushes the new NodeSet resulting from the search.
9930 * Returns the number of node traversed
9931 */
9932static int
9933xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9934 xmlXPathStepOpPtr op, int indx,
9935 xmlNodePtr * first, xmlNodePtr * last)
9936{
William M. Brack78637da2003-07-31 14:47:38 +00009937 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9938 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9939 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 const xmlChar *prefix = op->value4;
9941 const xmlChar *name = op->value5;
9942 const xmlChar *URI = NULL;
9943 int n = 0, t = 0;
9944
9945 int i;
9946 xmlNodeSetPtr list;
9947 xmlXPathTraversalFunction next = NULL;
9948 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9949 xmlNodePtr cur = NULL;
9950 xmlXPathObjectPtr obj;
9951 xmlNodeSetPtr nodelist;
9952 xmlNodePtr tmp;
9953
9954 CHECK_TYPE0(XPATH_NODESET);
9955 obj = valuePop(ctxt);
9956 addNode = xmlXPathNodeSetAdd;
9957 if (prefix != NULL) {
9958 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009959 if (URI == NULL) {
9960 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009961 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009962 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009963 }
9964#ifdef DEBUG_STEP_NTH
9965 xmlGenericError(xmlGenericErrorContext, "new step : ");
9966 if (first != NULL) {
9967 if (*first != NULL)
9968 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9969 (*first)->name);
9970 else
9971 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9972 }
9973 if (last != NULL) {
9974 if (*last != NULL)
9975 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9976 (*last)->name);
9977 else
9978 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9979 }
9980#endif
9981 switch (axis) {
9982 case AXIS_ANCESTOR:
9983#ifdef DEBUG_STEP_NTH
9984 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9985#endif
9986 first = NULL;
9987 next = xmlXPathNextAncestor;
9988 break;
9989 case AXIS_ANCESTOR_OR_SELF:
9990#ifdef DEBUG_STEP_NTH
9991 xmlGenericError(xmlGenericErrorContext,
9992 "axis 'ancestors-or-self' ");
9993#endif
9994 first = NULL;
9995 next = xmlXPathNextAncestorOrSelf;
9996 break;
9997 case AXIS_ATTRIBUTE:
9998#ifdef DEBUG_STEP_NTH
9999 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
10000#endif
10001 first = NULL;
10002 last = NULL;
10003 next = xmlXPathNextAttribute;
10004 break;
10005 case AXIS_CHILD:
10006#ifdef DEBUG_STEP_NTH
10007 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
10008#endif
10009 last = NULL;
10010 next = xmlXPathNextChild;
10011 break;
10012 case AXIS_DESCENDANT:
10013#ifdef DEBUG_STEP_NTH
10014 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
10015#endif
10016 last = NULL;
10017 next = xmlXPathNextDescendant;
10018 break;
10019 case AXIS_DESCENDANT_OR_SELF:
10020#ifdef DEBUG_STEP_NTH
10021 xmlGenericError(xmlGenericErrorContext,
10022 "axis 'descendant-or-self' ");
10023#endif
10024 last = NULL;
10025 next = xmlXPathNextDescendantOrSelf;
10026 break;
10027 case AXIS_FOLLOWING:
10028#ifdef DEBUG_STEP_NTH
10029 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
10030#endif
10031 last = NULL;
10032 next = xmlXPathNextFollowing;
10033 break;
10034 case AXIS_FOLLOWING_SIBLING:
10035#ifdef DEBUG_STEP_NTH
10036 xmlGenericError(xmlGenericErrorContext,
10037 "axis 'following-siblings' ");
10038#endif
10039 last = NULL;
10040 next = xmlXPathNextFollowingSibling;
10041 break;
10042 case AXIS_NAMESPACE:
10043#ifdef DEBUG_STEP_NTH
10044 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
10045#endif
10046 last = NULL;
10047 first = NULL;
10048 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10049 break;
10050 case AXIS_PARENT:
10051#ifdef DEBUG_STEP_NTH
10052 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
10053#endif
10054 first = NULL;
10055 next = xmlXPathNextParent;
10056 break;
10057 case AXIS_PRECEDING:
10058#ifdef DEBUG_STEP_NTH
10059 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
10060#endif
10061 first = NULL;
10062 next = xmlXPathNextPrecedingInternal;
10063 break;
10064 case AXIS_PRECEDING_SIBLING:
10065#ifdef DEBUG_STEP_NTH
10066 xmlGenericError(xmlGenericErrorContext,
10067 "axis 'preceding-sibling' ");
10068#endif
10069 first = NULL;
10070 next = xmlXPathNextPrecedingSibling;
10071 break;
10072 case AXIS_SELF:
10073#ifdef DEBUG_STEP_NTH
10074 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
10075#endif
10076 first = NULL;
10077 last = NULL;
10078 next = xmlXPathNextSelf;
10079 break;
10080 }
William M. Brack2c19a7b2005-04-10 01:03:23 +000010081 if (next == NULL) {
10082 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010084 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010085
10086 nodelist = obj->nodesetval;
10087 if (nodelist == NULL) {
10088 xmlXPathFreeObject(obj);
10089 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
10090 return(0);
10091 }
10092 addNode = xmlXPathNodeSetAddUnique;
10093#ifdef DEBUG_STEP_NTH
10094 xmlGenericError(xmlGenericErrorContext,
10095 " context contains %d nodes\n", nodelist->nodeNr);
10096 switch (test) {
10097 case NODE_TEST_NONE:
10098 xmlGenericError(xmlGenericErrorContext,
10099 " searching for none !!!\n");
10100 break;
10101 case NODE_TEST_TYPE:
10102 xmlGenericError(xmlGenericErrorContext,
10103 " searching for type %d\n", type);
10104 break;
10105 case NODE_TEST_PI:
10106 xmlGenericError(xmlGenericErrorContext,
10107 " searching for PI !!!\n");
10108 break;
10109 case NODE_TEST_ALL:
10110 xmlGenericError(xmlGenericErrorContext,
10111 " searching for *\n");
10112 break;
10113 case NODE_TEST_NS:
10114 xmlGenericError(xmlGenericErrorContext,
10115 " searching for namespace %s\n",
10116 prefix);
10117 break;
10118 case NODE_TEST_NAME:
10119 xmlGenericError(xmlGenericErrorContext,
10120 " searching for name %s\n", name);
10121 if (prefix != NULL)
10122 xmlGenericError(xmlGenericErrorContext,
10123 " with namespace %s\n", prefix);
10124 break;
10125 }
10126 xmlGenericError(xmlGenericErrorContext, "Testing : ");
10127#endif
10128 /*
10129 * 2.3 Node Tests
10130 * - For the attribute axis, the principal node type is attribute.
10131 * - For the namespace axis, the principal node type is namespace.
10132 * - For other axes, the principal node type is element.
10133 *
10134 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010135 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +000010136 * select all element children of the context node
10137 */
10138 tmp = ctxt->context->node;
10139 list = xmlXPathNodeSetCreate(NULL);
10140 for (i = 0; i < nodelist->nodeNr; i++) {
10141 ctxt->context->node = nodelist->nodeTab[i];
10142
10143 cur = NULL;
10144 n = 0;
10145 do {
10146 cur = next(ctxt, cur);
10147 if (cur == NULL)
10148 break;
10149 if ((first != NULL) && (*first == cur))
10150 break;
10151 if (((t % 256) == 0) &&
10152 (first != NULL) && (*first != NULL) &&
10153 (xmlXPathCmpNodes(*first, cur) >= 0))
10154 break;
10155 if ((last != NULL) && (*last == cur))
10156 break;
10157 if (((t % 256) == 0) &&
10158 (last != NULL) && (*last != NULL) &&
10159 (xmlXPathCmpNodes(cur, *last) >= 0))
10160 break;
10161 t++;
10162 switch (test) {
10163 case NODE_TEST_NONE:
10164 ctxt->context->node = tmp;
10165 STRANGE return(0);
10166 case NODE_TEST_TYPE:
10167 if ((cur->type == type) ||
10168 ((type == NODE_TYPE_NODE) &&
10169 ((cur->type == XML_DOCUMENT_NODE) ||
10170 (cur->type == XML_HTML_DOCUMENT_NODE) ||
10171 (cur->type == XML_ELEMENT_NODE) ||
10172 (cur->type == XML_PI_NODE) ||
10173 (cur->type == XML_COMMENT_NODE) ||
10174 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +000010175 (cur->type == XML_TEXT_NODE))) ||
10176 ((type == NODE_TYPE_TEXT) &&
10177 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010178 n++;
10179 if (n == indx)
10180 addNode(list, cur);
10181 }
10182 break;
10183 case NODE_TEST_PI:
10184 if (cur->type == XML_PI_NODE) {
10185 if ((name != NULL) &&
10186 (!xmlStrEqual(name, cur->name)))
10187 break;
10188 n++;
10189 if (n == indx)
10190 addNode(list, cur);
10191 }
10192 break;
10193 case NODE_TEST_ALL:
10194 if (axis == AXIS_ATTRIBUTE) {
10195 if (cur->type == XML_ATTRIBUTE_NODE) {
10196 n++;
10197 if (n == indx)
10198 addNode(list, cur);
10199 }
10200 } else if (axis == AXIS_NAMESPACE) {
10201 if (cur->type == XML_NAMESPACE_DECL) {
10202 n++;
10203 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000010204 xmlXPathNodeSetAddNs(list, ctxt->context->node,
10205 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010206 }
10207 } else {
10208 if (cur->type == XML_ELEMENT_NODE) {
10209 if (prefix == NULL) {
10210 n++;
10211 if (n == indx)
10212 addNode(list, cur);
10213 } else if ((cur->ns != NULL) &&
10214 (xmlStrEqual(URI, cur->ns->href))) {
10215 n++;
10216 if (n == indx)
10217 addNode(list, cur);
10218 }
10219 }
10220 }
10221 break;
10222 case NODE_TEST_NS:{
10223 TODO;
10224 break;
10225 }
10226 case NODE_TEST_NAME:
10227 switch (cur->type) {
10228 case XML_ELEMENT_NODE:
10229 if (xmlStrEqual(name, cur->name)) {
10230 if (prefix == NULL) {
10231 if (cur->ns == NULL) {
10232 n++;
10233 if (n == indx)
10234 addNode(list, cur);
10235 }
10236 } else {
10237 if ((cur->ns != NULL) &&
10238 (xmlStrEqual(URI,
10239 cur->ns->href))) {
10240 n++;
10241 if (n == indx)
10242 addNode(list, cur);
10243 }
10244 }
10245 }
10246 break;
10247 case XML_ATTRIBUTE_NODE:{
10248 xmlAttrPtr attr = (xmlAttrPtr) cur;
10249
10250 if (xmlStrEqual(name, attr->name)) {
10251 if (prefix == NULL) {
10252 if ((attr->ns == NULL) ||
10253 (attr->ns->prefix == NULL)) {
10254 n++;
10255 if (n == indx)
10256 addNode(list, cur);
10257 }
10258 } else {
10259 if ((attr->ns != NULL) &&
10260 (xmlStrEqual(URI,
10261 attr->ns->
10262 href))) {
10263 n++;
10264 if (n == indx)
10265 addNode(list, cur);
10266 }
10267 }
10268 }
10269 break;
10270 }
10271 case XML_NAMESPACE_DECL:
10272 if (cur->type == XML_NAMESPACE_DECL) {
10273 xmlNsPtr ns = (xmlNsPtr) cur;
10274
10275 if ((ns->prefix != NULL) && (name != NULL)
10276 && (xmlStrEqual(ns->prefix, name))) {
10277 n++;
10278 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +000010279 xmlXPathNodeSetAddNs(list,
10280 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 }
10282 }
10283 break;
10284 default:
10285 break;
10286 }
10287 break;
10288 break;
10289 }
10290 } while (n < indx);
10291 }
10292 ctxt->context->node = tmp;
10293#ifdef DEBUG_STEP_NTH
10294 xmlGenericError(xmlGenericErrorContext,
10295 "\nExamined %d nodes, found %d nodes at that step\n",
10296 t, list->nodeNr);
10297#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000010298 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +000010299 if ((obj->boolval) && (obj->user != NULL)) {
10300 ctxt->value->boolval = 1;
10301 ctxt->value->user = obj->user;
10302 obj->user = NULL;
10303 obj->boolval = 0;
10304 }
10305 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010306 return(t);
10307}
10308
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010309static int
10310xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10311 xmlXPathStepOpPtr op, xmlNodePtr * first);
10312
Daniel Veillardf06307e2001-07-03 10:35:50 +000010313/**
10314 * xmlXPathCompOpEvalFirst:
10315 * @ctxt: the XPath parser context with the compiled expression
10316 * @op: an XPath compiled operation
10317 * @first: the first elem found so far
10318 *
10319 * Evaluate the Precompiled XPath operation searching only the first
10320 * element in document order
10321 *
10322 * Returns the number of examined objects.
10323 */
10324static int
10325xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10326 xmlXPathStepOpPtr op, xmlNodePtr * first)
10327{
10328 int total = 0, cur;
10329 xmlXPathCompExprPtr comp;
10330 xmlXPathObjectPtr arg1, arg2;
10331
Daniel Veillard556c6682001-10-06 09:59:51 +000010332 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010333 comp = ctxt->comp;
10334 switch (op->op) {
10335 case XPATH_OP_END:
10336 return (0);
10337 case XPATH_OP_UNION:
10338 total =
10339 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10340 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010341 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 if ((ctxt->value != NULL)
10343 && (ctxt->value->type == XPATH_NODESET)
10344 && (ctxt->value->nodesetval != NULL)
10345 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10346 /*
10347 * limit tree traversing to first node in the result
10348 */
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010349 /*
10350 * OPTIMIZE TODO: This implicitely sorts
10351 * the result, even if not needed. E.g. if the argument
10352 * of the count() function, no sorting is needed.
10353 * OPTIMIZE TODO: How do we know if the node-list wasn't
10354 * aready sorted?
10355 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010356 if (ctxt->value->nodesetval->nodeNr > 1)
10357 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010358 *first = ctxt->value->nodesetval->nodeTab[0];
10359 }
10360 cur =
10361 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10362 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010363 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364 CHECK_TYPE0(XPATH_NODESET);
10365 arg2 = valuePop(ctxt);
10366
10367 CHECK_TYPE0(XPATH_NODESET);
10368 arg1 = valuePop(ctxt);
10369
10370 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10371 arg2->nodesetval);
10372 valuePush(ctxt, arg1);
10373 xmlXPathFreeObject(arg2);
10374 /* optimizer */
10375 if (total > cur)
10376 xmlXPathCompSwap(op);
10377 return (total + cur);
10378 case XPATH_OP_ROOT:
10379 xmlXPathRoot(ctxt);
10380 return (0);
10381 case XPATH_OP_NODE:
10382 if (op->ch1 != -1)
10383 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010384 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010385 if (op->ch2 != -1)
10386 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010387 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010388 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10389 return (total);
10390 case XPATH_OP_RESET:
10391 if (op->ch1 != -1)
10392 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010393 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 if (op->ch2 != -1)
10395 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010396 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010397 ctxt->context->node = NULL;
10398 return (total);
10399 case XPATH_OP_COLLECT:{
10400 if (op->ch1 == -1)
10401 return (total);
10402
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
10406 /*
10407 * Optimization for [n] selection where n is a number
10408 */
10409 if ((op->ch2 != -1) &&
10410 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10411 (comp->steps[op->ch2].ch1 == -1) &&
10412 (comp->steps[op->ch2].ch2 != -1) &&
10413 (comp->steps[comp->steps[op->ch2].ch2].op ==
10414 XPATH_OP_VALUE)) {
10415 xmlXPathObjectPtr val;
10416
10417 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10418 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10419 int indx = (int) val->floatval;
10420
10421 if (val->floatval == (float) indx) {
10422 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
10423 first, NULL);
10424 return (total);
10425 }
10426 }
10427 }
10428 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10429 return (total);
10430 }
10431 case XPATH_OP_VALUE:
10432 valuePush(ctxt,
10433 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10434 return (0);
10435 case XPATH_OP_SORT:
10436 if (op->ch1 != -1)
10437 total +=
10438 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10439 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010440 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010441 if ((ctxt->value != NULL)
10442 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010443 && (ctxt->value->nodesetval != NULL)
10444 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000010445 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10446 return (total);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010447#ifdef XP_OPTIMIZED_FILTER_FIRST
10448 case XPATH_OP_FILTER:
10449 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10450 return (total);
10451#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +000010452 default:
10453 return (xmlXPathCompOpEval(ctxt, op));
10454 }
10455}
10456
10457/**
10458 * xmlXPathCompOpEvalLast:
10459 * @ctxt: the XPath parser context with the compiled expression
10460 * @op: an XPath compiled operation
10461 * @last: the last elem found so far
10462 *
10463 * Evaluate the Precompiled XPath operation searching only the last
10464 * element in document order
10465 *
William M. Brack08171912003-12-29 02:52:11 +000010466 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010467 */
10468static int
10469xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10470 xmlNodePtr * last)
10471{
10472 int total = 0, cur;
10473 xmlXPathCompExprPtr comp;
10474 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010475 xmlNodePtr bak;
10476 xmlDocPtr bakd;
10477 int pp;
10478 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010479
Daniel Veillard556c6682001-10-06 09:59:51 +000010480 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010481 comp = ctxt->comp;
10482 switch (op->op) {
10483 case XPATH_OP_END:
10484 return (0);
10485 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010486 bakd = ctxt->context->doc;
10487 bak = ctxt->context->node;
10488 pp = ctxt->context->proximityPosition;
10489 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010490 total =
10491 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010492 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010493 if ((ctxt->value != NULL)
10494 && (ctxt->value->type == XPATH_NODESET)
10495 && (ctxt->value->nodesetval != NULL)
10496 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10497 /*
10498 * limit tree traversing to first node in the result
10499 */
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010500 if (ctxt->value->nodesetval->nodeNr > 1)
10501 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010502 *last =
10503 ctxt->value->nodesetval->nodeTab[ctxt->value->
10504 nodesetval->nodeNr -
10505 1];
10506 }
William M. Brackce4fc562004-01-22 02:47:18 +000010507 ctxt->context->doc = bakd;
10508 ctxt->context->node = bak;
10509 ctxt->context->proximityPosition = pp;
10510 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 cur =
10512 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010513 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010514 if ((ctxt->value != NULL)
10515 && (ctxt->value->type == XPATH_NODESET)
10516 && (ctxt->value->nodesetval != NULL)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010517 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010518 }
10519 CHECK_TYPE0(XPATH_NODESET);
10520 arg2 = valuePop(ctxt);
10521
10522 CHECK_TYPE0(XPATH_NODESET);
10523 arg1 = valuePop(ctxt);
10524
10525 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10526 arg2->nodesetval);
10527 valuePush(ctxt, arg1);
10528 xmlXPathFreeObject(arg2);
10529 /* optimizer */
10530 if (total > cur)
10531 xmlXPathCompSwap(op);
10532 return (total + cur);
10533 case XPATH_OP_ROOT:
10534 xmlXPathRoot(ctxt);
10535 return (0);
10536 case XPATH_OP_NODE:
10537 if (op->ch1 != -1)
10538 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010539 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010540 if (op->ch2 != -1)
10541 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010542 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010543 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10544 return (total);
10545 case XPATH_OP_RESET:
10546 if (op->ch1 != -1)
10547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010548 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010549 if (op->ch2 != -1)
10550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010551 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010552 ctxt->context->node = NULL;
10553 return (total);
10554 case XPATH_OP_COLLECT:{
10555 if (op->ch1 == -1)
10556 return (0);
10557
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
10561 /*
10562 * Optimization for [n] selection where n is a number
10563 */
10564 if ((op->ch2 != -1) &&
10565 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10566 (comp->steps[op->ch2].ch1 == -1) &&
10567 (comp->steps[op->ch2].ch2 != -1) &&
10568 (comp->steps[comp->steps[op->ch2].ch2].op ==
10569 XPATH_OP_VALUE)) {
10570 xmlXPathObjectPtr val;
10571
10572 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10573 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10574 int indx = (int) val->floatval;
10575
10576 if (val->floatval == (float) indx) {
10577 total +=
10578 xmlXPathNodeCollectAndTestNth(ctxt, op,
10579 indx, NULL,
10580 last);
10581 return (total);
10582 }
10583 }
10584 }
10585 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10586 return (total);
10587 }
10588 case XPATH_OP_VALUE:
10589 valuePush(ctxt,
10590 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10591 return (0);
10592 case XPATH_OP_SORT:
10593 if (op->ch1 != -1)
10594 total +=
10595 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10596 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010597 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010598 if ((ctxt->value != NULL)
10599 && (ctxt->value->type == XPATH_NODESET)
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000010600 && (ctxt->value->nodesetval != NULL)
10601 && (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000010602 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10603 return (total);
10604 default:
10605 return (xmlXPathCompOpEval(ctxt, op));
10606 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010607}
10608
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000010609#ifdef XP_OPTIMIZED_FILTER_FIRST
10610static int
10611xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10612 xmlXPathStepOpPtr op, xmlNodePtr * first)
10613{
10614 int total = 0;
10615 xmlXPathCompExprPtr comp;
10616 xmlXPathObjectPtr res;
10617 xmlXPathObjectPtr obj;
10618 xmlNodeSetPtr oldset;
10619 xmlNodePtr oldnode;
10620 xmlDocPtr oldDoc;
10621 int i;
10622
10623 CHECK_ERROR0;
10624 comp = ctxt->comp;
10625 /*
10626 * Optimization for ()[last()] selection i.e. the last elem
10627 */
10628 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10629 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10630 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10631 int f = comp->steps[op->ch2].ch1;
10632
10633 if ((f != -1) &&
10634 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10635 (comp->steps[f].value5 == NULL) &&
10636 (comp->steps[f].value == 0) &&
10637 (comp->steps[f].value4 != NULL) &&
10638 (xmlStrEqual
10639 (comp->steps[f].value4, BAD_CAST "last"))) {
10640 xmlNodePtr last = NULL;
10641
10642 total +=
10643 xmlXPathCompOpEvalLast(ctxt,
10644 &comp->steps[op->ch1],
10645 &last);
10646 CHECK_ERROR0;
10647 /*
10648 * The nodeset should be in document order,
10649 * Keep only the last value
10650 */
10651 if ((ctxt->value != NULL) &&
10652 (ctxt->value->type == XPATH_NODESET) &&
10653 (ctxt->value->nodesetval != NULL) &&
10654 (ctxt->value->nodesetval->nodeTab != NULL) &&
10655 (ctxt->value->nodesetval->nodeNr > 1)) {
10656 ctxt->value->nodesetval->nodeTab[0] =
10657 ctxt->value->nodesetval->nodeTab[ctxt->
10658 value->
10659 nodesetval->
10660 nodeNr -
10661 1];
10662 ctxt->value->nodesetval->nodeNr = 1;
10663 *first = *(ctxt->value->nodesetval->nodeTab);
10664 }
10665 return (total);
10666 }
10667 }
10668
10669 if (op->ch1 != -1)
10670 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10671 CHECK_ERROR0;
10672 if (op->ch2 == -1)
10673 return (total);
10674 if (ctxt->value == NULL)
10675 return (total);
10676
10677#ifdef LIBXML_XPTR_ENABLED
10678 oldnode = ctxt->context->node;
10679 /*
10680 * Hum are we filtering the result of an XPointer expression
10681 */
10682 if (ctxt->value->type == XPATH_LOCATIONSET) {
10683 xmlXPathObjectPtr tmp = NULL;
10684 xmlLocationSetPtr newlocset = NULL;
10685 xmlLocationSetPtr oldlocset;
10686
10687 /*
10688 * Extract the old locset, and then evaluate the result of the
10689 * expression for all the element in the locset. use it to grow
10690 * up a new locset.
10691 */
10692 CHECK_TYPE0(XPATH_LOCATIONSET);
10693 obj = valuePop(ctxt);
10694 oldlocset = obj->user;
10695 ctxt->context->node = NULL;
10696
10697 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10698 ctxt->context->contextSize = 0;
10699 ctxt->context->proximityPosition = 0;
10700 if (op->ch2 != -1)
10701 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10702 res = valuePop(ctxt);
10703 if (res != NULL)
10704 xmlXPathFreeObject(res);
10705 valuePush(ctxt, obj);
10706 CHECK_ERROR0;
10707 return (total);
10708 }
10709 newlocset = xmlXPtrLocationSetCreate(NULL);
10710
10711 for (i = 0; i < oldlocset->locNr; i++) {
10712 /*
10713 * Run the evaluation with a node list made of a
10714 * single item in the nodelocset.
10715 */
10716 ctxt->context->node = oldlocset->locTab[i]->user;
10717 ctxt->context->contextSize = oldlocset->locNr;
10718 ctxt->context->proximityPosition = i + 1;
10719 if (tmp == NULL)
10720 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10721 else {
10722 *(tmp->nodesetval->nodeTab) = ctxt->context->node;
10723 tmp->nodesetval->nodeNr = 1;
10724 }
10725 valuePush(ctxt, tmp);
10726 if (op->ch2 != -1)
10727 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10728 if (ctxt->error != XPATH_EXPRESSION_OK) {
10729 xmlXPathFreeObject(obj);
10730 return(0);
10731 }
10732 /*
10733 * The result of the evaluation need to be tested to
10734 * decided whether the filter succeeded or not
10735 */
10736 res = valuePop(ctxt);
10737 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10738 xmlXPtrLocationSetAdd(newlocset,
10739 xmlXPathObjectCopy(oldlocset->locTab[i]));
10740 }
10741 /*
10742 * Cleanup
10743 */
10744 if (res != NULL)
10745 xmlXPathFreeObject(res);
10746 if (ctxt->value == tmp) {
10747 valuePop(ctxt);
10748 tmp->nodesetval->nodeNr = 0;
10749 /*
10750 * REVISIT TODO: Don't free the temporary nodeset
10751 * in order to avoid massive recreation inside this
10752 * loop.
10753 */
10754 /* xmlXPathFreeObject(res); */
10755 } else {
10756 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10757 }
10758 ctxt->context->node = NULL;
10759 /*
10760 * Only put the first node in the result, then leave.
10761 */
10762 if (newlocset->locNr > 0) {
10763 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
10764 break;
10765 }
10766 }
10767 if (tmp != NULL)
10768 xmlXPathFreeObject(tmp);
10769 /*
10770 * The result is used as the new evaluation locset.
10771 */
10772 xmlXPathFreeObject(obj);
10773 ctxt->context->node = NULL;
10774 ctxt->context->contextSize = -1;
10775 ctxt->context->proximityPosition = -1;
10776 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10777 ctxt->context->node = oldnode;
10778 return (total);
10779 }
10780#endif /* LIBXML_XPTR_ENABLED */
10781
10782 /*
10783 * Extract the old set, and then evaluate the result of the
10784 * expression for all the element in the set. use it to grow
10785 * up a new set.
10786 */
10787 CHECK_TYPE0(XPATH_NODESET);
10788 obj = valuePop(ctxt);
10789 oldset = obj->nodesetval;
10790
10791 oldnode = ctxt->context->node;
10792 oldDoc = ctxt->context->doc;
10793 ctxt->context->node = NULL;
10794
10795 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10796 ctxt->context->contextSize = 0;
10797 ctxt->context->proximityPosition = 0;
10798 /* QUESTION TODO: Why was this code commented out?
10799 if (op->ch2 != -1)
10800 total +=
10801 xmlXPathCompOpEval(ctxt,
10802 &comp->steps[op->ch2]);
10803 CHECK_ERROR0;
10804 res = valuePop(ctxt);
10805 if (res != NULL)
10806 xmlXPathFreeObject(res);
10807 */
10808 valuePush(ctxt, obj);
10809 ctxt->context->node = oldnode;
10810 CHECK_ERROR0;
10811 } else {
10812 xmlNodeSetPtr newset;
10813 xmlXPathObjectPtr tmp = NULL;
10814 /*
10815 * Initialize the new set.
10816 * Also set the xpath document in case things like
10817 * key() evaluation are attempted on the predicate
10818 */
10819 newset = xmlXPathNodeSetCreate(NULL);
10820
10821 for (i = 0; i < oldset->nodeNr; i++) {
10822 /*
10823 * Run the evaluation with a node list made of
10824 * a single item in the nodeset.
10825 */
10826 ctxt->context->node = oldset->nodeTab[i];
10827 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10828 (oldset->nodeTab[i]->doc != NULL))
10829 ctxt->context->doc = oldset->nodeTab[i]->doc;
10830 if (tmp == NULL)
10831 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10832 else {
10833 *(tmp->nodesetval->nodeTab) = ctxt->context->node;
10834 tmp->nodesetval->nodeNr = 1;
10835 }
10836 valuePush(ctxt, tmp);
10837 ctxt->context->contextSize = oldset->nodeNr;
10838 ctxt->context->proximityPosition = i + 1;
10839 if (op->ch2 != -1)
10840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10841 if (ctxt->error != XPATH_EXPRESSION_OK) {
10842 xmlXPathFreeNodeSet(newset);
10843 xmlXPathFreeObject(obj);
10844 return(0);
10845 }
10846 /*
10847 * The result of the evaluation needs to be tested to
10848 * decide whether the filter succeeded or not
10849 */
10850 res = valuePop(ctxt);
10851 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10852 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10853 }
10854 /*
10855 * Cleanup
10856 */
10857 if (res != NULL)
10858 xmlXPathFreeObject(res);
10859 if (ctxt->value == tmp) {
10860 valuePop(ctxt);
10861 tmp->nodesetval->nodeNr = 0;
10862 /*
10863 * REVISIT TODO: Don't free the temporary nodeset
10864 * in order to avoid massive recreation inside this
10865 * loop.
10866 */
10867 /* xmlXPathFreeObject(res); */
10868 } else {
10869 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10870 }
10871 ctxt->context->node = NULL;
10872 /*
10873 * Only put the first node in the result, then leave.
10874 */
10875 if (newset->nodeNr > 0) {
10876 *first = *(newset->nodeTab);
10877 break;
10878 }
10879 }
10880 if (tmp != NULL)
10881 xmlXPathFreeObject(tmp);
10882 /*
10883 * The result is used as the new evaluation set.
10884 */
10885 xmlXPathFreeObject(obj);
10886 ctxt->context->node = NULL;
10887 ctxt->context->contextSize = -1;
10888 ctxt->context->proximityPosition = -1;
10889 /* may want to move this past the '}' later */
10890 ctxt->context->doc = oldDoc;
10891 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10892 }
10893 ctxt->context->node = oldnode;
10894 return(total);
10895}
10896#endif /* XP_OPTIMIZED_FILTER_FIRST */
10897
Owen Taylor3473f882001-02-23 17:55:21 +000010898/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010899 * xmlXPathCompOpEval:
10900 * @ctxt: the XPath parser context with the compiled expression
10901 * @op: an XPath compiled operation
10902 *
10903 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010904 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010905 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010906static int
10907xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10908{
10909 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010910 int equal, ret;
10911 xmlXPathCompExprPtr comp;
10912 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010913 xmlNodePtr bak;
10914 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010915 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010916 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010917
Daniel Veillard556c6682001-10-06 09:59:51 +000010918 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010919 comp = ctxt->comp;
10920 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010921 case XPATH_OP_END:
10922 return (0);
10923 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010924 bakd = ctxt->context->doc;
10925 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010926 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010927 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010928 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010929 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010930 xmlXPathBooleanFunction(ctxt, 1);
10931 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10932 return (total);
10933 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010934 ctxt->context->doc = bakd;
10935 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010936 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010937 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010938 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010939 if (ctxt->error) {
10940 xmlXPathFreeObject(arg2);
10941 return(0);
10942 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010943 xmlXPathBooleanFunction(ctxt, 1);
10944 arg1 = valuePop(ctxt);
10945 arg1->boolval &= arg2->boolval;
10946 valuePush(ctxt, arg1);
10947 xmlXPathFreeObject(arg2);
10948 return (total);
10949 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010950 bakd = ctxt->context->doc;
10951 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010952 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010953 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010954 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010955 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010956 xmlXPathBooleanFunction(ctxt, 1);
10957 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10958 return (total);
10959 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010960 ctxt->context->doc = bakd;
10961 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010962 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010963 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010965 if (ctxt->error) {
10966 xmlXPathFreeObject(arg2);
10967 return(0);
10968 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010969 xmlXPathBooleanFunction(ctxt, 1);
10970 arg1 = valuePop(ctxt);
10971 arg1->boolval |= arg2->boolval;
10972 valuePush(ctxt, arg1);
10973 xmlXPathFreeObject(arg2);
10974 return (total);
10975 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010976 bakd = ctxt->context->doc;
10977 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010978 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010979 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010980 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010981 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010982 ctxt->context->doc = bakd;
10983 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010984 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010985 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010986 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010987 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010988 if (op->value)
10989 equal = xmlXPathEqualValues(ctxt);
10990 else
10991 equal = xmlXPathNotEqualValues(ctxt);
10992 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010993 return (total);
10994 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010995 bakd = ctxt->context->doc;
10996 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010997 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010998 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011000 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011001 ctxt->context->doc = bakd;
11002 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011003 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011004 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011006 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011007 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11008 valuePush(ctxt, xmlXPathNewBoolean(ret));
11009 return (total);
11010 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011011 bakd = ctxt->context->doc;
11012 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000011013 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000011014 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011015 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011016 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011017 if (op->ch2 != -1) {
11018 ctxt->context->doc = bakd;
11019 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011020 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011021 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011022 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011023 }
Daniel Veillard556c6682001-10-06 09:59:51 +000011024 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011025 if (op->value == 0)
11026 xmlXPathSubValues(ctxt);
11027 else if (op->value == 1)
11028 xmlXPathAddValues(ctxt);
11029 else if (op->value == 2)
11030 xmlXPathValueFlipSign(ctxt);
11031 else if (op->value == 3) {
11032 CAST_TO_NUMBER;
11033 CHECK_TYPE0(XPATH_NUMBER);
11034 }
11035 return (total);
11036 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011037 bakd = ctxt->context->doc;
11038 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000011039 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000011040 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011041 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011042 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011043 ctxt->context->doc = bakd;
11044 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011045 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011046 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011047 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011048 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011049 if (op->value == 0)
11050 xmlXPathMultValues(ctxt);
11051 else if (op->value == 1)
11052 xmlXPathDivValues(ctxt);
11053 else if (op->value == 2)
11054 xmlXPathModValues(ctxt);
11055 return (total);
11056 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011057 bakd = ctxt->context->doc;
11058 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000011059 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000011060 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011061 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011062 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000011063 ctxt->context->doc = bakd;
11064 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000011065 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000011066 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011067 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011068 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011069 CHECK_TYPE0(XPATH_NODESET);
11070 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011071
Daniel Veillardf06307e2001-07-03 10:35:50 +000011072 CHECK_TYPE0(XPATH_NODESET);
11073 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011074
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011075 if ((arg1->nodesetval == NULL) ||
11076 ((arg2->nodesetval != NULL) &&
11077 (arg2->nodesetval->nodeNr != 0)))
11078 {
11079 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11080 arg2->nodesetval);
11081 }
11082
Daniel Veillardf06307e2001-07-03 10:35:50 +000011083 valuePush(ctxt, arg1);
11084 xmlXPathFreeObject(arg2);
11085 return (total);
11086 case XPATH_OP_ROOT:
11087 xmlXPathRoot(ctxt);
11088 return (total);
11089 case XPATH_OP_NODE:
11090 if (op->ch1 != -1)
11091 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011092 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011093 if (op->ch2 != -1)
11094 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011095 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011096 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
11097 return (total);
11098 case XPATH_OP_RESET:
11099 if (op->ch1 != -1)
11100 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011101 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011102 if (op->ch2 != -1)
11103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011105 ctxt->context->node = NULL;
11106 return (total);
11107 case XPATH_OP_COLLECT:{
11108 if (op->ch1 == -1)
11109 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011110
Daniel Veillardf06307e2001-07-03 10:35:50 +000011111 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011112 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011113
Daniel Veillardf06307e2001-07-03 10:35:50 +000011114 /*
11115 * Optimization for [n] selection where n is a number
11116 */
11117 if ((op->ch2 != -1) &&
11118 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
11119 (comp->steps[op->ch2].ch1 == -1) &&
11120 (comp->steps[op->ch2].ch2 != -1) &&
11121 (comp->steps[comp->steps[op->ch2].ch2].op ==
11122 XPATH_OP_VALUE)) {
11123 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000011124
Daniel Veillardf06307e2001-07-03 10:35:50 +000011125 val = comp->steps[comp->steps[op->ch2].ch2].value4;
11126 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
11127 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011128
Daniel Veillardf06307e2001-07-03 10:35:50 +000011129 if (val->floatval == (float) indx) {
11130 total +=
11131 xmlXPathNodeCollectAndTestNth(ctxt, op,
11132 indx, NULL,
11133 NULL);
11134 return (total);
11135 }
11136 }
11137 }
11138 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
11139 return (total);
11140 }
11141 case XPATH_OP_VALUE:
11142 valuePush(ctxt,
11143 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
11144 return (total);
11145 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000011146 xmlXPathObjectPtr val;
11147
Daniel Veillardf06307e2001-07-03 10:35:50 +000011148 if (op->ch1 != -1)
11149 total +=
11150 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011151 if (op->value5 == NULL) {
11152 val = xmlXPathVariableLookup(ctxt->context, op->value4);
11153 if (val == NULL) {
11154 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
11155 return(0);
11156 }
11157 valuePush(ctxt, val);
11158 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011159 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011160
Daniel Veillardf06307e2001-07-03 10:35:50 +000011161 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11162 if (URI == NULL) {
11163 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011164 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000011165 op->value4, op->value5);
11166 return (total);
11167 }
Daniel Veillard556c6682001-10-06 09:59:51 +000011168 val = xmlXPathVariableLookupNS(ctxt->context,
11169 op->value4, URI);
11170 if (val == NULL) {
11171 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
11172 return(0);
11173 }
11174 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011175 }
11176 return (total);
11177 }
11178 case XPATH_OP_FUNCTION:{
11179 xmlXPathFunction func;
11180 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000011181 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011182
11183 if (op->ch1 != -1)
11184 total +=
11185 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011186 if (ctxt->valueNr < op->value) {
11187 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011188 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000011189 ctxt->error = XPATH_INVALID_OPERAND;
11190 return (total);
11191 }
11192 for (i = 0; i < op->value; i++)
11193 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
11194 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011195 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000011196 ctxt->error = XPATH_INVALID_OPERAND;
11197 return (total);
11198 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011199 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000011200 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011201 else {
11202 const xmlChar *URI = NULL;
11203
11204 if (op->value5 == NULL)
11205 func =
11206 xmlXPathFunctionLookup(ctxt->context,
11207 op->value4);
11208 else {
11209 URI = xmlXPathNsLookup(ctxt->context, op->value5);
11210 if (URI == NULL) {
11211 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011212 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000011213 op->value4, op->value5);
11214 return (total);
11215 }
11216 func = xmlXPathFunctionLookupNS(ctxt->context,
11217 op->value4, URI);
11218 }
11219 if (func == NULL) {
11220 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011221 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000011222 op->value4);
11223 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011224 }
William M. Brackad0e67c2004-12-01 14:35:10 +000011225 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011226 op->cacheURI = (void *) URI;
11227 }
11228 oldFunc = ctxt->context->function;
11229 oldFuncURI = ctxt->context->functionURI;
11230 ctxt->context->function = op->value4;
11231 ctxt->context->functionURI = op->cacheURI;
11232 func(ctxt, op->value);
11233 ctxt->context->function = oldFunc;
11234 ctxt->context->functionURI = oldFuncURI;
11235 return (total);
11236 }
11237 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000011238 bakd = ctxt->context->doc;
11239 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000011240 pp = ctxt->context->proximityPosition;
11241 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011242 if (op->ch1 != -1)
11243 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000011244 ctxt->context->contextSize = cs;
11245 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000011246 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000011247 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000011248 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000011249 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011250 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000011251 ctxt->context->doc = bakd;
11252 ctxt->context->node = bak;
11253 CHECK_ERROR0;
11254 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011255 return (total);
11256 case XPATH_OP_PREDICATE:
11257 case XPATH_OP_FILTER:{
11258 xmlXPathObjectPtr res;
11259 xmlXPathObjectPtr obj, tmp;
11260 xmlNodeSetPtr newset = NULL;
11261 xmlNodeSetPtr oldset;
11262 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000011263 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011264 int i;
11265
11266 /*
11267 * Optimization for ()[1] selection i.e. the first elem
11268 */
11269 if ((op->ch1 != -1) && (op->ch2 != -1) &&
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011270#ifdef XP_OPTIMIZED_FILTER_FIRST
11271 /*
11272 * FILTER TODO: Can we assume that the inner processing
11273 * will result in an ordered list if we have an
11274 * XPATH_OP_FILTER?
11275 * What about an additional field or flag on
11276 * xmlXPathObject like @sorted ? This way we wouln'd need
11277 * to assume anything, so it would be more robust and
11278 * easier to optimize.
11279 */
11280 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11281 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11282#else
11283 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11284#endif
11285 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000011286 xmlXPathObjectPtr val;
11287
11288 val = comp->steps[op->ch2].value4;
11289 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11290 (val->floatval == 1.0)) {
11291 xmlNodePtr first = NULL;
11292
11293 total +=
11294 xmlXPathCompOpEvalFirst(ctxt,
11295 &comp->steps[op->ch1],
11296 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000011297 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011298 /*
11299 * The nodeset should be in document order,
11300 * Keep only the first value
11301 */
11302 if ((ctxt->value != NULL) &&
11303 (ctxt->value->type == XPATH_NODESET) &&
11304 (ctxt->value->nodesetval != NULL) &&
11305 (ctxt->value->nodesetval->nodeNr > 1))
11306 ctxt->value->nodesetval->nodeNr = 1;
11307 return (total);
11308 }
11309 }
11310 /*
11311 * Optimization for ()[last()] selection i.e. the last elem
11312 */
11313 if ((op->ch1 != -1) && (op->ch2 != -1) &&
11314 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11315 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11316 int f = comp->steps[op->ch2].ch1;
11317
11318 if ((f != -1) &&
11319 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11320 (comp->steps[f].value5 == NULL) &&
11321 (comp->steps[f].value == 0) &&
11322 (comp->steps[f].value4 != NULL) &&
11323 (xmlStrEqual
11324 (comp->steps[f].value4, BAD_CAST "last"))) {
11325 xmlNodePtr last = NULL;
11326
11327 total +=
11328 xmlXPathCompOpEvalLast(ctxt,
11329 &comp->steps[op->ch1],
11330 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000011331 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011332 /*
11333 * The nodeset should be in document order,
11334 * Keep only the last value
11335 */
11336 if ((ctxt->value != NULL) &&
11337 (ctxt->value->type == XPATH_NODESET) &&
11338 (ctxt->value->nodesetval != NULL) &&
11339 (ctxt->value->nodesetval->nodeTab != NULL) &&
11340 (ctxt->value->nodesetval->nodeNr > 1)) {
11341 ctxt->value->nodesetval->nodeTab[0] =
11342 ctxt->value->nodesetval->nodeTab[ctxt->
11343 value->
11344 nodesetval->
11345 nodeNr -
11346 1];
11347 ctxt->value->nodesetval->nodeNr = 1;
11348 }
11349 return (total);
11350 }
11351 }
11352
11353 if (op->ch1 != -1)
11354 total +=
11355 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011356 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011357 if (op->ch2 == -1)
11358 return (total);
11359 if (ctxt->value == NULL)
11360 return (total);
11361
11362 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011363
11364#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000011365 /*
11366 * Hum are we filtering the result of an XPointer expression
11367 */
11368 if (ctxt->value->type == XPATH_LOCATIONSET) {
11369 xmlLocationSetPtr newlocset = NULL;
11370 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011371
Daniel Veillardf06307e2001-07-03 10:35:50 +000011372 /*
11373 * Extract the old locset, and then evaluate the result of the
11374 * expression for all the element in the locset. use it to grow
11375 * up a new locset.
11376 */
11377 CHECK_TYPE0(XPATH_LOCATIONSET);
11378 obj = valuePop(ctxt);
11379 oldlocset = obj->user;
11380 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011381
Daniel Veillardf06307e2001-07-03 10:35:50 +000011382 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
11383 ctxt->context->contextSize = 0;
11384 ctxt->context->proximityPosition = 0;
11385 if (op->ch2 != -1)
11386 total +=
11387 xmlXPathCompOpEval(ctxt,
11388 &comp->steps[op->ch2]);
11389 res = valuePop(ctxt);
11390 if (res != NULL)
11391 xmlXPathFreeObject(res);
11392 valuePush(ctxt, obj);
11393 CHECK_ERROR0;
11394 return (total);
11395 }
11396 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011397
Daniel Veillardf06307e2001-07-03 10:35:50 +000011398 for (i = 0; i < oldlocset->locNr; i++) {
11399 /*
11400 * Run the evaluation with a node list made of a
11401 * single item in the nodelocset.
11402 */
11403 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011404 ctxt->context->contextSize = oldlocset->locNr;
11405 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000011406 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11407 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011408
Daniel Veillardf06307e2001-07-03 10:35:50 +000011409 if (op->ch2 != -1)
11410 total +=
11411 xmlXPathCompOpEval(ctxt,
11412 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011413 if (ctxt->error != XPATH_EXPRESSION_OK) {
11414 xmlXPathFreeObject(obj);
11415 return(0);
11416 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011417
Daniel Veillardf06307e2001-07-03 10:35:50 +000011418 /*
11419 * The result of the evaluation need to be tested to
11420 * decided whether the filter succeeded or not
11421 */
11422 res = valuePop(ctxt);
11423 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
11424 xmlXPtrLocationSetAdd(newlocset,
11425 xmlXPathObjectCopy
11426 (oldlocset->locTab[i]));
11427 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011428
Daniel Veillardf06307e2001-07-03 10:35:50 +000011429 /*
11430 * Cleanup
11431 */
11432 if (res != NULL)
11433 xmlXPathFreeObject(res);
11434 if (ctxt->value == tmp) {
11435 res = valuePop(ctxt);
11436 xmlXPathFreeObject(res);
11437 }
11438
11439 ctxt->context->node = NULL;
11440 }
11441
11442 /*
11443 * The result is used as the new evaluation locset.
11444 */
11445 xmlXPathFreeObject(obj);
11446 ctxt->context->node = NULL;
11447 ctxt->context->contextSize = -1;
11448 ctxt->context->proximityPosition = -1;
11449 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
11450 ctxt->context->node = oldnode;
11451 return (total);
11452 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011453#endif /* LIBXML_XPTR_ENABLED */
11454
Daniel Veillardf06307e2001-07-03 10:35:50 +000011455 /*
11456 * Extract the old set, and then evaluate the result of the
11457 * expression for all the element in the set. use it to grow
11458 * up a new set.
11459 */
11460 CHECK_TYPE0(XPATH_NODESET);
11461 obj = valuePop(ctxt);
11462 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000011463
Daniel Veillardf06307e2001-07-03 10:35:50 +000011464 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000011465 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011466 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011467
Daniel Veillardf06307e2001-07-03 10:35:50 +000011468 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
11469 ctxt->context->contextSize = 0;
11470 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000011471/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000011472 if (op->ch2 != -1)
11473 total +=
11474 xmlXPathCompOpEval(ctxt,
11475 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011476 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011477 res = valuePop(ctxt);
11478 if (res != NULL)
11479 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000011480*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000011481 valuePush(ctxt, obj);
11482 ctxt->context->node = oldnode;
11483 CHECK_ERROR0;
11484 } else {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011485 tmp = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011486 /*
11487 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000011488 * Also set the xpath document in case things like
11489 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000011490 */
11491 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011492
Daniel Veillardf06307e2001-07-03 10:35:50 +000011493 for (i = 0; i < oldset->nodeNr; i++) {
11494 /*
11495 * Run the evaluation with a node list made of
11496 * a single item in the nodeset.
11497 */
11498 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000011499 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
11500 (oldset->nodeTab[i]->doc != NULL))
11501 ctxt->context->doc = oldset->nodeTab[i]->doc;
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011502 if (tmp == NULL)
11503 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11504 else {
11505 *(tmp->nodesetval->nodeTab) = ctxt->context->node;
11506 tmp->nodesetval->nodeNr = 1;
11507 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011508 valuePush(ctxt, tmp);
11509 ctxt->context->contextSize = oldset->nodeNr;
11510 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011511
Daniel Veillardf06307e2001-07-03 10:35:50 +000011512 if (op->ch2 != -1)
11513 total +=
11514 xmlXPathCompOpEval(ctxt,
11515 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011516 if (ctxt->error != XPATH_EXPRESSION_OK) {
11517 xmlXPathFreeNodeSet(newset);
11518 xmlXPathFreeObject(obj);
11519 return(0);
11520 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011521
Daniel Veillardf06307e2001-07-03 10:35:50 +000011522 /*
William M. Brack08171912003-12-29 02:52:11 +000011523 * The result of the evaluation needs to be tested to
11524 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000011525 */
11526 res = valuePop(ctxt);
11527 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
11528 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
11529 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011530
Daniel Veillardf06307e2001-07-03 10:35:50 +000011531 /*
11532 * Cleanup
11533 */
11534 if (res != NULL)
11535 xmlXPathFreeObject(res);
11536 if (ctxt->value == tmp) {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011537 valuePop(ctxt);
11538 tmp->nodesetval->nodeNr = 0;
11539 /*
11540 * REVISIT TODO: Don't free the temporary nodeset
11541 * in order to avoid massive recreation inside this
11542 * loop.
11543 */
11544 /* xmlXPathFreeObject(res); */
11545 } else
11546 tmp = xmlXPathNewNodeSet(ctxt->context->node);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011547
Daniel Veillardf06307e2001-07-03 10:35:50 +000011548 ctxt->context->node = NULL;
11549 }
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000011550 if (tmp != NULL)
11551 xmlXPathFreeObject(tmp);
Daniel Veillardf06307e2001-07-03 10:35:50 +000011552
11553 /*
11554 * The result is used as the new evaluation set.
11555 */
11556 xmlXPathFreeObject(obj);
11557 ctxt->context->node = NULL;
11558 ctxt->context->contextSize = -1;
11559 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000011560 /* may want to move this past the '}' later */
11561 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011562 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
11563 }
11564 ctxt->context->node = oldnode;
11565 return (total);
11566 }
11567 case XPATH_OP_SORT:
11568 if (op->ch1 != -1)
11569 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000011570 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011571 if ((ctxt->value != NULL) &&
11572 (ctxt->value->type == XPATH_NODESET) &&
Kasimier T. Buchcik64f7e1a2006-05-19 19:59:54 +000011573 (ctxt->value->nodesetval != NULL) &&
11574 (ctxt->value->nodesetval->nodeNr > 1))
Daniel Veillardf06307e2001-07-03 10:35:50 +000011575 xmlXPathNodeSetSort(ctxt->value->nodesetval);
11576 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011577#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000011578 case XPATH_OP_RANGETO:{
11579 xmlXPathObjectPtr range;
11580 xmlXPathObjectPtr res, obj;
11581 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000011582 xmlLocationSetPtr newlocset = NULL;
11583 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011584 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000011585 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011586
Daniel Veillardf06307e2001-07-03 10:35:50 +000011587 if (op->ch1 != -1)
11588 total +=
11589 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11590 if (op->ch2 == -1)
11591 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011592
William M. Brack08171912003-12-29 02:52:11 +000011593 if (ctxt->value->type == XPATH_LOCATIONSET) {
11594 /*
11595 * Extract the old locset, and then evaluate the result of the
11596 * expression for all the element in the locset. use it to grow
11597 * up a new locset.
11598 */
11599 CHECK_TYPE0(XPATH_LOCATIONSET);
11600 obj = valuePop(ctxt);
11601 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011602
William M. Brack08171912003-12-29 02:52:11 +000011603 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000011604 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000011605 ctxt->context->contextSize = 0;
11606 ctxt->context->proximityPosition = 0;
11607 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
11608 res = valuePop(ctxt);
11609 if (res != NULL)
11610 xmlXPathFreeObject(res);
11611 valuePush(ctxt, obj);
11612 CHECK_ERROR0;
11613 return (total);
11614 }
11615 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011616
William M. Brack08171912003-12-29 02:52:11 +000011617 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000011618 /*
William M. Brack08171912003-12-29 02:52:11 +000011619 * Run the evaluation with a node list made of a
11620 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000011621 */
William M. Brackf7eb7942003-12-31 07:59:17 +000011622 ctxt->context->node = oldlocset->locTab[i]->user;
11623 ctxt->context->contextSize = oldlocset->locNr;
11624 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000011625 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11626 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011627
Daniel Veillardf06307e2001-07-03 10:35:50 +000011628 if (op->ch2 != -1)
11629 total +=
11630 xmlXPathCompOpEval(ctxt,
11631 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011632 if (ctxt->error != XPATH_EXPRESSION_OK) {
11633 xmlXPathFreeObject(obj);
11634 return(0);
11635 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011636
Daniel Veillardf06307e2001-07-03 10:35:50 +000011637 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000011638 if (res->type == XPATH_LOCATIONSET) {
11639 xmlLocationSetPtr rloc =
11640 (xmlLocationSetPtr)res->user;
11641 for (j=0; j<rloc->locNr; j++) {
11642 range = xmlXPtrNewRange(
11643 oldlocset->locTab[i]->user,
11644 oldlocset->locTab[i]->index,
11645 rloc->locTab[j]->user2,
11646 rloc->locTab[j]->index2);
11647 if (range != NULL) {
11648 xmlXPtrLocationSetAdd(newlocset, range);
11649 }
11650 }
11651 } else {
11652 range = xmlXPtrNewRangeNodeObject(
11653 (xmlNodePtr)oldlocset->locTab[i]->user, res);
11654 if (range != NULL) {
11655 xmlXPtrLocationSetAdd(newlocset,range);
11656 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011657 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011658
Daniel Veillardf06307e2001-07-03 10:35:50 +000011659 /*
11660 * Cleanup
11661 */
11662 if (res != NULL)
11663 xmlXPathFreeObject(res);
11664 if (ctxt->value == tmp) {
11665 res = valuePop(ctxt);
11666 xmlXPathFreeObject(res);
11667 }
11668
11669 ctxt->context->node = NULL;
11670 }
William M. Brack72ee48d2003-12-30 08:30:19 +000011671 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000011672 CHECK_TYPE0(XPATH_NODESET);
11673 obj = valuePop(ctxt);
11674 oldset = obj->nodesetval;
11675 ctxt->context->node = NULL;
11676
11677 newlocset = xmlXPtrLocationSetCreate(NULL);
11678
11679 if (oldset != NULL) {
11680 for (i = 0; i < oldset->nodeNr; i++) {
11681 /*
11682 * Run the evaluation with a node list made of a single item
11683 * in the nodeset.
11684 */
11685 ctxt->context->node = oldset->nodeTab[i];
11686 tmp = xmlXPathNewNodeSet(ctxt->context->node);
11687 valuePush(ctxt, tmp);
11688
11689 if (op->ch2 != -1)
11690 total +=
11691 xmlXPathCompOpEval(ctxt,
11692 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000011693 if (ctxt->error != XPATH_EXPRESSION_OK) {
11694 xmlXPathFreeObject(obj);
11695 return(0);
11696 }
William M. Brack08171912003-12-29 02:52:11 +000011697
William M. Brack08171912003-12-29 02:52:11 +000011698 res = valuePop(ctxt);
11699 range =
11700 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
11701 res);
11702 if (range != NULL) {
11703 xmlXPtrLocationSetAdd(newlocset, range);
11704 }
11705
11706 /*
11707 * Cleanup
11708 */
11709 if (res != NULL)
11710 xmlXPathFreeObject(res);
11711 if (ctxt->value == tmp) {
11712 res = valuePop(ctxt);
11713 xmlXPathFreeObject(res);
11714 }
11715
11716 ctxt->context->node = NULL;
11717 }
11718 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000011719 }
11720
11721 /*
11722 * The result is used as the new evaluation set.
11723 */
11724 xmlXPathFreeObject(obj);
11725 ctxt->context->node = NULL;
11726 ctxt->context->contextSize = -1;
11727 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000011728 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000011729 return (total);
11730 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011731#endif /* LIBXML_XPTR_ENABLED */
11732 }
11733 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000011734 "XPath: unknown precompiled operation %d\n", op->op);
11735 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011736}
11737
Daniel Veillard56de87e2005-02-16 00:22:29 +000011738#ifdef XPATH_STREAMING
11739/**
11740 * xmlXPathRunStreamEval:
11741 * @ctxt: the XPath parser context with the compiled expression
11742 *
11743 * Evaluate the Precompiled Streamable XPath expression in the given context.
11744 */
11745static xmlXPathObjectPtr
11746xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011747 int max_depth, min_depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011748 int from_root;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011749 int ret, depth;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011750#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11751 int eval_all_nodes;
11752#endif
William M. Brack12d37ab2005-02-21 13:54:07 +000011753 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011754 xmlXPathObjectPtr retval;
11755 xmlStreamCtxtPtr patstream;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011756
11757 int nb_nodes = 0;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011758
11759 if ((ctxt == NULL) || (comp == NULL))
11760 return(NULL);
11761 max_depth = xmlPatternMaxDepth(comp);
11762 if (max_depth == -1)
11763 return(NULL);
11764 if (max_depth == -2)
11765 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011766 min_depth = xmlPatternMinDepth(comp);
11767 if (min_depth == -1)
11768 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011769 from_root = xmlPatternFromRoot(comp);
11770 if (from_root < 0)
11771 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011772#if 0
11773 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11774#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011775
11776 retval = xmlXPathNewNodeSet(NULL);
11777 if (retval == NULL)
11778 return(NULL);
11779
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011780 /*
11781 * handle the special cases of / amd . being matched
11782 */
11783 if (min_depth == 0) {
11784 if (from_root) {
11785 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11786 } else {
11787 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11788 }
11789 }
11790 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011791 return(retval);
11792 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011793
Daniel Veillard56de87e2005-02-16 00:22:29 +000011794 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011795 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011796 } else if (ctxt->node != NULL) {
11797 switch (ctxt->node->type) {
11798 case XML_ELEMENT_NODE:
11799 case XML_DOCUMENT_NODE:
11800 case XML_DOCUMENT_FRAG_NODE:
11801 case XML_HTML_DOCUMENT_NODE:
11802#ifdef LIBXML_DOCB_ENABLED
11803 case XML_DOCB_DOCUMENT_NODE:
11804#endif
11805 cur = ctxt->node;
11806 break;
11807 case XML_ATTRIBUTE_NODE:
11808 case XML_TEXT_NODE:
11809 case XML_CDATA_SECTION_NODE:
11810 case XML_ENTITY_REF_NODE:
11811 case XML_ENTITY_NODE:
11812 case XML_PI_NODE:
11813 case XML_COMMENT_NODE:
11814 case XML_NOTATION_NODE:
11815 case XML_DTD_NODE:
11816 case XML_DOCUMENT_TYPE_NODE:
11817 case XML_ELEMENT_DECL:
11818 case XML_ATTRIBUTE_DECL:
11819 case XML_ENTITY_DECL:
11820 case XML_NAMESPACE_DECL:
11821 case XML_XINCLUDE_START:
11822 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011823 break;
11824 }
11825 limit = cur;
11826 }
11827 if (cur == NULL)
11828 return(retval);
11829
11830 patstream = xmlPatternGetStreamCtxt(comp);
11831 if (patstream == NULL) {
11832 return(retval);
11833 }
11834
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011835#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11836 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11837#endif
11838
Daniel Veillard56de87e2005-02-16 00:22:29 +000011839 if (from_root) {
11840 ret = xmlStreamPush(patstream, NULL, NULL);
11841 if (ret < 0) {
11842 } else if (ret == 1) {
11843 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11844 }
11845 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011846 depth = 0;
11847 goto scan_children;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011848next_node:
Daniel Veillardd3ff7ef2006-02-27 19:43:17 +000011849 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011850 nb_nodes++;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011851
11852 switch (cur->type) {
11853 case XML_ELEMENT_NODE:
11854#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11855 case XML_TEXT_NODE:
11856 case XML_CDATA_SECTION_NODE:
11857 case XML_COMMENT_NODE:
11858 case XML_PI_NODE:
11859#endif
11860 if (cur->type == XML_ELEMENT_NODE) {
11861 ret = xmlStreamPush(patstream, cur->name,
Daniel Veillard56de87e2005-02-16 00:22:29 +000011862 (cur->ns ? cur->ns->href : NULL));
William M. Brackfbb619f2005-06-06 13:49:18 +000011863 }
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011864#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11865 else if (eval_all_nodes)
11866 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11867 else
11868 break;
11869#endif
11870
11871 if (ret < 0) {
11872 /* NOP. */
11873 } else if (ret == 1) {
11874 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11875 }
11876 if ((cur->children == NULL) || (depth >= max_depth)) {
11877 ret = xmlStreamPop(patstream);
11878 while (cur->next != NULL) {
11879 cur = cur->next;
11880 if ((cur->type != XML_ENTITY_DECL) &&
11881 (cur->type != XML_DTD_NODE))
11882 goto next_node;
11883 }
11884 }
11885 default:
11886 break;
11887 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011888
11889scan_children:
11890 if ((cur->children != NULL) && (depth < max_depth)) {
11891 /*
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011892 * Do not descend on entities declarations
Daniel Veillard56de87e2005-02-16 00:22:29 +000011893 */
11894 if (cur->children->type != XML_ENTITY_DECL) {
11895 cur = cur->children;
11896 depth++;
11897 /*
11898 * Skip DTDs
11899 */
11900 if (cur->type != XML_DTD_NODE)
11901 continue;
11902 }
11903 }
11904
11905 if (cur == limit)
11906 break;
11907
11908 while (cur->next != NULL) {
11909 cur = cur->next;
11910 if ((cur->type != XML_ENTITY_DECL) &&
11911 (cur->type != XML_DTD_NODE))
11912 goto next_node;
11913 }
11914
11915 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011916 cur = cur->parent;
11917 depth--;
11918 if ((cur == NULL) || (cur == limit))
11919 goto done;
Kasimier T. Buchcik97258712006-01-05 12:30:43 +000011920 if (cur->type == XML_ELEMENT_NODE) {
11921 ret = xmlStreamPop(patstream);
11922 }
11923#ifdef XP_PATTERN_TO_ANY_NODE_ENABLED
11924 else if ((eval_all_nodes) &&
11925 ((cur->type == XML_TEXT_NODE) ||
11926 (cur->type == XML_CDATA_SECTION_NODE) ||
11927 (cur->type == XML_COMMENT_NODE) ||
11928 (cur->type == XML_PI_NODE)))
11929 {
11930 ret = xmlStreamPop(patstream);
11931 }
11932#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011933 if (cur->next != NULL) {
11934 cur = cur->next;
11935 break;
11936 }
11937 } while (cur != NULL);
11938
11939 } while ((cur != NULL) && (depth >= 0));
11940done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011941#if 0
11942 printf("stream eval: checked %d nodes selected %d\n",
11943 nb_nodes, retval->nodesetval->nodeNr);
11944#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011945 xmlFreeStreamCtxt(patstream);
11946 return(retval);
11947}
11948#endif /* XPATH_STREAMING */
11949
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011950/**
11951 * xmlXPathRunEval:
11952 * @ctxt: the XPath parser context with the compiled expression
11953 *
11954 * Evaluate the Precompiled XPath expression in the given context.
11955 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011956static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011957xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11958 xmlXPathCompExprPtr comp;
11959
11960 if ((ctxt == NULL) || (ctxt->comp == NULL))
11961 return;
11962
11963 if (ctxt->valueTab == NULL) {
11964 /* Allocate the value stack */
11965 ctxt->valueTab = (xmlXPathObjectPtr *)
11966 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11967 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011968 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011969 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011970 }
11971 ctxt->valueNr = 0;
11972 ctxt->valueMax = 10;
11973 ctxt->value = NULL;
11974 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011975#ifdef XPATH_STREAMING
11976 if (ctxt->comp->stream) {
11977 xmlXPathObjectPtr ret;
11978 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11979 if (ret != NULL) {
11980 valuePush(ctxt, ret);
11981 return;
11982 }
11983 }
11984#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011985 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011986 if(comp->last < 0) {
11987 xmlGenericError(xmlGenericErrorContext,
11988 "xmlXPathRunEval: last is less than zero\n");
11989 return;
11990 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011991 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11992}
11993
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011994/************************************************************************
11995 * *
11996 * Public interfaces *
11997 * *
11998 ************************************************************************/
11999
12000/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012001 * xmlXPathEvalPredicate:
12002 * @ctxt: the XPath context
12003 * @res: the Predicate Expression evaluation result
12004 *
12005 * Evaluate a predicate result for the current node.
12006 * A PredicateExpr is evaluated by evaluating the Expr and converting
12007 * the result to a boolean. If the result is a number, the result will
12008 * be converted to true if the number is equal to the position of the
12009 * context node in the context node list (as returned by the position
12010 * function) and will be converted to false otherwise; if the result
12011 * is not a number, then the result will be converted as if by a call
12012 * to the boolean function.
12013 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012014 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012015 */
12016int
12017xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000012018 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012019 switch (res->type) {
12020 case XPATH_BOOLEAN:
12021 return(res->boolval);
12022 case XPATH_NUMBER:
12023 return(res->floatval == ctxt->proximityPosition);
12024 case XPATH_NODESET:
12025 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000012026 if (res->nodesetval == NULL)
12027 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000012028 return(res->nodesetval->nodeNr != 0);
12029 case XPATH_STRING:
12030 return((res->stringval != NULL) &&
12031 (xmlStrlen(res->stringval) != 0));
12032 default:
12033 STRANGE
12034 }
12035 return(0);
12036}
12037
12038/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012039 * xmlXPathEvaluatePredicateResult:
12040 * @ctxt: the XPath Parser context
12041 * @res: the Predicate Expression evaluation result
12042 *
12043 * Evaluate a predicate result for the current node.
12044 * A PredicateExpr is evaluated by evaluating the Expr and converting
12045 * the result to a boolean. If the result is a number, the result will
12046 * be converted to true if the number is equal to the position of the
12047 * context node in the context node list (as returned by the position
12048 * function) and will be converted to false otherwise; if the result
12049 * is not a number, then the result will be converted as if by a call
12050 * to the boolean function.
12051 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012052 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012053 */
12054int
12055xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12056 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000012057 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012058 switch (res->type) {
12059 case XPATH_BOOLEAN:
12060 return(res->boolval);
12061 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000012062#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000012063 return((res->floatval == ctxt->context->proximityPosition) &&
12064 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000012065#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012066 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000012067#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012068 case XPATH_NODESET:
12069 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000012070 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000012071 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012072 return(res->nodesetval->nodeNr != 0);
12073 case XPATH_STRING:
12074 return((res->stringval != NULL) &&
12075 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000012076#ifdef LIBXML_XPTR_ENABLED
12077 case XPATH_LOCATIONSET:{
12078 xmlLocationSetPtr ptr = res->user;
12079 if (ptr == NULL)
12080 return(0);
12081 return (ptr->locNr != 0);
12082 }
12083#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012084 default:
12085 STRANGE
12086 }
12087 return(0);
12088}
12089
Daniel Veillard56de87e2005-02-16 00:22:29 +000012090#ifdef XPATH_STREAMING
12091/**
12092 * xmlXPathTryStreamCompile:
12093 * @ctxt: an XPath context
12094 * @str: the XPath expression
12095 *
12096 * Try to compile the XPath expression as a streamable subset.
12097 *
12098 * Returns the compiled expression or NULL if failed to compile.
12099 */
12100static xmlXPathCompExprPtr
12101xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12102 /*
12103 * Optimization: use streaming patterns when the XPath expression can
12104 * be compiled to a stream lookup
12105 */
12106 xmlPatternPtr stream;
12107 xmlXPathCompExprPtr comp;
12108 xmlDictPtr dict = NULL;
12109 const xmlChar **namespaces = NULL;
12110 xmlNsPtr ns;
12111 int i, j;
12112
12113 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12114 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000012115 const xmlChar *tmp;
12116
12117 /*
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000012118 * We don't try to handle expressions using the verbose axis
12119 * specifiers ("::"), just the simplied form at this point.
12120 * Additionally, if there is no list of namespaces available and
12121 * there's a ":" in the expression, indicating a prefixed QName,
12122 * then we won't try to compile either. xmlPatterncompile() needs
12123 * to have a list of namespaces at compilation time in order to
12124 * compile prefixed name tests.
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000012125 */
12126 tmp = xmlStrchr(str, ':');
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000012127 if ((tmp != NULL) &&
12128 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12129 return(NULL);
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000012130
Daniel Veillard56de87e2005-02-16 00:22:29 +000012131 if (ctxt != NULL) {
12132 dict = ctxt->dict;
12133 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000012134 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000012135 if (namespaces == NULL) {
12136 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
12137 return(NULL);
12138 }
12139 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12140 ns = ctxt->namespaces[j];
12141 namespaces[i++] = ns->href;
12142 namespaces[i++] = ns->prefix;
12143 }
12144 namespaces[i++] = NULL;
12145 namespaces[i++] = NULL;
12146 }
12147 }
12148
William M. Brackea152c02005-06-09 18:12:28 +000012149 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
12150 &namespaces[0]);
Kasimier T. Buchcik6ed2eb42006-05-16 15:13:37 +000012151 if (namespaces != NULL) {
12152 xmlFree((xmlChar **)namespaces);
12153 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000012154 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12155 comp = xmlXPathNewCompExpr();
12156 if (comp == NULL) {
12157 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
12158 return(NULL);
12159 }
12160 comp->stream = stream;
12161 comp->dict = dict;
12162 if (comp->dict)
12163 xmlDictReference(comp->dict);
12164 return(comp);
12165 }
12166 xmlFreePattern(stream);
12167 }
12168 return(NULL);
12169}
12170#endif /* XPATH_STREAMING */
12171
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012172/**
Daniel Veillard4773df22004-01-23 13:15:13 +000012173 * xmlXPathCtxtCompile:
12174 * @ctxt: an XPath context
12175 * @str: the XPath expression
12176 *
12177 * Compile an XPath expression
12178 *
12179 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12180 * the caller has to free the object.
12181 */
12182xmlXPathCompExprPtr
12183xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12184 xmlXPathParserContextPtr pctxt;
12185 xmlXPathCompExprPtr comp;
12186
Daniel Veillard56de87e2005-02-16 00:22:29 +000012187#ifdef XPATH_STREAMING
12188 comp = xmlXPathTryStreamCompile(ctxt, str);
12189 if (comp != NULL)
12190 return(comp);
12191#endif
12192
Daniel Veillard4773df22004-01-23 13:15:13 +000012193 xmlXPathInit();
12194
12195 pctxt = xmlXPathNewParserContext(str, ctxt);
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012196 xmlXPathCompileExpr(pctxt, 1);
Daniel Veillard4773df22004-01-23 13:15:13 +000012197
12198 if( pctxt->error != XPATH_EXPRESSION_OK )
12199 {
12200 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000012201 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000012202 }
12203
12204 if (*pctxt->cur != 0) {
12205 /*
12206 * aleksey: in some cases this line prints *second* error message
12207 * (see bug #78858) and probably this should be fixed.
12208 * However, we are not sure that all error messages are printed
12209 * out in other places. It's not critical so we leave it as-is for now
12210 */
12211 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12212 comp = NULL;
12213 } else {
12214 comp = pctxt->comp;
12215 pctxt->comp = NULL;
12216 }
12217 xmlXPathFreeParserContext(pctxt);
12218 if (comp != NULL) {
12219 comp->expr = xmlStrdup(str);
12220#ifdef DEBUG_EVAL_COUNTS
12221 comp->string = xmlStrdup(str);
12222 comp->nb = 0;
12223#endif
12224 }
12225 return(comp);
12226}
12227
12228/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012229 * xmlXPathCompile:
12230 * @str: the XPath expression
12231 *
12232 * Compile an XPath expression
12233 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000012234 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012235 * the caller has to free the object.
12236 */
12237xmlXPathCompExprPtr
12238xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000012239 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012240}
12241
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012242/**
12243 * xmlXPathCompiledEval:
12244 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000012245 * @ctx: the XPath context
12246 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012247 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000012248 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012249 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000012250 * the caller has to free the object.
12251 */
12252xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012253xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000012254 xmlXPathParserContextPtr ctxt;
12255 xmlXPathObjectPtr res, tmp, init = NULL;
12256 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000012257#ifndef LIBXML_THREAD_ENABLED
12258 static int reentance = 0;
12259#endif
Owen Taylor3473f882001-02-23 17:55:21 +000012260
William M. Brackf13f77f2004-11-12 16:03:48 +000012261 CHECK_CTXT(ctx)
12262
12263 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012264 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000012265 xmlXPathInit();
12266
Daniel Veillard81463942001-10-16 12:34:39 +000012267#ifndef LIBXML_THREAD_ENABLED
12268 reentance++;
12269 if (reentance > 1)
12270 xmlXPathDisableOptimizer = 1;
12271#endif
12272
Daniel Veillardf06307e2001-07-03 10:35:50 +000012273#ifdef DEBUG_EVAL_COUNTS
12274 comp->nb++;
12275 if ((comp->string != NULL) && (comp->nb > 100)) {
12276 fprintf(stderr, "100 x %s\n", comp->string);
12277 comp->nb = 0;
12278 }
12279#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012280 ctxt = xmlXPathCompParserContext(comp, ctx);
12281 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000012282
12283 if (ctxt->value == NULL) {
12284 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012285 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000012286 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000012287 } else {
12288 res = valuePop(ctxt);
12289 }
12290
Daniel Veillardf06307e2001-07-03 10:35:50 +000012291
Owen Taylor3473f882001-02-23 17:55:21 +000012292 do {
12293 tmp = valuePop(ctxt);
12294 if (tmp != NULL) {
12295 if (tmp != init)
12296 stack++;
12297 xmlXPathFreeObject(tmp);
12298 }
12299 } while (tmp != NULL);
12300 if ((stack != 0) && (res != NULL)) {
12301 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012302 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000012303 stack);
12304 }
12305 if (ctxt->error != XPATH_EXPRESSION_OK) {
12306 xmlXPathFreeObject(res);
12307 res = NULL;
12308 }
12309
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012310
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012311 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012312 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000012313#ifndef LIBXML_THREAD_ENABLED
12314 reentance--;
12315#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012316 return(res);
12317}
12318
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012319/**
12320 * xmlXPathEvalExpr:
12321 * @ctxt: the XPath Parser context
12322 *
12323 * Parse and evaluate an XPath expression in the given context,
12324 * then push the result on the context stack
12325 */
12326void
12327xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000012328#ifdef XPATH_STREAMING
12329 xmlXPathCompExprPtr comp;
12330#endif
12331
Daniel Veillarda82b1822004-11-08 16:24:57 +000012332 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000012333
12334#ifdef XPATH_STREAMING
12335 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12336 if (comp != NULL) {
12337 if (ctxt->comp != NULL)
12338 xmlXPathFreeCompExpr(ctxt->comp);
12339 ctxt->comp = comp;
12340 if (ctxt->cur != NULL)
12341 while (*ctxt->cur != 0) ctxt->cur++;
12342 } else
12343#endif
12344 {
Kasimier T. Buchcik5691f432006-05-22 15:19:55 +000012345 xmlXPathCompileExpr(ctxt, 1);
Daniel Veillard56de87e2005-02-16 00:22:29 +000012346 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000012347 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000012348 xmlXPathRunEval(ctxt);
12349}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012350
12351/**
12352 * xmlXPathEval:
12353 * @str: the XPath expression
12354 * @ctx: the XPath context
12355 *
12356 * Evaluate the XPath Location Path in the given context.
12357 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000012358 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012359 * the caller has to free the object.
12360 */
12361xmlXPathObjectPtr
12362xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
12363 xmlXPathParserContextPtr ctxt;
12364 xmlXPathObjectPtr res, tmp, init = NULL;
12365 int stack = 0;
12366
William M. Brackf13f77f2004-11-12 16:03:48 +000012367 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012368
William M. Brackf13f77f2004-11-12 16:03:48 +000012369 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012370
12371 ctxt = xmlXPathNewParserContext(str, ctx);
12372 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012373
12374 if (ctxt->value == NULL) {
12375 xmlGenericError(xmlGenericErrorContext,
12376 "xmlXPathEval: evaluation failed\n");
12377 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000012378 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
12379#ifdef XPATH_STREAMING
12380 && (ctxt->comp->stream == NULL)
12381#endif
12382 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000012383 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12384 res = NULL;
12385 } else {
12386 res = valuePop(ctxt);
12387 }
12388
12389 do {
12390 tmp = valuePop(ctxt);
12391 if (tmp != NULL) {
12392 if (tmp != init)
12393 stack++;
12394 xmlXPathFreeObject(tmp);
12395 }
12396 } while (tmp != NULL);
12397 if ((stack != 0) && (res != NULL)) {
12398 xmlGenericError(xmlGenericErrorContext,
12399 "xmlXPathEval: %d object left on the stack\n",
12400 stack);
12401 }
12402 if (ctxt->error != XPATH_EXPRESSION_OK) {
12403 xmlXPathFreeObject(res);
12404 res = NULL;
12405 }
12406
Owen Taylor3473f882001-02-23 17:55:21 +000012407 xmlXPathFreeParserContext(ctxt);
12408 return(res);
12409}
12410
12411/**
12412 * xmlXPathEvalExpression:
12413 * @str: the XPath expression
12414 * @ctxt: the XPath context
12415 *
12416 * Evaluate the XPath expression in the given context.
12417 *
12418 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12419 * the caller has to free the object.
12420 */
12421xmlXPathObjectPtr
12422xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
12423 xmlXPathParserContextPtr pctxt;
12424 xmlXPathObjectPtr res, tmp;
12425 int stack = 0;
12426
William M. Brackf13f77f2004-11-12 16:03:48 +000012427 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000012428
William M. Brackf13f77f2004-11-12 16:03:48 +000012429 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000012430
12431 pctxt = xmlXPathNewParserContext(str, ctxt);
12432 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000012433
12434 if (*pctxt->cur != 0) {
12435 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12436 res = NULL;
12437 } else {
12438 res = valuePop(pctxt);
12439 }
12440 do {
12441 tmp = valuePop(pctxt);
12442 if (tmp != NULL) {
12443 xmlXPathFreeObject(tmp);
12444 stack++;
12445 }
12446 } while (tmp != NULL);
12447 if ((stack != 0) && (res != NULL)) {
12448 xmlGenericError(xmlGenericErrorContext,
12449 "xmlXPathEvalExpression: %d object left on the stack\n",
12450 stack);
12451 }
12452 xmlXPathFreeParserContext(pctxt);
12453 return(res);
12454}
12455
Daniel Veillard42766c02002-08-22 20:52:17 +000012456/************************************************************************
12457 * *
12458 * Extra functions not pertaining to the XPath spec *
12459 * *
12460 ************************************************************************/
12461/**
12462 * xmlXPathEscapeUriFunction:
12463 * @ctxt: the XPath Parser context
12464 * @nargs: the number of arguments
12465 *
12466 * Implement the escape-uri() XPath function
12467 * string escape-uri(string $str, bool $escape-reserved)
12468 *
12469 * This function applies the URI escaping rules defined in section 2 of [RFC
12470 * 2396] to the string supplied as $uri-part, which typically represents all
12471 * or part of a URI. The effect of the function is to replace any special
12472 * character in the string by an escape sequence of the form %xx%yy...,
12473 * where xxyy... is the hexadecimal representation of the octets used to
12474 * represent the character in UTF-8.
12475 *
12476 * The set of characters that are escaped depends on the setting of the
12477 * boolean argument $escape-reserved.
12478 *
12479 * If $escape-reserved is true, all characters are escaped other than lower
12480 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12481 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12482 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12483 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12484 * A-F).
12485 *
12486 * If $escape-reserved is false, the behavior differs in that characters
12487 * referred to in [RFC 2396] as reserved characters are not escaped. These
12488 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12489 *
12490 * [RFC 2396] does not define whether escaped URIs should use lower case or
12491 * upper case for hexadecimal digits. To ensure that escaped URIs can be
12492 * compared using string comparison functions, this function must always use
12493 * the upper-case letters A-F.
12494 *
12495 * Generally, $escape-reserved should be set to true when escaping a string
12496 * that is to form a single part of a URI, and to false when escaping an
12497 * entire URI or URI reference.
12498 *
12499 * In the case of non-ascii characters, the string is encoded according to
12500 * utf-8 and then converted according to RFC 2396.
12501 *
12502 * Examples
12503 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12504 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12505 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12506 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12507 *
12508 */
Daniel Veillard118aed72002-09-24 14:13:13 +000012509static void
Daniel Veillard42766c02002-08-22 20:52:17 +000012510xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12511 xmlXPathObjectPtr str;
12512 int escape_reserved;
12513 xmlBufferPtr target;
12514 xmlChar *cptr;
12515 xmlChar escape[4];
12516
12517 CHECK_ARITY(2);
12518
12519 escape_reserved = xmlXPathPopBoolean(ctxt);
12520
12521 CAST_TO_STRING;
12522 str = valuePop(ctxt);
12523
12524 target = xmlBufferCreate();
12525
12526 escape[0] = '%';
12527 escape[3] = 0;
12528
12529 if (target) {
12530 for (cptr = str->stringval; *cptr; cptr++) {
12531 if ((*cptr >= 'A' && *cptr <= 'Z') ||
12532 (*cptr >= 'a' && *cptr <= 'z') ||
12533 (*cptr >= '0' && *cptr <= '9') ||
12534 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
12535 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
12536 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12537 (*cptr == '%' &&
12538 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12539 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12540 (cptr[1] >= '0' && cptr[1] <= '9')) &&
12541 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12542 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12543 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12544 (!escape_reserved &&
12545 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12546 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12547 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12548 *cptr == ','))) {
12549 xmlBufferAdd(target, cptr, 1);
12550 } else {
12551 if ((*cptr >> 4) < 10)
12552 escape[1] = '0' + (*cptr >> 4);
12553 else
12554 escape[1] = 'A' - 10 + (*cptr >> 4);
12555 if ((*cptr & 0xF) < 10)
12556 escape[2] = '0' + (*cptr & 0xF);
12557 else
12558 escape[2] = 'A' - 10 + (*cptr & 0xF);
12559
12560 xmlBufferAdd(target, &escape[0], 3);
12561 }
12562 }
12563 }
12564 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
12565 xmlBufferFree(target);
12566 xmlXPathFreeObject(str);
12567}
12568
Owen Taylor3473f882001-02-23 17:55:21 +000012569/**
12570 * xmlXPathRegisterAllFunctions:
12571 * @ctxt: the XPath context
12572 *
12573 * Registers all default XPath functions in this context
12574 */
12575void
12576xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12577{
12578 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12579 xmlXPathBooleanFunction);
12580 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12581 xmlXPathCeilingFunction);
12582 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12583 xmlXPathCountFunction);
12584 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12585 xmlXPathConcatFunction);
12586 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12587 xmlXPathContainsFunction);
12588 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12589 xmlXPathIdFunction);
12590 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12591 xmlXPathFalseFunction);
12592 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12593 xmlXPathFloorFunction);
12594 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12595 xmlXPathLastFunction);
12596 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12597 xmlXPathLangFunction);
12598 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12599 xmlXPathLocalNameFunction);
12600 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12601 xmlXPathNotFunction);
12602 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12603 xmlXPathNameFunction);
12604 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12605 xmlXPathNamespaceURIFunction);
12606 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12607 xmlXPathNormalizeFunction);
12608 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12609 xmlXPathNumberFunction);
12610 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
12611 xmlXPathPositionFunction);
12612 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
12613 xmlXPathRoundFunction);
12614 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
12615 xmlXPathStringFunction);
12616 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
12617 xmlXPathStringLengthFunction);
12618 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
12619 xmlXPathStartsWithFunction);
12620 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
12621 xmlXPathSubstringFunction);
12622 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
12623 xmlXPathSubstringBeforeFunction);
12624 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
12625 xmlXPathSubstringAfterFunction);
12626 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
12627 xmlXPathSumFunction);
12628 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
12629 xmlXPathTrueFunction);
12630 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
12631 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000012632
12633 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
12634 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
12635 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000012636}
12637
12638#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000012639#define bottom_xpath
12640#include "elfgcchack.h"