blob: 162f6e3aa8577b0dbe7914be7a093880a346ab95 [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/*
68 * TODO:
69 * There are a few spots where some tests are done which depend upon ascii
70 * data. These should be enhanced for full UTF8 support (see particularly
71 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
72 */
73
William M. Brack21e4ef22005-01-02 09:53:13 +000074#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000075/************************************************************************
76 * *
77 * Floating point stuff *
78 * *
79 ************************************************************************/
80
Daniel Veillardc0631a62001-09-20 13:56:06 +000081#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000082#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000083#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000084#include "trionan.c"
85
Owen Taylor3473f882001-02-23 17:55:21 +000086/*
Owen Taylor3473f882001-02-23 17:55:21 +000087 * The lack of portability of this section of the libc is annoying !
88 */
89double xmlXPathNAN = 0;
90double xmlXPathPINF = 1;
91double xmlXPathNINF = -1;
Daniel Veillard24505b02005-07-28 23:49:35 +000092static double xmlXPathNZERO = 0; /* not exported from headers */
Daniel Veillard20ee8c02001-10-05 09:18:14 +000093static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000094
Owen Taylor3473f882001-02-23 17:55:21 +000095/**
96 * xmlXPathInit:
97 *
98 * Initialize the XPath environment
99 */
100void
101xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000102 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +0000103
Bjorn Reese45029602001-08-21 09:23:53 +0000104 xmlXPathPINF = trio_pinf();
105 xmlXPathNINF = trio_ninf();
106 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000107 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000108
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000109 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000110}
111
Daniel Veillardcda96922001-08-21 10:56:31 +0000112/**
113 * xmlXPathIsNaN:
114 * @val: a double value
115 *
116 * Provides a portable isnan() function to detect whether a double
117 * is a NotaNumber. Based on trio code
118 * http://sourceforge.net/projects/ctrio/
119 *
120 * Returns 1 if the value is a NaN, 0 otherwise
121 */
122int
123xmlXPathIsNaN(double val) {
124 return(trio_isnan(val));
125}
126
127/**
128 * xmlXPathIsInf:
129 * @val: a double value
130 *
131 * Provides a portable isinf() function to detect whether a double
132 * is a +Infinite or -Infinite. Based on trio code
133 * http://sourceforge.net/projects/ctrio/
134 *
135 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
136 */
137int
138xmlXPathIsInf(double val) {
139 return(trio_isinf(val));
140}
141
Daniel Veillard4432df22003-09-28 18:58:27 +0000142#endif /* SCHEMAS or XPATH */
143#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000144/**
145 * xmlXPathGetSign:
146 * @val: a double value
147 *
148 * Provides a portable function to detect the sign of a double
149 * Modified from trio code
150 * http://sourceforge.net/projects/ctrio/
151 *
152 * Returns 1 if the value is Negative, 0 if positive
153 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000154static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000155xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000156 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000157}
158
159
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000160/*
161 * TODO: when compatibility allows remove all "fake node libxslt" strings
162 * the test should just be name[0] = ' '
163 */
164/* #define DEBUG */
165/* #define DEBUG_STEP */
166/* #define DEBUG_STEP_NTH */
167/* #define DEBUG_EXPR */
168/* #define DEBUG_EVAL_COUNTS */
169
170static xmlNs xmlXPathXMLNamespaceStruct = {
171 NULL,
172 XML_NAMESPACE_DECL,
173 XML_XML_NAMESPACE,
174 BAD_CAST "xml",
175 NULL
176};
177static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
178#ifndef LIBXML_THREAD_ENABLED
179/*
180 * Optimizer is disabled only when threaded apps are detected while
181 * the library ain't compiled for thread safety.
182 */
183static int xmlXPathDisableOptimizer = 0;
184#endif
185
Owen Taylor3473f882001-02-23 17:55:21 +0000186/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000187 * *
188 * Error handling routines *
189 * *
190 ************************************************************************/
191
Daniel Veillard24505b02005-07-28 23:49:35 +0000192/**
193 * XP_ERRORNULL:
194 * @X: the error code
195 *
196 * Macro to raise an XPath error and return NULL.
197 */
198#define XP_ERRORNULL(X) \
199 { xmlXPathErr(ctxt, X); return(NULL); }
200
William M. Brack08171912003-12-29 02:52:11 +0000201/*
202 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
203 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000204static const char *xmlXPathErrorMessages[] = {
205 "Ok\n",
206 "Number encoding\n",
207 "Unfinished literal\n",
208 "Start of literal\n",
209 "Expected $ for variable reference\n",
210 "Undefined variable\n",
211 "Invalid predicate\n",
212 "Invalid expression\n",
213 "Missing closing curly brace\n",
214 "Unregistered function\n",
215 "Invalid operand\n",
216 "Invalid type\n",
217 "Invalid number of arguments\n",
218 "Invalid context size\n",
219 "Invalid context position\n",
220 "Memory allocation error\n",
221 "Syntax error\n",
222 "Resource error\n",
223 "Sub resource error\n",
224 "Undefined namespace prefix\n",
225 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000226 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000227 "Invalid or incomplete context\n",
228 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000229};
William M. Brackcd65bc92005-01-06 09:39:18 +0000230#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
231 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000232/**
233 * xmlXPathErrMemory:
234 * @ctxt: an XPath context
235 * @extra: extra informations
236 *
237 * Handle a redefinition of attribute error
238 */
239static void
240xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
241{
242 if (ctxt != NULL) {
243 if (extra) {
244 xmlChar buf[200];
245
246 xmlStrPrintf(buf, 200,
247 BAD_CAST "Memory allocation failed : %s\n",
248 extra);
249 ctxt->lastError.message = (char *) xmlStrdup(buf);
250 } else {
251 ctxt->lastError.message = (char *)
252 xmlStrdup(BAD_CAST "Memory allocation failed\n");
253 }
254 ctxt->lastError.domain = XML_FROM_XPATH;
255 ctxt->lastError.code = XML_ERR_NO_MEMORY;
256 if (ctxt->error != NULL)
257 ctxt->error(ctxt->userData, &ctxt->lastError);
258 } else {
259 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000260 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000261 NULL, NULL, XML_FROM_XPATH,
262 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
263 extra, NULL, NULL, 0, 0,
264 "Memory allocation failed : %s\n", extra);
265 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000266 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000267 NULL, NULL, XML_FROM_XPATH,
268 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
269 NULL, NULL, NULL, 0, 0,
270 "Memory allocation failed\n");
271 }
272}
273
274/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000275 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000276 * @ctxt: an XPath parser context
277 * @extra: extra informations
278 *
279 * Handle a redefinition of attribute error
280 */
281static void
282xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
283{
284 ctxt->error = XPATH_MEMORY_ERROR;
285 if (ctxt == NULL)
286 xmlXPathErrMemory(NULL, extra);
287 else
288 xmlXPathErrMemory(ctxt->context, extra);
289}
290
291/**
292 * xmlXPathErr:
293 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000294 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000295 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000296 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000297 */
298void
299xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
300{
William M. Brackcd65bc92005-01-06 09:39:18 +0000301 if ((error < 0) || (error > MAXERRNO))
302 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000303 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000304 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000305 NULL, NULL, XML_FROM_XPATH,
306 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
307 XML_ERR_ERROR, NULL, 0,
308 NULL, NULL, NULL, 0, 0,
309 xmlXPathErrorMessages[error]);
310 return;
311 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000312 ctxt->error = error;
313 if (ctxt->context == NULL) {
314 __xmlRaiseError(NULL, NULL, NULL,
315 NULL, NULL, XML_FROM_XPATH,
316 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
317 XML_ERR_ERROR, NULL, 0,
318 (const char *) ctxt->base, NULL, NULL,
319 ctxt->cur - ctxt->base, 0,
320 xmlXPathErrorMessages[error]);
321 return;
322 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000323 ctxt->context->lastError.domain = XML_FROM_XPATH;
324 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
325 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000326 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000327 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
328 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
329 ctxt->context->lastError.node = ctxt->context->debugNode;
330 if (ctxt->context->error != NULL) {
331 ctxt->context->error(ctxt->context->userData,
332 &ctxt->context->lastError);
333 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000334 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000335 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
336 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
337 XML_ERR_ERROR, NULL, 0,
338 (const char *) ctxt->base, NULL, NULL,
339 ctxt->cur - ctxt->base, 0,
340 xmlXPathErrorMessages[error]);
341 }
342
343}
344
345/**
346 * xmlXPatherror:
347 * @ctxt: the XPath Parser context
348 * @file: the file name
349 * @line: the line number
350 * @no: the error number
351 *
352 * Formats an error message.
353 */
354void
355xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
356 int line ATTRIBUTE_UNUSED, int no) {
357 xmlXPathErr(ctxt, no);
358}
359
360
361/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000362 * *
363 * Parser Types *
364 * *
365 ************************************************************************/
366
367/*
368 * Types are private:
369 */
370
371typedef enum {
372 XPATH_OP_END=0,
373 XPATH_OP_AND,
374 XPATH_OP_OR,
375 XPATH_OP_EQUAL,
376 XPATH_OP_CMP,
377 XPATH_OP_PLUS,
378 XPATH_OP_MULT,
379 XPATH_OP_UNION,
380 XPATH_OP_ROOT,
381 XPATH_OP_NODE,
382 XPATH_OP_RESET,
383 XPATH_OP_COLLECT,
384 XPATH_OP_VALUE,
385 XPATH_OP_VARIABLE,
386 XPATH_OP_FUNCTION,
387 XPATH_OP_ARG,
388 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000389 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000390 XPATH_OP_SORT
391#ifdef LIBXML_XPTR_ENABLED
392 ,XPATH_OP_RANGETO
393#endif
394} xmlXPathOp;
395
396typedef enum {
397 AXIS_ANCESTOR = 1,
398 AXIS_ANCESTOR_OR_SELF,
399 AXIS_ATTRIBUTE,
400 AXIS_CHILD,
401 AXIS_DESCENDANT,
402 AXIS_DESCENDANT_OR_SELF,
403 AXIS_FOLLOWING,
404 AXIS_FOLLOWING_SIBLING,
405 AXIS_NAMESPACE,
406 AXIS_PARENT,
407 AXIS_PRECEDING,
408 AXIS_PRECEDING_SIBLING,
409 AXIS_SELF
410} xmlXPathAxisVal;
411
412typedef enum {
413 NODE_TEST_NONE = 0,
414 NODE_TEST_TYPE = 1,
415 NODE_TEST_PI = 2,
416 NODE_TEST_ALL = 3,
417 NODE_TEST_NS = 4,
418 NODE_TEST_NAME = 5
419} xmlXPathTestVal;
420
421typedef enum {
422 NODE_TYPE_NODE = 0,
423 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
424 NODE_TYPE_TEXT = XML_TEXT_NODE,
425 NODE_TYPE_PI = XML_PI_NODE
426} xmlXPathTypeVal;
427
428
429typedef struct _xmlXPathStepOp xmlXPathStepOp;
430typedef xmlXPathStepOp *xmlXPathStepOpPtr;
431struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000432 xmlXPathOp op; /* The identifier of the operation */
433 int ch1; /* First child */
434 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000435 int value;
436 int value2;
437 int value3;
438 void *value4;
439 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000440 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000441 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000442};
443
444struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000445 int nbStep; /* Number of steps in this expression */
446 int maxStep; /* Maximum number of steps allocated */
447 xmlXPathStepOp *steps; /* ops for computation of this expression */
448 int last; /* index of last step in expression */
449 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000450 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000451#ifdef DEBUG_EVAL_COUNTS
452 int nb;
453 xmlChar *string;
454#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000455#ifdef XPATH_STREAMING
456 xmlPatternPtr stream;
457#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000458};
459
460/************************************************************************
461 * *
462 * Parser Type functions *
463 * *
464 ************************************************************************/
465
466/**
467 * xmlXPathNewCompExpr:
468 *
469 * Create a new Xpath component
470 *
471 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
472 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000473static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000474xmlXPathNewCompExpr(void) {
475 xmlXPathCompExprPtr cur;
476
477 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
478 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000479 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000480 return(NULL);
481 }
482 memset(cur, 0, sizeof(xmlXPathCompExpr));
483 cur->maxStep = 10;
484 cur->nbStep = 0;
485 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
486 sizeof(xmlXPathStepOp));
487 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000488 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000489 xmlFree(cur);
490 return(NULL);
491 }
492 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
493 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000494#ifdef DEBUG_EVAL_COUNTS
495 cur->nb = 0;
496#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000497 return(cur);
498}
499
500/**
501 * xmlXPathFreeCompExpr:
502 * @comp: an XPATH comp
503 *
504 * Free up the memory allocated by @comp
505 */
506void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000507xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
508{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000509 xmlXPathStepOpPtr op;
510 int i;
511
512 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000513 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000514 if (comp->dict == NULL) {
515 for (i = 0; i < comp->nbStep; i++) {
516 op = &comp->steps[i];
517 if (op->value4 != NULL) {
518 if (op->op == XPATH_OP_VALUE)
519 xmlXPathFreeObject(op->value4);
520 else
521 xmlFree(op->value4);
522 }
523 if (op->value5 != NULL)
524 xmlFree(op->value5);
525 }
526 } else {
527 for (i = 0; i < comp->nbStep; i++) {
528 op = &comp->steps[i];
529 if (op->value4 != NULL) {
530 if (op->op == XPATH_OP_VALUE)
531 xmlXPathFreeObject(op->value4);
532 }
533 }
534 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000535 }
536 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000537 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000539#ifdef DEBUG_EVAL_COUNTS
540 if (comp->string != NULL) {
541 xmlFree(comp->string);
542 }
543#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000544#ifdef XPATH_STREAMING
545 if (comp->stream != NULL) {
546 xmlFreePatternList(comp->stream);
547 }
548#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000549 if (comp->expr != NULL) {
550 xmlFree(comp->expr);
551 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000552
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000553 xmlFree(comp);
554}
555
556/**
557 * xmlXPathCompExprAdd:
558 * @comp: the compiled expression
559 * @ch1: first child index
560 * @ch2: second child index
561 * @op: an op
562 * @value: the first int value
563 * @value2: the second int value
564 * @value3: the third int value
565 * @value4: the first string value
566 * @value5: the second string value
567 *
William M. Brack08171912003-12-29 02:52:11 +0000568 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000569 *
570 * Returns -1 in case of failure, the index otherwise
571 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000572static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000573xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
574 xmlXPathOp op, int value,
575 int value2, int value3, void *value4, void *value5) {
576 if (comp->nbStep >= comp->maxStep) {
577 xmlXPathStepOp *real;
578
579 comp->maxStep *= 2;
580 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
581 comp->maxStep * sizeof(xmlXPathStepOp));
582 if (real == NULL) {
583 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000584 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000585 return(-1);
586 }
587 comp->steps = real;
588 }
589 comp->last = comp->nbStep;
590 comp->steps[comp->nbStep].ch1 = ch1;
591 comp->steps[comp->nbStep].ch2 = ch2;
592 comp->steps[comp->nbStep].op = op;
593 comp->steps[comp->nbStep].value = value;
594 comp->steps[comp->nbStep].value2 = value2;
595 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000596 if ((comp->dict != NULL) &&
597 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
598 (op == XPATH_OP_COLLECT))) {
599 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000600 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000601 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000602 xmlFree(value4);
603 } else
604 comp->steps[comp->nbStep].value4 = NULL;
605 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000606 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000607 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000608 xmlFree(value5);
609 } else
610 comp->steps[comp->nbStep].value5 = NULL;
611 } else {
612 comp->steps[comp->nbStep].value4 = value4;
613 comp->steps[comp->nbStep].value5 = value5;
614 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000615 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000616 return(comp->nbStep++);
617}
618
Daniel Veillardf06307e2001-07-03 10:35:50 +0000619/**
620 * xmlXPathCompSwap:
621 * @comp: the compiled expression
622 * @op: operation index
623 *
624 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000625 */
626static void
627xmlXPathCompSwap(xmlXPathStepOpPtr op) {
628 int tmp;
629
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000630#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000631 /*
632 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000633 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000634 * application
635 */
636 if (xmlXPathDisableOptimizer)
637 return;
638#endif
639
Daniel Veillardf06307e2001-07-03 10:35:50 +0000640 tmp = op->ch1;
641 op->ch1 = op->ch2;
642 op->ch2 = tmp;
643}
644
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000645#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
646 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
647 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000648#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
649 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
650 (op), (val), (val2), (val3), (val4), (val5))
651
652#define PUSH_LEAVE_EXPR(op, val, val2) \
653xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
654
655#define PUSH_UNARY_EXPR(op, ch, val, val2) \
656xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
657
658#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000659xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
660 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000661
662/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000663 * *
664 * Debugging related functions *
665 * *
666 ************************************************************************/
667
Owen Taylor3473f882001-02-23 17:55:21 +0000668#define STRANGE \
669 xmlGenericError(xmlGenericErrorContext, \
670 "Internal error at %s:%d\n", \
671 __FILE__, __LINE__);
672
673#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000674static void
675xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000676 int i;
677 char shift[100];
678
679 for (i = 0;((i < depth) && (i < 25));i++)
680 shift[2 * i] = shift[2 * i + 1] = ' ';
681 shift[2 * i] = shift[2 * i + 1] = 0;
682 if (cur == NULL) {
683 fprintf(output, shift);
684 fprintf(output, "Node is NULL !\n");
685 return;
686
687 }
688
689 if ((cur->type == XML_DOCUMENT_NODE) ||
690 (cur->type == XML_HTML_DOCUMENT_NODE)) {
691 fprintf(output, shift);
692 fprintf(output, " /\n");
693 } else if (cur->type == XML_ATTRIBUTE_NODE)
694 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
695 else
696 xmlDebugDumpOneNode(output, cur, depth);
697}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000698static void
699xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000700 xmlNodePtr tmp;
701 int i;
702 char shift[100];
703
704 for (i = 0;((i < depth) && (i < 25));i++)
705 shift[2 * i] = shift[2 * i + 1] = ' ';
706 shift[2 * i] = shift[2 * i + 1] = 0;
707 if (cur == NULL) {
708 fprintf(output, shift);
709 fprintf(output, "Node is NULL !\n");
710 return;
711
712 }
713
714 while (cur != NULL) {
715 tmp = cur;
716 cur = cur->next;
717 xmlDebugDumpOneNode(output, tmp, depth);
718 }
719}
Owen Taylor3473f882001-02-23 17:55:21 +0000720
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000721static void
722xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000723 int i;
724 char shift[100];
725
726 for (i = 0;((i < depth) && (i < 25));i++)
727 shift[2 * i] = shift[2 * i + 1] = ' ';
728 shift[2 * i] = shift[2 * i + 1] = 0;
729
730 if (cur == NULL) {
731 fprintf(output, shift);
732 fprintf(output, "NodeSet is NULL !\n");
733 return;
734
735 }
736
Daniel Veillard911f49a2001-04-07 15:39:35 +0000737 if (cur != NULL) {
738 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
739 for (i = 0;i < cur->nodeNr;i++) {
740 fprintf(output, shift);
741 fprintf(output, "%d", i + 1);
742 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
743 }
Owen Taylor3473f882001-02-23 17:55:21 +0000744 }
745}
746
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000747static void
748xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000749 int i;
750 char shift[100];
751
752 for (i = 0;((i < depth) && (i < 25));i++)
753 shift[2 * i] = shift[2 * i + 1] = ' ';
754 shift[2 * i] = shift[2 * i + 1] = 0;
755
756 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
757 fprintf(output, shift);
758 fprintf(output, "Value Tree is NULL !\n");
759 return;
760
761 }
762
763 fprintf(output, shift);
764 fprintf(output, "%d", i + 1);
765 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
766}
Owen Taylor3473f882001-02-23 17:55:21 +0000767#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000768static void
769xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000770 int i;
771 char shift[100];
772
773 for (i = 0;((i < depth) && (i < 25));i++)
774 shift[2 * i] = shift[2 * i + 1] = ' ';
775 shift[2 * i] = shift[2 * i + 1] = 0;
776
777 if (cur == NULL) {
778 fprintf(output, shift);
779 fprintf(output, "LocationSet is NULL !\n");
780 return;
781
782 }
783
784 for (i = 0;i < cur->locNr;i++) {
785 fprintf(output, shift);
786 fprintf(output, "%d : ", i + 1);
787 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
788 }
789}
Daniel Veillard017b1082001-06-21 11:20:21 +0000790#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000791
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000792/**
793 * xmlXPathDebugDumpObject:
794 * @output: the FILE * to dump the output
795 * @cur: the object to inspect
796 * @depth: indentation level
797 *
798 * Dump the content of the object for debugging purposes
799 */
800void
801xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000802 int i;
803 char shift[100];
804
Daniel Veillarda82b1822004-11-08 16:24:57 +0000805 if (output == NULL) return;
806
Owen Taylor3473f882001-02-23 17:55:21 +0000807 for (i = 0;((i < depth) && (i < 25));i++)
808 shift[2 * i] = shift[2 * i + 1] = ' ';
809 shift[2 * i] = shift[2 * i + 1] = 0;
810
811 fprintf(output, shift);
812
813 if (cur == NULL) {
814 fprintf(output, "Object is empty (NULL)\n");
815 return;
816 }
817 switch(cur->type) {
818 case XPATH_UNDEFINED:
819 fprintf(output, "Object is uninitialized\n");
820 break;
821 case XPATH_NODESET:
822 fprintf(output, "Object is a Node Set :\n");
823 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
824 break;
825 case XPATH_XSLT_TREE:
826 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000827 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000828 break;
829 case XPATH_BOOLEAN:
830 fprintf(output, "Object is a Boolean : ");
831 if (cur->boolval) fprintf(output, "true\n");
832 else fprintf(output, "false\n");
833 break;
834 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000835 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000836 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000837 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000838 break;
839 case -1:
840 fprintf(output, "Object is a number : -Infinity\n");
841 break;
842 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000843 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000844 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000845 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
846 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000847 } else {
848 fprintf(output, "Object is a number : %0g\n", cur->floatval);
849 }
850 }
Owen Taylor3473f882001-02-23 17:55:21 +0000851 break;
852 case XPATH_STRING:
853 fprintf(output, "Object is a string : ");
854 xmlDebugDumpString(output, cur->stringval);
855 fprintf(output, "\n");
856 break;
857 case XPATH_POINT:
858 fprintf(output, "Object is a point : index %d in node", cur->index);
859 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
860 fprintf(output, "\n");
861 break;
862 case XPATH_RANGE:
863 if ((cur->user2 == NULL) ||
864 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
865 fprintf(output, "Object is a collapsed range :\n");
866 fprintf(output, shift);
867 if (cur->index >= 0)
868 fprintf(output, "index %d in ", cur->index);
869 fprintf(output, "node\n");
870 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
871 depth + 1);
872 } else {
873 fprintf(output, "Object is a range :\n");
874 fprintf(output, shift);
875 fprintf(output, "From ");
876 if (cur->index >= 0)
877 fprintf(output, "index %d in ", cur->index);
878 fprintf(output, "node\n");
879 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
880 depth + 1);
881 fprintf(output, shift);
882 fprintf(output, "To ");
883 if (cur->index2 >= 0)
884 fprintf(output, "index %d in ", cur->index2);
885 fprintf(output, "node\n");
886 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
887 depth + 1);
888 fprintf(output, "\n");
889 }
890 break;
891 case XPATH_LOCATIONSET:
892#if defined(LIBXML_XPTR_ENABLED)
893 fprintf(output, "Object is a Location Set:\n");
894 xmlXPathDebugDumpLocationSet(output,
895 (xmlLocationSetPtr) cur->user, depth);
896#endif
897 break;
898 case XPATH_USERS:
899 fprintf(output, "Object is user defined\n");
900 break;
901 }
902}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000903
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000904static void
905xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000906 xmlXPathStepOpPtr op, int depth) {
907 int i;
908 char shift[100];
909
910 for (i = 0;((i < depth) && (i < 25));i++)
911 shift[2 * i] = shift[2 * i + 1] = ' ';
912 shift[2 * i] = shift[2 * i + 1] = 0;
913
914 fprintf(output, shift);
915 if (op == NULL) {
916 fprintf(output, "Step is NULL\n");
917 return;
918 }
919 switch (op->op) {
920 case XPATH_OP_END:
921 fprintf(output, "END"); break;
922 case XPATH_OP_AND:
923 fprintf(output, "AND"); break;
924 case XPATH_OP_OR:
925 fprintf(output, "OR"); break;
926 case XPATH_OP_EQUAL:
927 if (op->value)
928 fprintf(output, "EQUAL =");
929 else
930 fprintf(output, "EQUAL !=");
931 break;
932 case XPATH_OP_CMP:
933 if (op->value)
934 fprintf(output, "CMP <");
935 else
936 fprintf(output, "CMP >");
937 if (!op->value2)
938 fprintf(output, "=");
939 break;
940 case XPATH_OP_PLUS:
941 if (op->value == 0)
942 fprintf(output, "PLUS -");
943 else if (op->value == 1)
944 fprintf(output, "PLUS +");
945 else if (op->value == 2)
946 fprintf(output, "PLUS unary -");
947 else if (op->value == 3)
948 fprintf(output, "PLUS unary - -");
949 break;
950 case XPATH_OP_MULT:
951 if (op->value == 0)
952 fprintf(output, "MULT *");
953 else if (op->value == 1)
954 fprintf(output, "MULT div");
955 else
956 fprintf(output, "MULT mod");
957 break;
958 case XPATH_OP_UNION:
959 fprintf(output, "UNION"); break;
960 case XPATH_OP_ROOT:
961 fprintf(output, "ROOT"); break;
962 case XPATH_OP_NODE:
963 fprintf(output, "NODE"); break;
964 case XPATH_OP_RESET:
965 fprintf(output, "RESET"); break;
966 case XPATH_OP_SORT:
967 fprintf(output, "SORT"); break;
968 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000969 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
970 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
971 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000972 const xmlChar *prefix = op->value4;
973 const xmlChar *name = op->value5;
974
975 fprintf(output, "COLLECT ");
976 switch (axis) {
977 case AXIS_ANCESTOR:
978 fprintf(output, " 'ancestors' "); break;
979 case AXIS_ANCESTOR_OR_SELF:
980 fprintf(output, " 'ancestors-or-self' "); break;
981 case AXIS_ATTRIBUTE:
982 fprintf(output, " 'attributes' "); break;
983 case AXIS_CHILD:
984 fprintf(output, " 'child' "); break;
985 case AXIS_DESCENDANT:
986 fprintf(output, " 'descendant' "); break;
987 case AXIS_DESCENDANT_OR_SELF:
988 fprintf(output, " 'descendant-or-self' "); break;
989 case AXIS_FOLLOWING:
990 fprintf(output, " 'following' "); break;
991 case AXIS_FOLLOWING_SIBLING:
992 fprintf(output, " 'following-siblings' "); break;
993 case AXIS_NAMESPACE:
994 fprintf(output, " 'namespace' "); break;
995 case AXIS_PARENT:
996 fprintf(output, " 'parent' "); break;
997 case AXIS_PRECEDING:
998 fprintf(output, " 'preceding' "); break;
999 case AXIS_PRECEDING_SIBLING:
1000 fprintf(output, " 'preceding-sibling' "); break;
1001 case AXIS_SELF:
1002 fprintf(output, " 'self' "); break;
1003 }
1004 switch (test) {
1005 case NODE_TEST_NONE:
1006 fprintf(output, "'none' "); break;
1007 case NODE_TEST_TYPE:
1008 fprintf(output, "'type' "); break;
1009 case NODE_TEST_PI:
1010 fprintf(output, "'PI' "); break;
1011 case NODE_TEST_ALL:
1012 fprintf(output, "'all' "); break;
1013 case NODE_TEST_NS:
1014 fprintf(output, "'namespace' "); break;
1015 case NODE_TEST_NAME:
1016 fprintf(output, "'name' "); break;
1017 }
1018 switch (type) {
1019 case NODE_TYPE_NODE:
1020 fprintf(output, "'node' "); break;
1021 case NODE_TYPE_COMMENT:
1022 fprintf(output, "'comment' "); break;
1023 case NODE_TYPE_TEXT:
1024 fprintf(output, "'text' "); break;
1025 case NODE_TYPE_PI:
1026 fprintf(output, "'PI' "); break;
1027 }
1028 if (prefix != NULL)
1029 fprintf(output, "%s:", prefix);
1030 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001031 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001032 break;
1033
1034 }
1035 case XPATH_OP_VALUE: {
1036 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1037
1038 fprintf(output, "ELEM ");
1039 xmlXPathDebugDumpObject(output, object, 0);
1040 goto finish;
1041 }
1042 case XPATH_OP_VARIABLE: {
1043 const xmlChar *prefix = op->value5;
1044 const xmlChar *name = op->value4;
1045
1046 if (prefix != NULL)
1047 fprintf(output, "VARIABLE %s:%s", prefix, name);
1048 else
1049 fprintf(output, "VARIABLE %s", name);
1050 break;
1051 }
1052 case XPATH_OP_FUNCTION: {
1053 int nbargs = op->value;
1054 const xmlChar *prefix = op->value5;
1055 const xmlChar *name = op->value4;
1056
1057 if (prefix != NULL)
1058 fprintf(output, "FUNCTION %s:%s(%d args)",
1059 prefix, name, nbargs);
1060 else
1061 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1062 break;
1063 }
1064 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1065 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001066 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001067#ifdef LIBXML_XPTR_ENABLED
1068 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1069#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001070 default:
1071 fprintf(output, "UNKNOWN %d\n", op->op); return;
1072 }
1073 fprintf(output, "\n");
1074finish:
1075 if (op->ch1 >= 0)
1076 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1077 if (op->ch2 >= 0)
1078 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1079}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001080
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001081/**
1082 * xmlXPathDebugDumpCompExpr:
1083 * @output: the FILE * for the output
1084 * @comp: the precompiled XPath expression
1085 * @depth: the indentation level.
1086 *
1087 * Dumps the tree of the compiled XPath expression.
1088 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001089void
1090xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1091 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001092 int i;
1093 char shift[100];
1094
Daniel Veillarda82b1822004-11-08 16:24:57 +00001095 if ((output == NULL) || (comp == NULL)) return;
1096
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001097 for (i = 0;((i < depth) && (i < 25));i++)
1098 shift[2 * i] = shift[2 * i + 1] = ' ';
1099 shift[2 * i] = shift[2 * i + 1] = 0;
1100
1101 fprintf(output, shift);
1102
1103 if (comp == NULL) {
1104 fprintf(output, "Compiled Expression is NULL\n");
1105 return;
1106 }
1107 fprintf(output, "Compiled Expression : %d elements\n",
1108 comp->nbStep);
1109 i = comp->last;
1110 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1111}
Daniel Veillard017b1082001-06-21 11:20:21 +00001112#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001113
1114/************************************************************************
1115 * *
1116 * Parser stacks related functions and macros *
1117 * *
1118 ************************************************************************/
1119
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001120/**
1121 * valuePop:
1122 * @ctxt: an XPath evaluation context
1123 *
1124 * Pops the top XPath object from the value stack
1125 *
1126 * Returns the XPath object just removed
1127 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001128xmlXPathObjectPtr
Daniel Veillard1c732d22002-11-30 11:22:59 +00001129valuePop(xmlXPathParserContextPtr ctxt)
1130{
1131 xmlXPathObjectPtr ret;
1132
Daniel Veillarda82b1822004-11-08 16:24:57 +00001133 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard24505b02005-07-28 23:49:35 +00001134 return (NULL);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001135 ctxt->valueNr--;
1136 if (ctxt->valueNr > 0)
1137 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1138 else
1139 ctxt->value = NULL;
1140 ret = ctxt->valueTab[ctxt->valueNr];
Daniel Veillard24505b02005-07-28 23:49:35 +00001141 ctxt->valueTab[ctxt->valueNr] = NULL;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001142 return (ret);
1143}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001144/**
1145 * valuePush:
1146 * @ctxt: an XPath evaluation context
1147 * @value: the XPath object
1148 *
1149 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001150 *
1151 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001152 */
Daniel Veillard24505b02005-07-28 23:49:35 +00001153int
Daniel Veillard1c732d22002-11-30 11:22:59 +00001154valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1155{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001156 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001157 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001158 xmlXPathObjectPtr *tmp;
1159
1160 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1161 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001162 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001163 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001164 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1165 return (0);
1166 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001167 ctxt->valueMax *= 2;
1168 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001169 }
1170 ctxt->valueTab[ctxt->valueNr] = value;
1171 ctxt->value = value;
1172 return (ctxt->valueNr++);
1173}
Owen Taylor3473f882001-02-23 17:55:21 +00001174
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001175/**
1176 * xmlXPathPopBoolean:
1177 * @ctxt: an XPath parser context
1178 *
1179 * Pops a boolean from the stack, handling conversion if needed.
1180 * Check error with #xmlXPathCheckError.
1181 *
1182 * Returns the boolean
1183 */
1184int
1185xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1186 xmlXPathObjectPtr obj;
1187 int ret;
1188
1189 obj = valuePop(ctxt);
1190 if (obj == NULL) {
1191 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1192 return(0);
1193 }
William M. Brack08171912003-12-29 02:52:11 +00001194 if (obj->type != XPATH_BOOLEAN)
1195 ret = xmlXPathCastToBoolean(obj);
1196 else
1197 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001198 xmlXPathFreeObject(obj);
1199 return(ret);
1200}
1201
1202/**
1203 * xmlXPathPopNumber:
1204 * @ctxt: an XPath parser context
1205 *
1206 * Pops a number from the stack, handling conversion if needed.
1207 * Check error with #xmlXPathCheckError.
1208 *
1209 * Returns the number
1210 */
1211double
1212xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1213 xmlXPathObjectPtr obj;
1214 double ret;
1215
1216 obj = valuePop(ctxt);
1217 if (obj == NULL) {
1218 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1219 return(0);
1220 }
William M. Brack08171912003-12-29 02:52:11 +00001221 if (obj->type != XPATH_NUMBER)
1222 ret = xmlXPathCastToNumber(obj);
1223 else
1224 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001225 xmlXPathFreeObject(obj);
1226 return(ret);
1227}
1228
1229/**
1230 * xmlXPathPopString:
1231 * @ctxt: an XPath parser context
1232 *
1233 * Pops a string from the stack, handling conversion if needed.
1234 * Check error with #xmlXPathCheckError.
1235 *
1236 * Returns the string
1237 */
1238xmlChar *
1239xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1240 xmlXPathObjectPtr obj;
1241 xmlChar * ret;
1242
1243 obj = valuePop(ctxt);
1244 if (obj == NULL) {
1245 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1246 return(NULL);
1247 }
William M. Brack08171912003-12-29 02:52:11 +00001248 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001249 /* TODO: needs refactoring somewhere else */
1250 if (obj->stringval == ret)
1251 obj->stringval = NULL;
1252 xmlXPathFreeObject(obj);
1253 return(ret);
1254}
1255
1256/**
1257 * xmlXPathPopNodeSet:
1258 * @ctxt: an XPath parser context
1259 *
1260 * Pops a node-set from the stack, handling conversion if needed.
1261 * Check error with #xmlXPathCheckError.
1262 *
1263 * Returns the node-set
1264 */
1265xmlNodeSetPtr
1266xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1267 xmlXPathObjectPtr obj;
1268 xmlNodeSetPtr ret;
1269
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001270 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001271 if (ctxt->value == NULL) {
1272 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1273 return(NULL);
1274 }
1275 if (!xmlXPathStackIsNodeSet(ctxt)) {
1276 xmlXPathSetTypeError(ctxt);
1277 return(NULL);
1278 }
1279 obj = valuePop(ctxt);
1280 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001281#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001282 /* to fix memory leak of not clearing obj->user */
1283 if (obj->boolval && obj->user != NULL)
1284 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001285#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001286 xmlXPathFreeNodeSetList(obj);
1287 return(ret);
1288}
1289
1290/**
1291 * xmlXPathPopExternal:
1292 * @ctxt: an XPath parser context
1293 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001294 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001295 * Check error with #xmlXPathCheckError.
1296 *
1297 * Returns the object
1298 */
1299void *
1300xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1301 xmlXPathObjectPtr obj;
1302 void * ret;
1303
Daniel Veillarda82b1822004-11-08 16:24:57 +00001304 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001305 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1306 return(NULL);
1307 }
1308 if (ctxt->value->type != XPATH_USERS) {
1309 xmlXPathSetTypeError(ctxt);
1310 return(NULL);
1311 }
1312 obj = valuePop(ctxt);
1313 ret = obj->user;
1314 xmlXPathFreeObject(obj);
1315 return(ret);
1316}
1317
Owen Taylor3473f882001-02-23 17:55:21 +00001318/*
1319 * Macros for accessing the content. Those should be used only by the parser,
1320 * and not exported.
1321 *
1322 * Dirty macros, i.e. one need to make assumption on the context to use them
1323 *
1324 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1325 * CUR returns the current xmlChar value, i.e. a 8 bit value
1326 * in ISO-Latin or UTF-8.
1327 * This should be used internally by the parser
1328 * only to compare to ASCII values otherwise it would break when
1329 * running with UTF-8 encoding.
1330 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1331 * to compare on ASCII based substring.
1332 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1333 * strings within the parser.
1334 * CURRENT Returns the current char value, with the full decoding of
1335 * UTF-8 if we are using this mode. It returns an int.
1336 * NEXT Skip to the next character, this does the proper decoding
1337 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1338 * It returns the pointer to the current xmlChar.
1339 */
1340
1341#define CUR (*ctxt->cur)
1342#define SKIP(val) ctxt->cur += (val)
1343#define NXT(val) ctxt->cur[(val)]
1344#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001345#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1346
1347#define COPY_BUF(l,b,i,v) \
1348 if (l == 1) b[i++] = (xmlChar) v; \
1349 else i += xmlCopyChar(l,&b[i],v)
1350
1351#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001352
1353#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001354 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001355
1356#define CURRENT (*ctxt->cur)
1357#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1358
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001359
1360#ifndef DBL_DIG
1361#define DBL_DIG 16
1362#endif
1363#ifndef DBL_EPSILON
1364#define DBL_EPSILON 1E-9
1365#endif
1366
1367#define UPPER_DOUBLE 1E9
1368#define LOWER_DOUBLE 1E-5
1369
1370#define INTEGER_DIGITS DBL_DIG
1371#define FRACTION_DIGITS (DBL_DIG + 1)
1372#define EXPONENT_DIGITS (3 + 2)
1373
1374/**
1375 * xmlXPathFormatNumber:
1376 * @number: number to format
1377 * @buffer: output buffer
1378 * @buffersize: size of output buffer
1379 *
1380 * Convert the number into a string representation.
1381 */
1382static void
1383xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1384{
Daniel Veillardcda96922001-08-21 10:56:31 +00001385 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001386 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001387 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001388 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001389 break;
1390 case -1:
1391 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001392 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001393 break;
1394 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001395 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001396 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001397 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001398 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001399 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001400 } else if (number == ((int) number)) {
1401 char work[30];
1402 char *ptr, *cur;
1403 int res, value = (int) number;
1404
1405 ptr = &buffer[0];
1406 if (value < 0) {
1407 *ptr++ = '-';
1408 value = -value;
1409 }
1410 if (value == 0) {
1411 *ptr++ = '0';
1412 } else {
1413 cur = &work[0];
1414 while (value != 0) {
1415 res = value % 10;
1416 value = value / 10;
1417 *cur++ = '0' + res;
1418 }
1419 cur--;
1420 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1421 *ptr++ = *cur--;
1422 }
1423 }
1424 if (ptr - buffer < buffersize) {
1425 *ptr = 0;
1426 } else if (buffersize > 0) {
1427 ptr--;
1428 *ptr = 0;
1429 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001430 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001431 /* 3 is sign, decimal point, and terminating zero */
1432 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1433 int integer_place, fraction_place;
1434 char *ptr;
1435 char *after_fraction;
1436 double absolute_value;
1437 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001438
Bjorn Reese70a9da52001-04-21 16:57:29 +00001439 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001440
Bjorn Reese70a9da52001-04-21 16:57:29 +00001441 /*
1442 * First choose format - scientific or regular floating point.
1443 * In either case, result is in work, and after_fraction points
1444 * just past the fractional part.
1445 */
1446 if ( ((absolute_value > UPPER_DOUBLE) ||
1447 (absolute_value < LOWER_DOUBLE)) &&
1448 (absolute_value != 0.0) ) {
1449 /* Use scientific notation */
1450 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1451 fraction_place = DBL_DIG - 1;
1452 snprintf(work, sizeof(work),"%*.*e",
1453 integer_place, fraction_place, number);
1454 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001455 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001456 else {
1457 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001458 if (absolute_value > 0.0)
1459 integer_place = 1 + (int)log10(absolute_value);
1460 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001461 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001462 fraction_place = (integer_place > 0)
1463 ? DBL_DIG - integer_place
1464 : DBL_DIG;
1465 size = snprintf(work, sizeof(work), "%0.*f",
1466 fraction_place, number);
1467 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001468 }
1469
Bjorn Reese70a9da52001-04-21 16:57:29 +00001470 /* Remove fractional trailing zeroes */
1471 ptr = after_fraction;
1472 while (*(--ptr) == '0')
1473 ;
1474 if (*ptr != '.')
1475 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001476 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001477
1478 /* Finally copy result back to caller */
1479 size = strlen(work) + 1;
1480 if (size > buffersize) {
1481 work[buffersize - 1] = 0;
1482 size = buffersize;
1483 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001484 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001485 }
1486 break;
1487 }
1488}
1489
Owen Taylor3473f882001-02-23 17:55:21 +00001490
1491/************************************************************************
1492 * *
1493 * Routines to handle NodeSets *
1494 * *
1495 ************************************************************************/
1496
1497/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001498 * xmlXPathOrderDocElems:
1499 * @doc: an input document
1500 *
1501 * Call this routine to speed up XPath computation on static documents.
1502 * This stamps all the element nodes with the document order
1503 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001504 * field, the value stored is actually - the node number (starting at -1)
1505 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001506 *
William M. Brack08171912003-12-29 02:52:11 +00001507 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001508 * of error.
1509 */
1510long
1511xmlXPathOrderDocElems(xmlDocPtr doc) {
1512 long count = 0;
1513 xmlNodePtr cur;
1514
1515 if (doc == NULL)
1516 return(-1);
1517 cur = doc->children;
1518 while (cur != NULL) {
1519 if (cur->type == XML_ELEMENT_NODE) {
1520 cur->content = (void *) (-(++count));
1521 if (cur->children != NULL) {
1522 cur = cur->children;
1523 continue;
1524 }
1525 }
1526 if (cur->next != NULL) {
1527 cur = cur->next;
1528 continue;
1529 }
1530 do {
1531 cur = cur->parent;
1532 if (cur == NULL)
1533 break;
1534 if (cur == (xmlNodePtr) doc) {
1535 cur = NULL;
1536 break;
1537 }
1538 if (cur->next != NULL) {
1539 cur = cur->next;
1540 break;
1541 }
1542 } while (cur != NULL);
1543 }
1544 return(count);
1545}
1546
1547/**
Owen Taylor3473f882001-02-23 17:55:21 +00001548 * xmlXPathCmpNodes:
1549 * @node1: the first node
1550 * @node2: the second node
1551 *
1552 * Compare two nodes w.r.t document order
1553 *
1554 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001555 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001556 */
1557int
1558xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1559 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001560 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001561 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001562 xmlNodePtr cur, root;
1563
1564 if ((node1 == NULL) || (node2 == NULL))
1565 return(-2);
1566 /*
1567 * a couple of optimizations which will avoid computations in most cases
1568 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001569 if (node1->type == XML_ATTRIBUTE_NODE) {
1570 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001571 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001572 node1 = node1->parent;
1573 }
1574 if (node2->type == XML_ATTRIBUTE_NODE) {
1575 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001576 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001577 node2 = node2->parent;
1578 }
1579 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001580 if (attr1 == attr2) {
1581 /* not required, but we keep attributes in order */
1582 if (attr1 != 0) {
1583 cur = attrNode2->prev;
1584 while (cur != NULL) {
1585 if (cur == attrNode1)
1586 return (1);
1587 cur = cur->prev;
1588 }
1589 return (-1);
1590 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001591 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001592 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001593 if (attr2 == 1)
1594 return(1);
1595 return(-1);
1596 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001597 if ((node1->type == XML_NAMESPACE_DECL) ||
1598 (node2->type == XML_NAMESPACE_DECL))
1599 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001600 if (node1 == node2->prev)
1601 return(1);
1602 if (node1 == node2->next)
1603 return(-1);
1604
1605 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001606 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001607 */
1608 if ((node1->type == XML_ELEMENT_NODE) &&
1609 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001610 (0 > (long) node1->content) &&
1611 (0 > (long) node2->content) &&
1612 (node1->doc == node2->doc)) {
1613 long l1, l2;
1614
1615 l1 = -((long) node1->content);
1616 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001617 if (l1 < l2)
1618 return(1);
1619 if (l1 > l2)
1620 return(-1);
1621 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001622
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001623 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001624 * compute depth to root
1625 */
1626 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1627 if (cur == node1)
1628 return(1);
1629 depth2++;
1630 }
1631 root = cur;
1632 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1633 if (cur == node2)
1634 return(-1);
1635 depth1++;
1636 }
1637 /*
1638 * Distinct document (or distinct entities :-( ) case.
1639 */
1640 if (root != cur) {
1641 return(-2);
1642 }
1643 /*
1644 * get the nearest common ancestor.
1645 */
1646 while (depth1 > depth2) {
1647 depth1--;
1648 node1 = node1->parent;
1649 }
1650 while (depth2 > depth1) {
1651 depth2--;
1652 node2 = node2->parent;
1653 }
1654 while (node1->parent != node2->parent) {
1655 node1 = node1->parent;
1656 node2 = node2->parent;
1657 /* should not happen but just in case ... */
1658 if ((node1 == NULL) || (node2 == NULL))
1659 return(-2);
1660 }
1661 /*
1662 * Find who's first.
1663 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001664 if (node1 == node2->prev)
1665 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001666 if (node1 == node2->next)
1667 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001668 /*
1669 * Speedup using document order if availble.
1670 */
1671 if ((node1->type == XML_ELEMENT_NODE) &&
1672 (node2->type == XML_ELEMENT_NODE) &&
1673 (0 > (long) node1->content) &&
1674 (0 > (long) node2->content) &&
1675 (node1->doc == node2->doc)) {
1676 long l1, l2;
1677
1678 l1 = -((long) node1->content);
1679 l2 = -((long) node2->content);
1680 if (l1 < l2)
1681 return(1);
1682 if (l1 > l2)
1683 return(-1);
1684 }
1685
Owen Taylor3473f882001-02-23 17:55:21 +00001686 for (cur = node1->next;cur != NULL;cur = cur->next)
1687 if (cur == node2)
1688 return(1);
1689 return(-1); /* assume there is no sibling list corruption */
1690}
1691
1692/**
1693 * xmlXPathNodeSetSort:
1694 * @set: the node set
1695 *
1696 * Sort the node set in document order
1697 */
1698void
1699xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001700 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001701 xmlNodePtr tmp;
1702
1703 if (set == NULL)
1704 return;
1705
1706 /* Use Shell's sort to sort the node-set */
1707 len = set->nodeNr;
1708 for (incr = len / 2; incr > 0; incr /= 2) {
1709 for (i = incr; i < len; i++) {
1710 j = i - incr;
1711 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001712 if (xmlXPathCmpNodes(set->nodeTab[j],
1713 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001714 tmp = set->nodeTab[j];
1715 set->nodeTab[j] = set->nodeTab[j + incr];
1716 set->nodeTab[j + incr] = tmp;
1717 j -= incr;
1718 } else
1719 break;
1720 }
1721 }
1722 }
1723}
1724
1725#define XML_NODESET_DEFAULT 10
1726/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001727 * xmlXPathNodeSetDupNs:
1728 * @node: the parent node of the namespace XPath node
1729 * @ns: the libxml namespace declaration node.
1730 *
1731 * Namespace node in libxml don't match the XPath semantic. In a node set
1732 * the namespace nodes are duplicated and the next pointer is set to the
1733 * parent node in the XPath semantic.
1734 *
1735 * Returns the newly created object.
1736 */
1737static xmlNodePtr
1738xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1739 xmlNsPtr cur;
1740
1741 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1742 return(NULL);
1743 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1744 return((xmlNodePtr) ns);
1745
1746 /*
1747 * Allocate a new Namespace and fill the fields.
1748 */
1749 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1750 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001751 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001752 return(NULL);
1753 }
1754 memset(cur, 0, sizeof(xmlNs));
1755 cur->type = XML_NAMESPACE_DECL;
1756 if (ns->href != NULL)
1757 cur->href = xmlStrdup(ns->href);
1758 if (ns->prefix != NULL)
1759 cur->prefix = xmlStrdup(ns->prefix);
1760 cur->next = (xmlNsPtr) node;
1761 return((xmlNodePtr) cur);
1762}
1763
1764/**
1765 * xmlXPathNodeSetFreeNs:
1766 * @ns: the XPath namespace node found in a nodeset.
1767 *
William M. Brack08171912003-12-29 02:52:11 +00001768 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001769 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001770 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001771 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001772void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001773xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1774 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1775 return;
1776
1777 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1778 if (ns->href != NULL)
1779 xmlFree((xmlChar *)ns->href);
1780 if (ns->prefix != NULL)
1781 xmlFree((xmlChar *)ns->prefix);
1782 xmlFree(ns);
1783 }
1784}
1785
1786/**
Owen Taylor3473f882001-02-23 17:55:21 +00001787 * xmlXPathNodeSetCreate:
1788 * @val: an initial xmlNodePtr, or NULL
1789 *
1790 * Create a new xmlNodeSetPtr of type double and of value @val
1791 *
1792 * Returns the newly created object.
1793 */
1794xmlNodeSetPtr
1795xmlXPathNodeSetCreate(xmlNodePtr val) {
1796 xmlNodeSetPtr ret;
1797
1798 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1799 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001800 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001801 return(NULL);
1802 }
1803 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1804 if (val != NULL) {
1805 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1806 sizeof(xmlNodePtr));
1807 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001808 xmlXPathErrMemory(NULL, "creating nodeset\n");
1809 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001810 return(NULL);
1811 }
1812 memset(ret->nodeTab, 0 ,
1813 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1814 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001815 if (val->type == XML_NAMESPACE_DECL) {
1816 xmlNsPtr ns = (xmlNsPtr) val;
1817
1818 ret->nodeTab[ret->nodeNr++] =
1819 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1820 } else
1821 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001822 }
1823 return(ret);
1824}
1825
1826/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001827 * xmlXPathNodeSetContains:
1828 * @cur: the node-set
1829 * @val: the node
1830 *
1831 * checks whether @cur contains @val
1832 *
1833 * Returns true (1) if @cur contains @val, false (0) otherwise
1834 */
1835int
1836xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1837 int i;
1838
Daniel Veillarda82b1822004-11-08 16:24:57 +00001839 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001840 if (val->type == XML_NAMESPACE_DECL) {
1841 for (i = 0; i < cur->nodeNr; i++) {
1842 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns1, ns2;
1844
1845 ns1 = (xmlNsPtr) val;
1846 ns2 = (xmlNsPtr) cur->nodeTab[i];
1847 if (ns1 == ns2)
1848 return(1);
1849 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1850 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1851 return(1);
1852 }
1853 }
1854 } else {
1855 for (i = 0; i < cur->nodeNr; i++) {
1856 if (cur->nodeTab[i] == val)
1857 return(1);
1858 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001859 }
1860 return(0);
1861}
1862
1863/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001864 * xmlXPathNodeSetAddNs:
1865 * @cur: the initial node set
1866 * @node: the hosting node
1867 * @ns: a the namespace node
1868 *
1869 * add a new namespace node to an existing NodeSet
1870 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001871void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001872xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1873 int i;
1874
Daniel Veillarda82b1822004-11-08 16:24:57 +00001875
1876 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1877 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001878 (node->type != XML_ELEMENT_NODE))
1879 return;
1880
William M. Brack08171912003-12-29 02:52:11 +00001881 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001882 /*
William M. Brack08171912003-12-29 02:52:11 +00001883 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001884 */
1885 for (i = 0;i < cur->nodeNr;i++) {
1886 if ((cur->nodeTab[i] != NULL) &&
1887 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001888 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001889 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1890 return;
1891 }
1892
1893 /*
1894 * grow the nodeTab if needed
1895 */
1896 if (cur->nodeMax == 0) {
1897 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1898 sizeof(xmlNodePtr));
1899 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001900 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001901 return;
1902 }
1903 memset(cur->nodeTab, 0 ,
1904 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1905 cur->nodeMax = XML_NODESET_DEFAULT;
1906 } else if (cur->nodeNr == cur->nodeMax) {
1907 xmlNodePtr *temp;
1908
1909 cur->nodeMax *= 2;
1910 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1911 sizeof(xmlNodePtr));
1912 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001913 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001914 return;
1915 }
1916 cur->nodeTab = temp;
1917 }
1918 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1919}
1920
1921/**
Owen Taylor3473f882001-02-23 17:55:21 +00001922 * xmlXPathNodeSetAdd:
1923 * @cur: the initial node set
1924 * @val: a new xmlNodePtr
1925 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001926 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001927 */
1928void
1929xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1930 int i;
1931
Daniel Veillarda82b1822004-11-08 16:24:57 +00001932 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001933
Daniel Veillardef0b4502003-03-24 13:57:34 +00001934#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001935 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1936 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001937#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001938
William M. Brack08171912003-12-29 02:52:11 +00001939 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001940 /*
William M. Brack08171912003-12-29 02:52:11 +00001941 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001942 */
1943 for (i = 0;i < cur->nodeNr;i++)
1944 if (cur->nodeTab[i] == val) return;
1945
1946 /*
1947 * grow the nodeTab if needed
1948 */
1949 if (cur->nodeMax == 0) {
1950 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1951 sizeof(xmlNodePtr));
1952 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001953 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001954 return;
1955 }
1956 memset(cur->nodeTab, 0 ,
1957 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1958 cur->nodeMax = XML_NODESET_DEFAULT;
1959 } else if (cur->nodeNr == cur->nodeMax) {
1960 xmlNodePtr *temp;
1961
1962 cur->nodeMax *= 2;
1963 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1964 sizeof(xmlNodePtr));
1965 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001966 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001967 return;
1968 }
1969 cur->nodeTab = temp;
1970 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001971 if (val->type == XML_NAMESPACE_DECL) {
1972 xmlNsPtr ns = (xmlNsPtr) val;
1973
1974 cur->nodeTab[cur->nodeNr++] =
1975 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1976 } else
1977 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001978}
1979
1980/**
1981 * xmlXPathNodeSetAddUnique:
1982 * @cur: the initial node set
1983 * @val: a new xmlNodePtr
1984 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001985 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001986 * when we are sure the node is not already in the set.
1987 */
1988void
1989xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001990 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001991
Daniel Veillardef0b4502003-03-24 13:57:34 +00001992#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001993 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1994 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001995#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001996
William M. Brack08171912003-12-29 02:52:11 +00001997 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001998 /*
1999 * grow the nodeTab if needed
2000 */
2001 if (cur->nodeMax == 0) {
2002 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2003 sizeof(xmlNodePtr));
2004 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002005 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002006 return;
2007 }
2008 memset(cur->nodeTab, 0 ,
2009 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2010 cur->nodeMax = XML_NODESET_DEFAULT;
2011 } else if (cur->nodeNr == cur->nodeMax) {
2012 xmlNodePtr *temp;
2013
2014 cur->nodeMax *= 2;
2015 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2016 sizeof(xmlNodePtr));
2017 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002018 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002019 return;
2020 }
2021 cur->nodeTab = temp;
2022 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002023 if (val->type == XML_NAMESPACE_DECL) {
2024 xmlNsPtr ns = (xmlNsPtr) val;
2025
2026 cur->nodeTab[cur->nodeNr++] =
2027 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2028 } else
2029 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002030}
2031
2032/**
2033 * xmlXPathNodeSetMerge:
2034 * @val1: the first NodeSet or NULL
2035 * @val2: the second NodeSet
2036 *
2037 * Merges two nodesets, all nodes from @val2 are added to @val1
2038 * if @val1 is NULL, a new set is created and copied from @val2
2039 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002040 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002041 */
2042xmlNodeSetPtr
2043xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002044 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002045
2046 if (val2 == NULL) return(val1);
2047 if (val1 == NULL) {
2048 val1 = xmlXPathNodeSetCreate(NULL);
2049 }
2050
William M. Brack08171912003-12-29 02:52:11 +00002051 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002052 initNr = val1->nodeNr;
2053
2054 for (i = 0;i < val2->nodeNr;i++) {
2055 /*
William M. Brack08171912003-12-29 02:52:11 +00002056 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002057 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002058 skip = 0;
2059 for (j = 0; j < initNr; j++) {
2060 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2061 skip = 1;
2062 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002063 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2064 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2065 xmlNsPtr ns1, ns2;
2066 ns1 = (xmlNsPtr) val1->nodeTab[j];
2067 ns2 = (xmlNsPtr) val2->nodeTab[i];
2068 if ((ns1->next == ns2->next) &&
2069 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2070 skip = 1;
2071 break;
2072 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002073 }
2074 }
2075 if (skip)
2076 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002077
2078 /*
2079 * grow the nodeTab if needed
2080 */
2081 if (val1->nodeMax == 0) {
2082 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2083 sizeof(xmlNodePtr));
2084 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002085 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002086 return(NULL);
2087 }
2088 memset(val1->nodeTab, 0 ,
2089 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2090 val1->nodeMax = XML_NODESET_DEFAULT;
2091 } else if (val1->nodeNr == val1->nodeMax) {
2092 xmlNodePtr *temp;
2093
2094 val1->nodeMax *= 2;
2095 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2096 sizeof(xmlNodePtr));
2097 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002098 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002099 return(NULL);
2100 }
2101 val1->nodeTab = temp;
2102 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002103 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2104 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2105
2106 val1->nodeTab[val1->nodeNr++] =
2107 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2108 } else
2109 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002110 }
2111
2112 return(val1);
2113}
2114
2115/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002116 * xmlXPathNodeSetMergeUnique:
2117 * @val1: the first NodeSet or NULL
2118 * @val2: the second NodeSet
2119 *
2120 * Merges two nodesets, all nodes from @val2 are added to @val1
2121 * if @val1 is NULL, a new set is created and copied from @val2
2122 *
2123 * Returns @val1 once extended or NULL in case of error.
2124 */
2125static xmlNodeSetPtr
2126xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002127 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002128
2129 if (val2 == NULL) return(val1);
2130 if (val1 == NULL) {
2131 val1 = xmlXPathNodeSetCreate(NULL);
2132 }
2133
William M. Brack08171912003-12-29 02:52:11 +00002134 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002135
2136 for (i = 0;i < val2->nodeNr;i++) {
2137 /*
2138 * grow the nodeTab if needed
2139 */
2140 if (val1->nodeMax == 0) {
2141 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2142 sizeof(xmlNodePtr));
2143 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002144 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002145 return(NULL);
2146 }
2147 memset(val1->nodeTab, 0 ,
2148 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2149 val1->nodeMax = XML_NODESET_DEFAULT;
2150 } else if (val1->nodeNr == val1->nodeMax) {
2151 xmlNodePtr *temp;
2152
2153 val1->nodeMax *= 2;
2154 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2155 sizeof(xmlNodePtr));
2156 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002157 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002158 return(NULL);
2159 }
2160 val1->nodeTab = temp;
2161 }
2162 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2163 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2164
2165 val1->nodeTab[val1->nodeNr++] =
2166 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2167 } else
2168 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2169 }
2170
2171 return(val1);
2172}
2173
2174/**
Owen Taylor3473f882001-02-23 17:55:21 +00002175 * xmlXPathNodeSetDel:
2176 * @cur: the initial node set
2177 * @val: an xmlNodePtr
2178 *
2179 * Removes an xmlNodePtr from an existing NodeSet
2180 */
2181void
2182xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2183 int i;
2184
2185 if (cur == NULL) return;
2186 if (val == NULL) return;
2187
2188 /*
William M. Brack08171912003-12-29 02:52:11 +00002189 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002190 */
2191 for (i = 0;i < cur->nodeNr;i++)
2192 if (cur->nodeTab[i] == val) break;
2193
William M. Brack08171912003-12-29 02:52:11 +00002194 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002195#ifdef DEBUG
2196 xmlGenericError(xmlGenericErrorContext,
2197 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2198 val->name);
2199#endif
2200 return;
2201 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002202 if ((cur->nodeTab[i] != NULL) &&
2203 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2204 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002205 cur->nodeNr--;
2206 for (;i < cur->nodeNr;i++)
2207 cur->nodeTab[i] = cur->nodeTab[i + 1];
2208 cur->nodeTab[cur->nodeNr] = NULL;
2209}
2210
2211/**
2212 * xmlXPathNodeSetRemove:
2213 * @cur: the initial node set
2214 * @val: the index to remove
2215 *
2216 * Removes an entry from an existing NodeSet list.
2217 */
2218void
2219xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2220 if (cur == NULL) return;
2221 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002222 if ((cur->nodeTab[val] != NULL) &&
2223 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2224 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002225 cur->nodeNr--;
2226 for (;val < cur->nodeNr;val++)
2227 cur->nodeTab[val] = cur->nodeTab[val + 1];
2228 cur->nodeTab[cur->nodeNr] = NULL;
2229}
2230
2231/**
2232 * xmlXPathFreeNodeSet:
2233 * @obj: the xmlNodeSetPtr to free
2234 *
2235 * Free the NodeSet compound (not the actual nodes !).
2236 */
2237void
2238xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2239 if (obj == NULL) return;
2240 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002241 int i;
2242
William M. Brack08171912003-12-29 02:52:11 +00002243 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002244 for (i = 0;i < obj->nodeNr;i++)
2245 if ((obj->nodeTab[i] != NULL) &&
2246 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2247 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002248 xmlFree(obj->nodeTab);
2249 }
Owen Taylor3473f882001-02-23 17:55:21 +00002250 xmlFree(obj);
2251}
2252
2253/**
2254 * xmlXPathFreeValueTree:
2255 * @obj: the xmlNodeSetPtr to free
2256 *
2257 * Free the NodeSet compound and the actual tree, this is different
2258 * from xmlXPathFreeNodeSet()
2259 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002260static void
Owen Taylor3473f882001-02-23 17:55:21 +00002261xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2262 int i;
2263
2264 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002265
2266 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002267 for (i = 0;i < obj->nodeNr;i++) {
2268 if (obj->nodeTab[i] != NULL) {
2269 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2270 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2271 } else {
2272 xmlFreeNodeList(obj->nodeTab[i]);
2273 }
2274 }
2275 }
Owen Taylor3473f882001-02-23 17:55:21 +00002276 xmlFree(obj->nodeTab);
2277 }
Owen Taylor3473f882001-02-23 17:55:21 +00002278 xmlFree(obj);
2279}
2280
2281#if defined(DEBUG) || defined(DEBUG_STEP)
2282/**
2283 * xmlGenericErrorContextNodeSet:
2284 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002285 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002286 *
2287 * Quick display of a NodeSet
2288 */
2289void
2290xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2291 int i;
2292
2293 if (output == NULL) output = xmlGenericErrorContext;
2294 if (obj == NULL) {
2295 fprintf(output, "NodeSet == NULL !\n");
2296 return;
2297 }
2298 if (obj->nodeNr == 0) {
2299 fprintf(output, "NodeSet is empty\n");
2300 return;
2301 }
2302 if (obj->nodeTab == NULL) {
2303 fprintf(output, " nodeTab == NULL !\n");
2304 return;
2305 }
2306 for (i = 0; i < obj->nodeNr; i++) {
2307 if (obj->nodeTab[i] == NULL) {
2308 fprintf(output, " NULL !\n");
2309 return;
2310 }
2311 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2312 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2313 fprintf(output, " /");
2314 else if (obj->nodeTab[i]->name == NULL)
2315 fprintf(output, " noname!");
2316 else fprintf(output, " %s", obj->nodeTab[i]->name);
2317 }
2318 fprintf(output, "\n");
2319}
2320#endif
2321
2322/**
2323 * xmlXPathNewNodeSet:
2324 * @val: the NodePtr value
2325 *
2326 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2327 * it with the single Node @val
2328 *
2329 * Returns the newly created object.
2330 */
2331xmlXPathObjectPtr
2332xmlXPathNewNodeSet(xmlNodePtr val) {
2333 xmlXPathObjectPtr ret;
2334
2335 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2336 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002337 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002338 return(NULL);
2339 }
2340 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2341 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002342 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002343 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002344 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002345 return(ret);
2346}
2347
2348/**
2349 * xmlXPathNewValueTree:
2350 * @val: the NodePtr value
2351 *
2352 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2353 * it with the tree root @val
2354 *
2355 * Returns the newly created object.
2356 */
2357xmlXPathObjectPtr
2358xmlXPathNewValueTree(xmlNodePtr val) {
2359 xmlXPathObjectPtr ret;
2360
2361 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2362 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002363 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002364 return(NULL);
2365 }
2366 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2367 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002368 ret->boolval = 1;
2369 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002370 ret->nodesetval = xmlXPathNodeSetCreate(val);
2371 return(ret);
2372}
2373
2374/**
2375 * xmlXPathNewNodeSetList:
2376 * @val: an existing NodeSet
2377 *
2378 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2379 * it with the Nodeset @val
2380 *
2381 * Returns the newly created object.
2382 */
2383xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002384xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2385{
Owen Taylor3473f882001-02-23 17:55:21 +00002386 xmlXPathObjectPtr ret;
2387 int i;
2388
2389 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002390 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002391 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002392 ret = xmlXPathNewNodeSet(NULL);
2393 else {
2394 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2395 for (i = 1; i < val->nodeNr; ++i)
2396 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2397 }
Owen Taylor3473f882001-02-23 17:55:21 +00002398
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002399 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002400}
2401
2402/**
2403 * xmlXPathWrapNodeSet:
2404 * @val: the NodePtr value
2405 *
2406 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2407 *
2408 * Returns the newly created object.
2409 */
2410xmlXPathObjectPtr
2411xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2412 xmlXPathObjectPtr ret;
2413
2414 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2415 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002416 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002417 return(NULL);
2418 }
2419 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2420 ret->type = XPATH_NODESET;
2421 ret->nodesetval = val;
2422 return(ret);
2423}
2424
2425/**
2426 * xmlXPathFreeNodeSetList:
2427 * @obj: an existing NodeSetList object
2428 *
2429 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2430 * the list contrary to xmlXPathFreeObject().
2431 */
2432void
2433xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2434 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002435 xmlFree(obj);
2436}
2437
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002438/**
2439 * xmlXPathDifference:
2440 * @nodes1: a node-set
2441 * @nodes2: a node-set
2442 *
2443 * Implements the EXSLT - Sets difference() function:
2444 * node-set set:difference (node-set, node-set)
2445 *
2446 * Returns the difference between the two node sets, or nodes1 if
2447 * nodes2 is empty
2448 */
2449xmlNodeSetPtr
2450xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2451 xmlNodeSetPtr ret;
2452 int i, l1;
2453 xmlNodePtr cur;
2454
2455 if (xmlXPathNodeSetIsEmpty(nodes2))
2456 return(nodes1);
2457
2458 ret = xmlXPathNodeSetCreate(NULL);
2459 if (xmlXPathNodeSetIsEmpty(nodes1))
2460 return(ret);
2461
2462 l1 = xmlXPathNodeSetGetLength(nodes1);
2463
2464 for (i = 0; i < l1; i++) {
2465 cur = xmlXPathNodeSetItem(nodes1, i);
2466 if (!xmlXPathNodeSetContains(nodes2, cur))
2467 xmlXPathNodeSetAddUnique(ret, cur);
2468 }
2469 return(ret);
2470}
2471
2472/**
2473 * xmlXPathIntersection:
2474 * @nodes1: a node-set
2475 * @nodes2: a node-set
2476 *
2477 * Implements the EXSLT - Sets intersection() function:
2478 * node-set set:intersection (node-set, node-set)
2479 *
2480 * Returns a node set comprising the nodes that are within both the
2481 * node sets passed as arguments
2482 */
2483xmlNodeSetPtr
2484xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2485 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2486 int i, l1;
2487 xmlNodePtr cur;
2488
2489 if (xmlXPathNodeSetIsEmpty(nodes1))
2490 return(ret);
2491 if (xmlXPathNodeSetIsEmpty(nodes2))
2492 return(ret);
2493
2494 l1 = xmlXPathNodeSetGetLength(nodes1);
2495
2496 for (i = 0; i < l1; i++) {
2497 cur = xmlXPathNodeSetItem(nodes1, i);
2498 if (xmlXPathNodeSetContains(nodes2, cur))
2499 xmlXPathNodeSetAddUnique(ret, cur);
2500 }
2501 return(ret);
2502}
2503
2504/**
2505 * xmlXPathDistinctSorted:
2506 * @nodes: a node-set, sorted by document order
2507 *
2508 * Implements the EXSLT - Sets distinct() function:
2509 * node-set set:distinct (node-set)
2510 *
2511 * Returns a subset of the nodes contained in @nodes, or @nodes if
2512 * it is empty
2513 */
2514xmlNodeSetPtr
2515xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2516 xmlNodeSetPtr ret;
2517 xmlHashTablePtr hash;
2518 int i, l;
2519 xmlChar * strval;
2520 xmlNodePtr cur;
2521
2522 if (xmlXPathNodeSetIsEmpty(nodes))
2523 return(nodes);
2524
2525 ret = xmlXPathNodeSetCreate(NULL);
2526 l = xmlXPathNodeSetGetLength(nodes);
2527 hash = xmlHashCreate (l);
2528 for (i = 0; i < l; i++) {
2529 cur = xmlXPathNodeSetItem(nodes, i);
2530 strval = xmlXPathCastNodeToString(cur);
2531 if (xmlHashLookup(hash, strval) == NULL) {
2532 xmlHashAddEntry(hash, strval, strval);
2533 xmlXPathNodeSetAddUnique(ret, cur);
2534 } else {
2535 xmlFree(strval);
2536 }
2537 }
2538 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2539 return(ret);
2540}
2541
2542/**
2543 * xmlXPathDistinct:
2544 * @nodes: a node-set
2545 *
2546 * Implements the EXSLT - Sets distinct() function:
2547 * node-set set:distinct (node-set)
2548 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2549 * is called with the sorted node-set
2550 *
2551 * Returns a subset of the nodes contained in @nodes, or @nodes if
2552 * it is empty
2553 */
2554xmlNodeSetPtr
2555xmlXPathDistinct (xmlNodeSetPtr nodes) {
2556 if (xmlXPathNodeSetIsEmpty(nodes))
2557 return(nodes);
2558
2559 xmlXPathNodeSetSort(nodes);
2560 return(xmlXPathDistinctSorted(nodes));
2561}
2562
2563/**
2564 * xmlXPathHasSameNodes:
2565 * @nodes1: a node-set
2566 * @nodes2: a node-set
2567 *
2568 * Implements the EXSLT - Sets has-same-nodes function:
2569 * boolean set:has-same-node(node-set, node-set)
2570 *
2571 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2572 * otherwise
2573 */
2574int
2575xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2576 int i, l;
2577 xmlNodePtr cur;
2578
2579 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2580 xmlXPathNodeSetIsEmpty(nodes2))
2581 return(0);
2582
2583 l = xmlXPathNodeSetGetLength(nodes1);
2584 for (i = 0; i < l; i++) {
2585 cur = xmlXPathNodeSetItem(nodes1, i);
2586 if (xmlXPathNodeSetContains(nodes2, cur))
2587 return(1);
2588 }
2589 return(0);
2590}
2591
2592/**
2593 * xmlXPathNodeLeadingSorted:
2594 * @nodes: a node-set, sorted by document order
2595 * @node: a node
2596 *
2597 * Implements the EXSLT - Sets leading() function:
2598 * node-set set:leading (node-set, node-set)
2599 *
2600 * Returns the nodes in @nodes that precede @node in document order,
2601 * @nodes if @node is NULL or an empty node-set if @nodes
2602 * doesn't contain @node
2603 */
2604xmlNodeSetPtr
2605xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2606 int i, l;
2607 xmlNodePtr cur;
2608 xmlNodeSetPtr ret;
2609
2610 if (node == NULL)
2611 return(nodes);
2612
2613 ret = xmlXPathNodeSetCreate(NULL);
2614 if (xmlXPathNodeSetIsEmpty(nodes) ||
2615 (!xmlXPathNodeSetContains(nodes, node)))
2616 return(ret);
2617
2618 l = xmlXPathNodeSetGetLength(nodes);
2619 for (i = 0; i < l; i++) {
2620 cur = xmlXPathNodeSetItem(nodes, i);
2621 if (cur == node)
2622 break;
2623 xmlXPathNodeSetAddUnique(ret, cur);
2624 }
2625 return(ret);
2626}
2627
2628/**
2629 * xmlXPathNodeLeading:
2630 * @nodes: a node-set
2631 * @node: a node
2632 *
2633 * Implements the EXSLT - Sets leading() function:
2634 * node-set set:leading (node-set, node-set)
2635 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2636 * is called.
2637 *
2638 * Returns the nodes in @nodes that precede @node in document order,
2639 * @nodes if @node is NULL or an empty node-set if @nodes
2640 * doesn't contain @node
2641 */
2642xmlNodeSetPtr
2643xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2644 xmlXPathNodeSetSort(nodes);
2645 return(xmlXPathNodeLeadingSorted(nodes, node));
2646}
2647
2648/**
2649 * xmlXPathLeadingSorted:
2650 * @nodes1: a node-set, sorted by document order
2651 * @nodes2: a node-set, sorted by document order
2652 *
2653 * Implements the EXSLT - Sets leading() function:
2654 * node-set set:leading (node-set, node-set)
2655 *
2656 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2657 * in document order, @nodes1 if @nodes2 is NULL or empty or
2658 * an empty node-set if @nodes1 doesn't contain @nodes2
2659 */
2660xmlNodeSetPtr
2661xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2662 if (xmlXPathNodeSetIsEmpty(nodes2))
2663 return(nodes1);
2664 return(xmlXPathNodeLeadingSorted(nodes1,
2665 xmlXPathNodeSetItem(nodes2, 1)));
2666}
2667
2668/**
2669 * xmlXPathLeading:
2670 * @nodes1: a node-set
2671 * @nodes2: a node-set
2672 *
2673 * Implements the EXSLT - Sets leading() function:
2674 * node-set set:leading (node-set, node-set)
2675 * @nodes1 and @nodes2 are sorted by document order, then
2676 * #exslSetsLeadingSorted is called.
2677 *
2678 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2679 * in document order, @nodes1 if @nodes2 is NULL or empty or
2680 * an empty node-set if @nodes1 doesn't contain @nodes2
2681 */
2682xmlNodeSetPtr
2683xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2684 if (xmlXPathNodeSetIsEmpty(nodes2))
2685 return(nodes1);
2686 if (xmlXPathNodeSetIsEmpty(nodes1))
2687 return(xmlXPathNodeSetCreate(NULL));
2688 xmlXPathNodeSetSort(nodes1);
2689 xmlXPathNodeSetSort(nodes2);
2690 return(xmlXPathNodeLeadingSorted(nodes1,
2691 xmlXPathNodeSetItem(nodes2, 1)));
2692}
2693
2694/**
2695 * xmlXPathNodeTrailingSorted:
2696 * @nodes: a node-set, sorted by document order
2697 * @node: a node
2698 *
2699 * Implements the EXSLT - Sets trailing() function:
2700 * node-set set:trailing (node-set, node-set)
2701 *
2702 * Returns the nodes in @nodes that follow @node in document order,
2703 * @nodes if @node is NULL or an empty node-set if @nodes
2704 * doesn't contain @node
2705 */
2706xmlNodeSetPtr
2707xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2708 int i, l;
2709 xmlNodePtr cur;
2710 xmlNodeSetPtr ret;
2711
2712 if (node == NULL)
2713 return(nodes);
2714
2715 ret = xmlXPathNodeSetCreate(NULL);
2716 if (xmlXPathNodeSetIsEmpty(nodes) ||
2717 (!xmlXPathNodeSetContains(nodes, node)))
2718 return(ret);
2719
2720 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002721 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002722 cur = xmlXPathNodeSetItem(nodes, i);
2723 if (cur == node)
2724 break;
2725 xmlXPathNodeSetAddUnique(ret, cur);
2726 }
2727 return(ret);
2728}
2729
2730/**
2731 * xmlXPathNodeTrailing:
2732 * @nodes: a node-set
2733 * @node: a node
2734 *
2735 * Implements the EXSLT - Sets trailing() function:
2736 * node-set set:trailing (node-set, node-set)
2737 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2738 * is called.
2739 *
2740 * Returns the nodes in @nodes that follow @node in document order,
2741 * @nodes if @node is NULL or an empty node-set if @nodes
2742 * doesn't contain @node
2743 */
2744xmlNodeSetPtr
2745xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2746 xmlXPathNodeSetSort(nodes);
2747 return(xmlXPathNodeTrailingSorted(nodes, node));
2748}
2749
2750/**
2751 * xmlXPathTrailingSorted:
2752 * @nodes1: a node-set, sorted by document order
2753 * @nodes2: a node-set, sorted by document order
2754 *
2755 * Implements the EXSLT - Sets trailing() function:
2756 * node-set set:trailing (node-set, node-set)
2757 *
2758 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2759 * in document order, @nodes1 if @nodes2 is NULL or empty or
2760 * an empty node-set if @nodes1 doesn't contain @nodes2
2761 */
2762xmlNodeSetPtr
2763xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2764 if (xmlXPathNodeSetIsEmpty(nodes2))
2765 return(nodes1);
2766 return(xmlXPathNodeTrailingSorted(nodes1,
2767 xmlXPathNodeSetItem(nodes2, 0)));
2768}
2769
2770/**
2771 * xmlXPathTrailing:
2772 * @nodes1: a node-set
2773 * @nodes2: a node-set
2774 *
2775 * Implements the EXSLT - Sets trailing() function:
2776 * node-set set:trailing (node-set, node-set)
2777 * @nodes1 and @nodes2 are sorted by document order, then
2778 * #xmlXPathTrailingSorted is called.
2779 *
2780 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2781 * in document order, @nodes1 if @nodes2 is NULL or empty or
2782 * an empty node-set if @nodes1 doesn't contain @nodes2
2783 */
2784xmlNodeSetPtr
2785xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2786 if (xmlXPathNodeSetIsEmpty(nodes2))
2787 return(nodes1);
2788 if (xmlXPathNodeSetIsEmpty(nodes1))
2789 return(xmlXPathNodeSetCreate(NULL));
2790 xmlXPathNodeSetSort(nodes1);
2791 xmlXPathNodeSetSort(nodes2);
2792 return(xmlXPathNodeTrailingSorted(nodes1,
2793 xmlXPathNodeSetItem(nodes2, 0)));
2794}
2795
Owen Taylor3473f882001-02-23 17:55:21 +00002796/************************************************************************
2797 * *
2798 * Routines to handle extra functions *
2799 * *
2800 ************************************************************************/
2801
2802/**
2803 * xmlXPathRegisterFunc:
2804 * @ctxt: the XPath context
2805 * @name: the function name
2806 * @f: the function implementation or NULL
2807 *
2808 * Register a new function. If @f is NULL it unregisters the function
2809 *
2810 * Returns 0 in case of success, -1 in case of error
2811 */
2812int
2813xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2814 xmlXPathFunction f) {
2815 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2816}
2817
2818/**
2819 * xmlXPathRegisterFuncNS:
2820 * @ctxt: the XPath context
2821 * @name: the function name
2822 * @ns_uri: the function namespace URI
2823 * @f: the function implementation or NULL
2824 *
2825 * Register a new function. If @f is NULL it unregisters the function
2826 *
2827 * Returns 0 in case of success, -1 in case of error
2828 */
2829int
2830xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2831 const xmlChar *ns_uri, xmlXPathFunction f) {
2832 if (ctxt == NULL)
2833 return(-1);
2834 if (name == NULL)
2835 return(-1);
2836
2837 if (ctxt->funcHash == NULL)
2838 ctxt->funcHash = xmlHashCreate(0);
2839 if (ctxt->funcHash == NULL)
2840 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002841 if (f == NULL)
2842 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00002843 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00002844}
2845
2846/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002847 * xmlXPathRegisterFuncLookup:
2848 * @ctxt: the XPath context
2849 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002850 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002851 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002852 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002853 */
2854void
2855xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2856 xmlXPathFuncLookupFunc f,
2857 void *funcCtxt) {
2858 if (ctxt == NULL)
2859 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002860 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002861 ctxt->funcLookupData = funcCtxt;
2862}
2863
2864/**
Owen Taylor3473f882001-02-23 17:55:21 +00002865 * xmlXPathFunctionLookup:
2866 * @ctxt: the XPath context
2867 * @name: the function name
2868 *
2869 * Search in the Function array of the context for the given
2870 * function.
2871 *
2872 * Returns the xmlXPathFunction or NULL if not found
2873 */
2874xmlXPathFunction
2875xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002876 if (ctxt == NULL)
2877 return (NULL);
2878
2879 if (ctxt->funcLookupFunc != NULL) {
2880 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002881 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002882
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002883 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002884 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002885 if (ret != NULL)
2886 return(ret);
2887 }
Owen Taylor3473f882001-02-23 17:55:21 +00002888 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2889}
2890
2891/**
2892 * xmlXPathFunctionLookupNS:
2893 * @ctxt: the XPath context
2894 * @name: the function name
2895 * @ns_uri: the function namespace URI
2896 *
2897 * Search in the Function array of the context for the given
2898 * function.
2899 *
2900 * Returns the xmlXPathFunction or NULL if not found
2901 */
2902xmlXPathFunction
2903xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2904 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00002905 xmlXPathFunction ret;
2906
Owen Taylor3473f882001-02-23 17:55:21 +00002907 if (ctxt == NULL)
2908 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002909 if (name == NULL)
2910 return(NULL);
2911
Thomas Broyerba4ad322001-07-26 16:55:21 +00002912 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002913 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002914
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002915 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002916 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002917 if (ret != NULL)
2918 return(ret);
2919 }
2920
2921 if (ctxt->funcHash == NULL)
2922 return(NULL);
2923
William M. Brackad0e67c2004-12-01 14:35:10 +00002924 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2925 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002926}
2927
2928/**
2929 * xmlXPathRegisteredFuncsCleanup:
2930 * @ctxt: the XPath context
2931 *
2932 * Cleanup the XPath context data associated to registered functions
2933 */
2934void
2935xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2936 if (ctxt == NULL)
2937 return;
2938
2939 xmlHashFree(ctxt->funcHash, NULL);
2940 ctxt->funcHash = NULL;
2941}
2942
2943/************************************************************************
2944 * *
William M. Brack08171912003-12-29 02:52:11 +00002945 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002946 * *
2947 ************************************************************************/
2948
2949/**
2950 * xmlXPathRegisterVariable:
2951 * @ctxt: the XPath context
2952 * @name: the variable name
2953 * @value: the variable value or NULL
2954 *
2955 * Register a new variable value. If @value is NULL it unregisters
2956 * the variable
2957 *
2958 * Returns 0 in case of success, -1 in case of error
2959 */
2960int
2961xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2962 xmlXPathObjectPtr value) {
2963 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2964}
2965
2966/**
2967 * xmlXPathRegisterVariableNS:
2968 * @ctxt: the XPath context
2969 * @name: the variable name
2970 * @ns_uri: the variable namespace URI
2971 * @value: the variable value or NULL
2972 *
2973 * Register a new variable value. If @value is NULL it unregisters
2974 * the variable
2975 *
2976 * Returns 0 in case of success, -1 in case of error
2977 */
2978int
2979xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2980 const xmlChar *ns_uri,
2981 xmlXPathObjectPtr value) {
2982 if (ctxt == NULL)
2983 return(-1);
2984 if (name == NULL)
2985 return(-1);
2986
2987 if (ctxt->varHash == NULL)
2988 ctxt->varHash = xmlHashCreate(0);
2989 if (ctxt->varHash == NULL)
2990 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002991 if (value == NULL)
2992 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2993 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002994 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2995 (void *) value,
2996 (xmlHashDeallocator)xmlXPathFreeObject));
2997}
2998
2999/**
3000 * xmlXPathRegisterVariableLookup:
3001 * @ctxt: the XPath context
3002 * @f: the lookup function
3003 * @data: the lookup data
3004 *
3005 * register an external mechanism to do variable lookup
3006 */
3007void
3008xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3009 xmlXPathVariableLookupFunc f, void *data) {
3010 if (ctxt == NULL)
3011 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003012 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003013 ctxt->varLookupData = data;
3014}
3015
3016/**
3017 * xmlXPathVariableLookup:
3018 * @ctxt: the XPath context
3019 * @name: the variable name
3020 *
3021 * Search in the Variable array of the context for the given
3022 * variable value.
3023 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003024 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003025 */
3026xmlXPathObjectPtr
3027xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3028 if (ctxt == NULL)
3029 return(NULL);
3030
3031 if (ctxt->varLookupFunc != NULL) {
3032 xmlXPathObjectPtr ret;
3033
3034 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3035 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003036 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003037 }
3038 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3039}
3040
3041/**
3042 * xmlXPathVariableLookupNS:
3043 * @ctxt: the XPath context
3044 * @name: the variable name
3045 * @ns_uri: the variable namespace URI
3046 *
3047 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003048 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003049 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003050 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003051 */
3052xmlXPathObjectPtr
3053xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3054 const xmlChar *ns_uri) {
3055 if (ctxt == NULL)
3056 return(NULL);
3057
3058 if (ctxt->varLookupFunc != NULL) {
3059 xmlXPathObjectPtr ret;
3060
3061 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3062 (ctxt->varLookupData, name, ns_uri);
3063 if (ret != NULL) return(ret);
3064 }
3065
3066 if (ctxt->varHash == NULL)
3067 return(NULL);
3068 if (name == NULL)
3069 return(NULL);
3070
Daniel Veillard8c357d52001-07-03 23:43:33 +00003071 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3072 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003073}
3074
3075/**
3076 * xmlXPathRegisteredVariablesCleanup:
3077 * @ctxt: the XPath context
3078 *
3079 * Cleanup the XPath context data associated to registered variables
3080 */
3081void
3082xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3083 if (ctxt == NULL)
3084 return;
3085
Daniel Veillard76d66f42001-05-16 21:05:17 +00003086 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 ctxt->varHash = NULL;
3088}
3089
3090/**
3091 * xmlXPathRegisterNs:
3092 * @ctxt: the XPath context
3093 * @prefix: the namespace prefix
3094 * @ns_uri: the namespace name
3095 *
3096 * Register a new namespace. If @ns_uri is NULL it unregisters
3097 * the namespace
3098 *
3099 * Returns 0 in case of success, -1 in case of error
3100 */
3101int
3102xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3103 const xmlChar *ns_uri) {
3104 if (ctxt == NULL)
3105 return(-1);
3106 if (prefix == NULL)
3107 return(-1);
3108
3109 if (ctxt->nsHash == NULL)
3110 ctxt->nsHash = xmlHashCreate(10);
3111 if (ctxt->nsHash == NULL)
3112 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003113 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003114 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003115 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003116 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003117 (xmlHashDeallocator)xmlFree));
3118}
3119
3120/**
3121 * xmlXPathNsLookup:
3122 * @ctxt: the XPath context
3123 * @prefix: the namespace prefix value
3124 *
3125 * Search in the namespace declaration array of the context for the given
3126 * namespace name associated to the given prefix
3127 *
3128 * Returns the value or NULL if not found
3129 */
3130const xmlChar *
3131xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3132 if (ctxt == NULL)
3133 return(NULL);
3134 if (prefix == NULL)
3135 return(NULL);
3136
3137#ifdef XML_XML_NAMESPACE
3138 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3139 return(XML_XML_NAMESPACE);
3140#endif
3141
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003142 if (ctxt->namespaces != NULL) {
3143 int i;
3144
3145 for (i = 0;i < ctxt->nsNr;i++) {
3146 if ((ctxt->namespaces[i] != NULL) &&
3147 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3148 return(ctxt->namespaces[i]->href);
3149 }
3150 }
Owen Taylor3473f882001-02-23 17:55:21 +00003151
3152 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3153}
3154
3155/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003156 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003157 * @ctxt: the XPath context
3158 *
3159 * Cleanup the XPath context data associated to registered variables
3160 */
3161void
3162xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3163 if (ctxt == NULL)
3164 return;
3165
Daniel Veillard42766c02002-08-22 20:52:17 +00003166 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003167 ctxt->nsHash = NULL;
3168}
3169
3170/************************************************************************
3171 * *
3172 * Routines to handle Values *
3173 * *
3174 ************************************************************************/
3175
William M. Brack08171912003-12-29 02:52:11 +00003176/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003177
3178/**
3179 * xmlXPathNewFloat:
3180 * @val: the double value
3181 *
3182 * Create a new xmlXPathObjectPtr of type double and of value @val
3183 *
3184 * Returns the newly created object.
3185 */
3186xmlXPathObjectPtr
3187xmlXPathNewFloat(double val) {
3188 xmlXPathObjectPtr ret;
3189
3190 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3191 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003192 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003193 return(NULL);
3194 }
3195 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3196 ret->type = XPATH_NUMBER;
3197 ret->floatval = val;
3198 return(ret);
3199}
3200
3201/**
3202 * xmlXPathNewBoolean:
3203 * @val: the boolean value
3204 *
3205 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3206 *
3207 * Returns the newly created object.
3208 */
3209xmlXPathObjectPtr
3210xmlXPathNewBoolean(int val) {
3211 xmlXPathObjectPtr ret;
3212
3213 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3214 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003215 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003216 return(NULL);
3217 }
3218 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3219 ret->type = XPATH_BOOLEAN;
3220 ret->boolval = (val != 0);
3221 return(ret);
3222}
3223
3224/**
3225 * xmlXPathNewString:
3226 * @val: the xmlChar * value
3227 *
3228 * Create a new xmlXPathObjectPtr of type string and of value @val
3229 *
3230 * Returns the newly created object.
3231 */
3232xmlXPathObjectPtr
3233xmlXPathNewString(const xmlChar *val) {
3234 xmlXPathObjectPtr ret;
3235
3236 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3237 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003238 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003239 return(NULL);
3240 }
3241 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3242 ret->type = XPATH_STRING;
3243 if (val != NULL)
3244 ret->stringval = xmlStrdup(val);
3245 else
3246 ret->stringval = xmlStrdup((const xmlChar *)"");
3247 return(ret);
3248}
3249
3250/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003251 * xmlXPathWrapString:
3252 * @val: the xmlChar * value
3253 *
3254 * Wraps the @val string into an XPath object.
3255 *
3256 * Returns the newly created object.
3257 */
3258xmlXPathObjectPtr
3259xmlXPathWrapString (xmlChar *val) {
3260 xmlXPathObjectPtr ret;
3261
3262 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3263 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003264 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003265 return(NULL);
3266 }
3267 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3268 ret->type = XPATH_STRING;
3269 ret->stringval = val;
3270 return(ret);
3271}
3272
3273/**
Owen Taylor3473f882001-02-23 17:55:21 +00003274 * xmlXPathNewCString:
3275 * @val: the char * value
3276 *
3277 * Create a new xmlXPathObjectPtr of type string and of value @val
3278 *
3279 * Returns the newly created object.
3280 */
3281xmlXPathObjectPtr
3282xmlXPathNewCString(const char *val) {
3283 xmlXPathObjectPtr ret;
3284
3285 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3286 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003287 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003288 return(NULL);
3289 }
3290 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3291 ret->type = XPATH_STRING;
3292 ret->stringval = xmlStrdup(BAD_CAST val);
3293 return(ret);
3294}
3295
3296/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003297 * xmlXPathWrapCString:
3298 * @val: the char * value
3299 *
3300 * Wraps a string into an XPath object.
3301 *
3302 * Returns the newly created object.
3303 */
3304xmlXPathObjectPtr
3305xmlXPathWrapCString (char * val) {
3306 return(xmlXPathWrapString((xmlChar *)(val)));
3307}
3308
3309/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003310 * xmlXPathWrapExternal:
3311 * @val: the user data
3312 *
3313 * Wraps the @val data into an XPath object.
3314 *
3315 * Returns the newly created object.
3316 */
3317xmlXPathObjectPtr
3318xmlXPathWrapExternal (void *val) {
3319 xmlXPathObjectPtr ret;
3320
3321 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3322 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003323 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003324 return(NULL);
3325 }
3326 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3327 ret->type = XPATH_USERS;
3328 ret->user = val;
3329 return(ret);
3330}
3331
3332/**
Owen Taylor3473f882001-02-23 17:55:21 +00003333 * xmlXPathObjectCopy:
3334 * @val: the original object
3335 *
3336 * allocate a new copy of a given object
3337 *
3338 * Returns the newly created object.
3339 */
3340xmlXPathObjectPtr
3341xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3342 xmlXPathObjectPtr ret;
3343
3344 if (val == NULL)
3345 return(NULL);
3346
3347 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3348 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003349 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003350 return(NULL);
3351 }
3352 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3353 switch (val->type) {
3354 case XPATH_BOOLEAN:
3355 case XPATH_NUMBER:
3356 case XPATH_POINT:
3357 case XPATH_RANGE:
3358 break;
3359 case XPATH_STRING:
3360 ret->stringval = xmlStrdup(val->stringval);
3361 break;
3362 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003363#if 0
3364/*
3365 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3366 this previous handling is no longer correct, and can cause some serious
3367 problems (ref. bug 145547)
3368*/
Owen Taylor3473f882001-02-23 17:55:21 +00003369 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003370 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003371 xmlNodePtr cur, tmp;
3372 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003373
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003374 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003375 top = xmlNewDoc(NULL);
3376 top->name = (char *)
3377 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003378 ret->user = top;
3379 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003380 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003381 cur = val->nodesetval->nodeTab[0]->children;
3382 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003383 tmp = xmlDocCopyNode(cur, top, 1);
3384 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003385 cur = cur->next;
3386 }
3387 }
William M. Bracke9449c52004-07-11 14:41:20 +00003388
Daniel Veillard9adc0462003-03-24 18:39:54 +00003389 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003390 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003391 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003392 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003393 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003394#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003395 case XPATH_NODESET:
3396 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003397 /* Do not deallocate the copied tree value */
3398 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003399 break;
3400 case XPATH_LOCATIONSET:
3401#ifdef LIBXML_XPTR_ENABLED
3402 {
3403 xmlLocationSetPtr loc = val->user;
3404 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3405 break;
3406 }
3407#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003408 case XPATH_USERS:
3409 ret->user = val->user;
3410 break;
3411 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003412 xmlGenericError(xmlGenericErrorContext,
3413 "xmlXPathObjectCopy: unsupported type %d\n",
3414 val->type);
3415 break;
3416 }
3417 return(ret);
3418}
3419
3420/**
3421 * xmlXPathFreeObject:
3422 * @obj: the object to free
3423 *
3424 * Free up an xmlXPathObjectPtr object.
3425 */
3426void
3427xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3428 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003429 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003430 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003431#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003432 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003433 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003434 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003435 } else
3436#endif
3437 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003438 xmlXPathFreeValueTree(obj->nodesetval);
3439 } else {
3440 if (obj->nodesetval != NULL)
3441 xmlXPathFreeNodeSet(obj->nodesetval);
3442 }
Owen Taylor3473f882001-02-23 17:55:21 +00003443#ifdef LIBXML_XPTR_ENABLED
3444 } else if (obj->type == XPATH_LOCATIONSET) {
3445 if (obj->user != NULL)
3446 xmlXPtrFreeLocationSet(obj->user);
3447#endif
3448 } else if (obj->type == XPATH_STRING) {
3449 if (obj->stringval != NULL)
3450 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003451 }
3452
Owen Taylor3473f882001-02-23 17:55:21 +00003453 xmlFree(obj);
3454}
3455
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003456
3457/************************************************************************
3458 * *
3459 * Type Casting Routines *
3460 * *
3461 ************************************************************************/
3462
3463/**
3464 * xmlXPathCastBooleanToString:
3465 * @val: a boolean
3466 *
3467 * Converts a boolean to its string value.
3468 *
3469 * Returns a newly allocated string.
3470 */
3471xmlChar *
3472xmlXPathCastBooleanToString (int val) {
3473 xmlChar *ret;
3474 if (val)
3475 ret = xmlStrdup((const xmlChar *) "true");
3476 else
3477 ret = xmlStrdup((const xmlChar *) "false");
3478 return(ret);
3479}
3480
3481/**
3482 * xmlXPathCastNumberToString:
3483 * @val: a number
3484 *
3485 * Converts a number to its string value.
3486 *
3487 * Returns a newly allocated string.
3488 */
3489xmlChar *
3490xmlXPathCastNumberToString (double val) {
3491 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003492 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003493 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003494 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003495 break;
3496 case -1:
3497 ret = xmlStrdup((const xmlChar *) "-Infinity");
3498 break;
3499 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003500 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003501 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003502 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3503 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003504 } else {
3505 /* could be improved */
3506 char buf[100];
3507 xmlXPathFormatNumber(val, buf, 100);
3508 ret = xmlStrdup((const xmlChar *) buf);
3509 }
3510 }
3511 return(ret);
3512}
3513
3514/**
3515 * xmlXPathCastNodeToString:
3516 * @node: a node
3517 *
3518 * Converts a node to its string value.
3519 *
3520 * Returns a newly allocated string.
3521 */
3522xmlChar *
3523xmlXPathCastNodeToString (xmlNodePtr node) {
3524 return(xmlNodeGetContent(node));
3525}
3526
3527/**
3528 * xmlXPathCastNodeSetToString:
3529 * @ns: a node-set
3530 *
3531 * Converts a node-set to its string value.
3532 *
3533 * Returns a newly allocated string.
3534 */
3535xmlChar *
3536xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3537 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3538 return(xmlStrdup((const xmlChar *) ""));
3539
3540 xmlXPathNodeSetSort(ns);
3541 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3542}
3543
3544/**
3545 * xmlXPathCastToString:
3546 * @val: an XPath object
3547 *
3548 * Converts an existing object to its string() equivalent
3549 *
3550 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003551 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003552 * string object).
3553 */
3554xmlChar *
3555xmlXPathCastToString(xmlXPathObjectPtr val) {
3556 xmlChar *ret = NULL;
3557
3558 if (val == NULL)
3559 return(xmlStrdup((const xmlChar *) ""));
3560 switch (val->type) {
3561 case XPATH_UNDEFINED:
3562#ifdef DEBUG_EXPR
3563 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3564#endif
3565 ret = xmlStrdup((const xmlChar *) "");
3566 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003567 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003568 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003569 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3570 break;
3571 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003572 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003573 case XPATH_BOOLEAN:
3574 ret = xmlXPathCastBooleanToString(val->boolval);
3575 break;
3576 case XPATH_NUMBER: {
3577 ret = xmlXPathCastNumberToString(val->floatval);
3578 break;
3579 }
3580 case XPATH_USERS:
3581 case XPATH_POINT:
3582 case XPATH_RANGE:
3583 case XPATH_LOCATIONSET:
3584 TODO
3585 ret = xmlStrdup((const xmlChar *) "");
3586 break;
3587 }
3588 return(ret);
3589}
3590
3591/**
3592 * xmlXPathConvertString:
3593 * @val: an XPath object
3594 *
3595 * Converts an existing object to its string() equivalent
3596 *
3597 * Returns the new object, the old one is freed (or the operation
3598 * is done directly on @val)
3599 */
3600xmlXPathObjectPtr
3601xmlXPathConvertString(xmlXPathObjectPtr val) {
3602 xmlChar *res = NULL;
3603
3604 if (val == NULL)
3605 return(xmlXPathNewCString(""));
3606
3607 switch (val->type) {
3608 case XPATH_UNDEFINED:
3609#ifdef DEBUG_EXPR
3610 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3611#endif
3612 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003613 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003614 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003615 res = xmlXPathCastNodeSetToString(val->nodesetval);
3616 break;
3617 case XPATH_STRING:
3618 return(val);
3619 case XPATH_BOOLEAN:
3620 res = xmlXPathCastBooleanToString(val->boolval);
3621 break;
3622 case XPATH_NUMBER:
3623 res = xmlXPathCastNumberToString(val->floatval);
3624 break;
3625 case XPATH_USERS:
3626 case XPATH_POINT:
3627 case XPATH_RANGE:
3628 case XPATH_LOCATIONSET:
3629 TODO;
3630 break;
3631 }
3632 xmlXPathFreeObject(val);
3633 if (res == NULL)
3634 return(xmlXPathNewCString(""));
3635 return(xmlXPathWrapString(res));
3636}
3637
3638/**
3639 * xmlXPathCastBooleanToNumber:
3640 * @val: a boolean
3641 *
3642 * Converts a boolean to its number value
3643 *
3644 * Returns the number value
3645 */
3646double
3647xmlXPathCastBooleanToNumber(int val) {
3648 if (val)
3649 return(1.0);
3650 return(0.0);
3651}
3652
3653/**
3654 * xmlXPathCastStringToNumber:
3655 * @val: a string
3656 *
3657 * Converts a string to its number value
3658 *
3659 * Returns the number value
3660 */
3661double
3662xmlXPathCastStringToNumber(const xmlChar * val) {
3663 return(xmlXPathStringEvalNumber(val));
3664}
3665
3666/**
3667 * xmlXPathCastNodeToNumber:
3668 * @node: a node
3669 *
3670 * Converts a node to its number value
3671 *
3672 * Returns the number value
3673 */
3674double
3675xmlXPathCastNodeToNumber (xmlNodePtr node) {
3676 xmlChar *strval;
3677 double ret;
3678
3679 if (node == NULL)
3680 return(xmlXPathNAN);
3681 strval = xmlXPathCastNodeToString(node);
3682 if (strval == NULL)
3683 return(xmlXPathNAN);
3684 ret = xmlXPathCastStringToNumber(strval);
3685 xmlFree(strval);
3686
3687 return(ret);
3688}
3689
3690/**
3691 * xmlXPathCastNodeSetToNumber:
3692 * @ns: a node-set
3693 *
3694 * Converts a node-set to its number value
3695 *
3696 * Returns the number value
3697 */
3698double
3699xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3700 xmlChar *str;
3701 double ret;
3702
3703 if (ns == NULL)
3704 return(xmlXPathNAN);
3705 str = xmlXPathCastNodeSetToString(ns);
3706 ret = xmlXPathCastStringToNumber(str);
3707 xmlFree(str);
3708 return(ret);
3709}
3710
3711/**
3712 * xmlXPathCastToNumber:
3713 * @val: an XPath object
3714 *
3715 * Converts an XPath object to its number value
3716 *
3717 * Returns the number value
3718 */
3719double
3720xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3721 double ret = 0.0;
3722
3723 if (val == NULL)
3724 return(xmlXPathNAN);
3725 switch (val->type) {
3726 case XPATH_UNDEFINED:
3727#ifdef DEGUB_EXPR
3728 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3729#endif
3730 ret = xmlXPathNAN;
3731 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003732 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003733 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003734 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3735 break;
3736 case XPATH_STRING:
3737 ret = xmlXPathCastStringToNumber(val->stringval);
3738 break;
3739 case XPATH_NUMBER:
3740 ret = val->floatval;
3741 break;
3742 case XPATH_BOOLEAN:
3743 ret = xmlXPathCastBooleanToNumber(val->boolval);
3744 break;
3745 case XPATH_USERS:
3746 case XPATH_POINT:
3747 case XPATH_RANGE:
3748 case XPATH_LOCATIONSET:
3749 TODO;
3750 ret = xmlXPathNAN;
3751 break;
3752 }
3753 return(ret);
3754}
3755
3756/**
3757 * xmlXPathConvertNumber:
3758 * @val: an XPath object
3759 *
3760 * Converts an existing object to its number() equivalent
3761 *
3762 * Returns the new object, the old one is freed (or the operation
3763 * is done directly on @val)
3764 */
3765xmlXPathObjectPtr
3766xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3767 xmlXPathObjectPtr ret;
3768
3769 if (val == NULL)
3770 return(xmlXPathNewFloat(0.0));
3771 if (val->type == XPATH_NUMBER)
3772 return(val);
3773 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3774 xmlXPathFreeObject(val);
3775 return(ret);
3776}
3777
3778/**
3779 * xmlXPathCastNumberToBoolean:
3780 * @val: a number
3781 *
3782 * Converts a number to its boolean value
3783 *
3784 * Returns the boolean value
3785 */
3786int
3787xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003788 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003789 return(0);
3790 return(1);
3791}
3792
3793/**
3794 * xmlXPathCastStringToBoolean:
3795 * @val: a string
3796 *
3797 * Converts a string to its boolean value
3798 *
3799 * Returns the boolean value
3800 */
3801int
3802xmlXPathCastStringToBoolean (const xmlChar *val) {
3803 if ((val == NULL) || (xmlStrlen(val) == 0))
3804 return(0);
3805 return(1);
3806}
3807
3808/**
3809 * xmlXPathCastNodeSetToBoolean:
3810 * @ns: a node-set
3811 *
3812 * Converts a node-set to its boolean value
3813 *
3814 * Returns the boolean value
3815 */
3816int
3817xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3818 if ((ns == NULL) || (ns->nodeNr == 0))
3819 return(0);
3820 return(1);
3821}
3822
3823/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003824 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003825 * @val: an XPath object
3826 *
3827 * Converts an XPath object to its boolean value
3828 *
3829 * Returns the boolean value
3830 */
3831int
3832xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3833 int ret = 0;
3834
3835 if (val == NULL)
3836 return(0);
3837 switch (val->type) {
3838 case XPATH_UNDEFINED:
3839#ifdef DEBUG_EXPR
3840 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3841#endif
3842 ret = 0;
3843 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003844 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003845 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003846 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3847 break;
3848 case XPATH_STRING:
3849 ret = xmlXPathCastStringToBoolean(val->stringval);
3850 break;
3851 case XPATH_NUMBER:
3852 ret = xmlXPathCastNumberToBoolean(val->floatval);
3853 break;
3854 case XPATH_BOOLEAN:
3855 ret = val->boolval;
3856 break;
3857 case XPATH_USERS:
3858 case XPATH_POINT:
3859 case XPATH_RANGE:
3860 case XPATH_LOCATIONSET:
3861 TODO;
3862 ret = 0;
3863 break;
3864 }
3865 return(ret);
3866}
3867
3868
3869/**
3870 * xmlXPathConvertBoolean:
3871 * @val: an XPath object
3872 *
3873 * Converts an existing object to its boolean() equivalent
3874 *
3875 * Returns the new object, the old one is freed (or the operation
3876 * is done directly on @val)
3877 */
3878xmlXPathObjectPtr
3879xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3880 xmlXPathObjectPtr ret;
3881
3882 if (val == NULL)
3883 return(xmlXPathNewBoolean(0));
3884 if (val->type == XPATH_BOOLEAN)
3885 return(val);
3886 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3887 xmlXPathFreeObject(val);
3888 return(ret);
3889}
3890
Owen Taylor3473f882001-02-23 17:55:21 +00003891/************************************************************************
3892 * *
3893 * Routines to handle XPath contexts *
3894 * *
3895 ************************************************************************/
3896
3897/**
3898 * xmlXPathNewContext:
3899 * @doc: the XML document
3900 *
3901 * Create a new xmlXPathContext
3902 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003903 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003904 */
3905xmlXPathContextPtr
3906xmlXPathNewContext(xmlDocPtr doc) {
3907 xmlXPathContextPtr ret;
3908
3909 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3910 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003911 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003912 return(NULL);
3913 }
3914 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3915 ret->doc = doc;
3916 ret->node = NULL;
3917
3918 ret->varHash = NULL;
3919
3920 ret->nb_types = 0;
3921 ret->max_types = 0;
3922 ret->types = NULL;
3923
3924 ret->funcHash = xmlHashCreate(0);
3925
3926 ret->nb_axis = 0;
3927 ret->max_axis = 0;
3928 ret->axis = NULL;
3929
3930 ret->nsHash = NULL;
3931 ret->user = NULL;
3932
3933 ret->contextSize = -1;
3934 ret->proximityPosition = -1;
3935
3936 xmlXPathRegisterAllFunctions(ret);
3937
3938 return(ret);
3939}
3940
3941/**
3942 * xmlXPathFreeContext:
3943 * @ctxt: the context to free
3944 *
3945 * Free up an xmlXPathContext
3946 */
3947void
3948xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003949 if (ctxt == NULL) return;
3950
Owen Taylor3473f882001-02-23 17:55:21 +00003951 xmlXPathRegisteredNsCleanup(ctxt);
3952 xmlXPathRegisteredFuncsCleanup(ctxt);
3953 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003954 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00003955 xmlFree(ctxt);
3956}
3957
3958/************************************************************************
3959 * *
3960 * Routines to handle XPath parser contexts *
3961 * *
3962 ************************************************************************/
3963
3964#define CHECK_CTXT(ctxt) \
3965 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003966 __xmlRaiseError(NULL, NULL, NULL, \
3967 NULL, NULL, XML_FROM_XPATH, \
3968 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3969 __FILE__, __LINE__, \
3970 NULL, NULL, NULL, 0, 0, \
3971 "NULL context pointer\n"); \
3972 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003973 } \
3974
3975
3976#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003977 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3978 (ctxt->doc->children == NULL)) { \
3979 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003980 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003981 }
Owen Taylor3473f882001-02-23 17:55:21 +00003982
3983
3984/**
3985 * xmlXPathNewParserContext:
3986 * @str: the XPath expression
3987 * @ctxt: the XPath context
3988 *
3989 * Create a new xmlXPathParserContext
3990 *
3991 * Returns the xmlXPathParserContext just allocated.
3992 */
3993xmlXPathParserContextPtr
3994xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3995 xmlXPathParserContextPtr ret;
3996
3997 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3998 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003999 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004000 return(NULL);
4001 }
4002 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4003 ret->cur = ret->base = str;
4004 ret->context = ctxt;
4005
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004006 ret->comp = xmlXPathNewCompExpr();
4007 if (ret->comp == NULL) {
4008 xmlFree(ret->valueTab);
4009 xmlFree(ret);
4010 return(NULL);
4011 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004012 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4013 ret->comp->dict = ctxt->dict;
4014 xmlDictReference(ret->comp->dict);
4015 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004016
4017 return(ret);
4018}
4019
4020/**
4021 * xmlXPathCompParserContext:
4022 * @comp: the XPath compiled expression
4023 * @ctxt: the XPath context
4024 *
4025 * Create a new xmlXPathParserContext when processing a compiled expression
4026 *
4027 * Returns the xmlXPathParserContext just allocated.
4028 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004029static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004030xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4031 xmlXPathParserContextPtr ret;
4032
4033 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4034 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004035 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004036 return(NULL);
4037 }
4038 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4039
Owen Taylor3473f882001-02-23 17:55:21 +00004040 /* Allocate the value stack */
4041 ret->valueTab = (xmlXPathObjectPtr *)
4042 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004043 if (ret->valueTab == NULL) {
4044 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004045 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004046 return(NULL);
4047 }
Owen Taylor3473f882001-02-23 17:55:21 +00004048 ret->valueNr = 0;
4049 ret->valueMax = 10;
4050 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004051
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004052 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004053 ret->comp = comp;
4054
Owen Taylor3473f882001-02-23 17:55:21 +00004055 return(ret);
4056}
4057
4058/**
4059 * xmlXPathFreeParserContext:
4060 * @ctxt: the context to free
4061 *
4062 * Free up an xmlXPathParserContext
4063 */
4064void
4065xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4066 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004067 xmlFree(ctxt->valueTab);
4068 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004069 if (ctxt->comp != NULL) {
4070#ifdef XPATH_STREAMING
4071 if (ctxt->comp->stream != NULL) {
4072 xmlFreePatternList(ctxt->comp->stream);
4073 ctxt->comp->stream = NULL;
4074 }
4075#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004076 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004077 }
Owen Taylor3473f882001-02-23 17:55:21 +00004078 xmlFree(ctxt);
4079}
4080
4081/************************************************************************
4082 * *
4083 * The implicit core function library *
4084 * *
4085 ************************************************************************/
4086
Owen Taylor3473f882001-02-23 17:55:21 +00004087/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004088 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004089 * @node: a node pointer
4090 *
4091 * Function computing the beginning of the string value of the node,
4092 * used to speed up comparisons
4093 *
4094 * Returns an int usable as a hash
4095 */
4096static unsigned int
4097xmlXPathNodeValHash(xmlNodePtr node) {
4098 int len = 2;
4099 const xmlChar * string = NULL;
4100 xmlNodePtr tmp = NULL;
4101 unsigned int ret = 0;
4102
4103 if (node == NULL)
4104 return(0);
4105
Daniel Veillard9adc0462003-03-24 18:39:54 +00004106 if (node->type == XML_DOCUMENT_NODE) {
4107 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4108 if (tmp == NULL)
4109 node = node->children;
4110 else
4111 node = tmp;
4112
4113 if (node == NULL)
4114 return(0);
4115 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004116
4117 switch (node->type) {
4118 case XML_COMMENT_NODE:
4119 case XML_PI_NODE:
4120 case XML_CDATA_SECTION_NODE:
4121 case XML_TEXT_NODE:
4122 string = node->content;
4123 if (string == NULL)
4124 return(0);
4125 if (string[0] == 0)
4126 return(0);
4127 return(((unsigned int) string[0]) +
4128 (((unsigned int) string[1]) << 8));
4129 case XML_NAMESPACE_DECL:
4130 string = ((xmlNsPtr)node)->href;
4131 if (string == NULL)
4132 return(0);
4133 if (string[0] == 0)
4134 return(0);
4135 return(((unsigned int) string[0]) +
4136 (((unsigned int) string[1]) << 8));
4137 case XML_ATTRIBUTE_NODE:
4138 tmp = ((xmlAttrPtr) node)->children;
4139 break;
4140 case XML_ELEMENT_NODE:
4141 tmp = node->children;
4142 break;
4143 default:
4144 return(0);
4145 }
4146 while (tmp != NULL) {
4147 switch (tmp->type) {
4148 case XML_COMMENT_NODE:
4149 case XML_PI_NODE:
4150 case XML_CDATA_SECTION_NODE:
4151 case XML_TEXT_NODE:
4152 string = tmp->content;
4153 break;
4154 case XML_NAMESPACE_DECL:
4155 string = ((xmlNsPtr)tmp)->href;
4156 break;
4157 default:
4158 break;
4159 }
4160 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004161 if (len == 1) {
4162 return(ret + (((unsigned int) string[0]) << 8));
4163 }
4164 if (string[1] == 0) {
4165 len = 1;
4166 ret = (unsigned int) string[0];
4167 } else {
4168 return(((unsigned int) string[0]) +
4169 (((unsigned int) string[1]) << 8));
4170 }
4171 }
4172 /*
4173 * Skip to next node
4174 */
4175 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4176 if (tmp->children->type != XML_ENTITY_DECL) {
4177 tmp = tmp->children;
4178 continue;
4179 }
4180 }
4181 if (tmp == node)
4182 break;
4183
4184 if (tmp->next != NULL) {
4185 tmp = tmp->next;
4186 continue;
4187 }
4188
4189 do {
4190 tmp = tmp->parent;
4191 if (tmp == NULL)
4192 break;
4193 if (tmp == node) {
4194 tmp = NULL;
4195 break;
4196 }
4197 if (tmp->next != NULL) {
4198 tmp = tmp->next;
4199 break;
4200 }
4201 } while (tmp != NULL);
4202 }
4203 return(ret);
4204}
4205
4206/**
4207 * xmlXPathStringHash:
4208 * @string: a string
4209 *
4210 * Function computing the beginning of the string value of the node,
4211 * used to speed up comparisons
4212 *
4213 * Returns an int usable as a hash
4214 */
4215static unsigned int
4216xmlXPathStringHash(const xmlChar * string) {
4217 if (string == NULL)
4218 return((unsigned int) 0);
4219 if (string[0] == 0)
4220 return(0);
4221 return(((unsigned int) string[0]) +
4222 (((unsigned int) string[1]) << 8));
4223}
4224
4225/**
Owen Taylor3473f882001-02-23 17:55:21 +00004226 * xmlXPathCompareNodeSetFloat:
4227 * @ctxt: the XPath Parser context
4228 * @inf: less than (1) or greater than (0)
4229 * @strict: is the comparison strict
4230 * @arg: the node set
4231 * @f: the value
4232 *
4233 * Implement the compare operation between a nodeset and a number
4234 * @ns < @val (1, 1, ...
4235 * @ns <= @val (1, 0, ...
4236 * @ns > @val (0, 1, ...
4237 * @ns >= @val (0, 0, ...
4238 *
4239 * If one object to be compared is a node-set and the other is a number,
4240 * then the comparison will be true if and only if there is a node in the
4241 * node-set such that the result of performing the comparison on the number
4242 * to be compared and on the result of converting the string-value of that
4243 * node to a number using the number function is true.
4244 *
4245 * Returns 0 or 1 depending on the results of the test.
4246 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004247static int
Owen Taylor3473f882001-02-23 17:55:21 +00004248xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4249 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4250 int i, ret = 0;
4251 xmlNodeSetPtr ns;
4252 xmlChar *str2;
4253
4254 if ((f == NULL) || (arg == NULL) ||
4255 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4256 xmlXPathFreeObject(arg);
4257 xmlXPathFreeObject(f);
4258 return(0);
4259 }
4260 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004261 if (ns != NULL) {
4262 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004263 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004264 if (str2 != NULL) {
4265 valuePush(ctxt,
4266 xmlXPathNewString(str2));
4267 xmlFree(str2);
4268 xmlXPathNumberFunction(ctxt, 1);
4269 valuePush(ctxt, xmlXPathObjectCopy(f));
4270 ret = xmlXPathCompareValues(ctxt, inf, strict);
4271 if (ret)
4272 break;
4273 }
4274 }
Owen Taylor3473f882001-02-23 17:55:21 +00004275 }
4276 xmlXPathFreeObject(arg);
4277 xmlXPathFreeObject(f);
4278 return(ret);
4279}
4280
4281/**
4282 * xmlXPathCompareNodeSetString:
4283 * @ctxt: the XPath Parser context
4284 * @inf: less than (1) or greater than (0)
4285 * @strict: is the comparison strict
4286 * @arg: the node set
4287 * @s: the value
4288 *
4289 * Implement the compare operation between a nodeset and a string
4290 * @ns < @val (1, 1, ...
4291 * @ns <= @val (1, 0, ...
4292 * @ns > @val (0, 1, ...
4293 * @ns >= @val (0, 0, ...
4294 *
4295 * If one object to be compared is a node-set and the other is a string,
4296 * then the comparison will be true if and only if there is a node in
4297 * the node-set such that the result of performing the comparison on the
4298 * string-value of the node and the other string is true.
4299 *
4300 * Returns 0 or 1 depending on the results of the test.
4301 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004302static int
Owen Taylor3473f882001-02-23 17:55:21 +00004303xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4304 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4305 int i, ret = 0;
4306 xmlNodeSetPtr ns;
4307 xmlChar *str2;
4308
4309 if ((s == NULL) || (arg == NULL) ||
4310 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4311 xmlXPathFreeObject(arg);
4312 xmlXPathFreeObject(s);
4313 return(0);
4314 }
4315 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004316 if (ns != NULL) {
4317 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004318 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004319 if (str2 != NULL) {
4320 valuePush(ctxt,
4321 xmlXPathNewString(str2));
4322 xmlFree(str2);
4323 valuePush(ctxt, xmlXPathObjectCopy(s));
4324 ret = xmlXPathCompareValues(ctxt, inf, strict);
4325 if (ret)
4326 break;
4327 }
4328 }
Owen Taylor3473f882001-02-23 17:55:21 +00004329 }
4330 xmlXPathFreeObject(arg);
4331 xmlXPathFreeObject(s);
4332 return(ret);
4333}
4334
4335/**
4336 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004337 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004338 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004339 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004340 * @arg2: the second node set object
4341 *
4342 * Implement the compare operation on nodesets:
4343 *
4344 * If both objects to be compared are node-sets, then the comparison
4345 * will be true if and only if there is a node in the first node-set
4346 * and a node in the second node-set such that the result of performing
4347 * the comparison on the string-values of the two nodes is true.
4348 * ....
4349 * When neither object to be compared is a node-set and the operator
4350 * is <=, <, >= or >, then the objects are compared by converting both
4351 * objects to numbers and comparing the numbers according to IEEE 754.
4352 * ....
4353 * The number function converts its argument to a number as follows:
4354 * - a string that consists of optional whitespace followed by an
4355 * optional minus sign followed by a Number followed by whitespace
4356 * is converted to the IEEE 754 number that is nearest (according
4357 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4358 * represented by the string; any other string is converted to NaN
4359 *
4360 * Conclusion all nodes need to be converted first to their string value
4361 * and then the comparison must be done when possible
4362 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004363static int
4364xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004365 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4366 int i, j, init = 0;
4367 double val1;
4368 double *values2;
4369 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004370 xmlNodeSetPtr ns1;
4371 xmlNodeSetPtr ns2;
4372
4373 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004374 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4375 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004376 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004377 }
Owen Taylor3473f882001-02-23 17:55:21 +00004378 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004379 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4380 xmlXPathFreeObject(arg1);
4381 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004383 }
Owen Taylor3473f882001-02-23 17:55:21 +00004384
4385 ns1 = arg1->nodesetval;
4386 ns2 = arg2->nodesetval;
4387
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004388 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004389 xmlXPathFreeObject(arg1);
4390 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004391 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004392 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004393 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004394 xmlXPathFreeObject(arg1);
4395 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004396 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004397 }
Owen Taylor3473f882001-02-23 17:55:21 +00004398
4399 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4400 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004401 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004402 xmlXPathFreeObject(arg1);
4403 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004404 return(0);
4405 }
4406 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004407 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004408 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004409 continue;
4410 for (j = 0;j < ns2->nodeNr;j++) {
4411 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004412 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004413 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004414 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004415 continue;
4416 if (inf && strict)
4417 ret = (val1 < values2[j]);
4418 else if (inf && !strict)
4419 ret = (val1 <= values2[j]);
4420 else if (!inf && strict)
4421 ret = (val1 > values2[j]);
4422 else if (!inf && !strict)
4423 ret = (val1 >= values2[j]);
4424 if (ret)
4425 break;
4426 }
4427 if (ret)
4428 break;
4429 init = 1;
4430 }
4431 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004432 xmlXPathFreeObject(arg1);
4433 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004434 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004435}
4436
4437/**
4438 * xmlXPathCompareNodeSetValue:
4439 * @ctxt: the XPath Parser context
4440 * @inf: less than (1) or greater than (0)
4441 * @strict: is the comparison strict
4442 * @arg: the node set
4443 * @val: the value
4444 *
4445 * Implement the compare operation between a nodeset and a value
4446 * @ns < @val (1, 1, ...
4447 * @ns <= @val (1, 0, ...
4448 * @ns > @val (0, 1, ...
4449 * @ns >= @val (0, 0, ...
4450 *
4451 * If one object to be compared is a node-set and the other is a boolean,
4452 * then the comparison will be true if and only if the result of performing
4453 * the comparison on the boolean and on the result of converting
4454 * the node-set to a boolean using the boolean function is true.
4455 *
4456 * Returns 0 or 1 depending on the results of the test.
4457 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004458static int
Owen Taylor3473f882001-02-23 17:55:21 +00004459xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4460 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4461 if ((val == NULL) || (arg == NULL) ||
4462 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4463 return(0);
4464
4465 switch(val->type) {
4466 case XPATH_NUMBER:
4467 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4468 case XPATH_NODESET:
4469 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004470 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004471 case XPATH_STRING:
4472 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4473 case XPATH_BOOLEAN:
4474 valuePush(ctxt, arg);
4475 xmlXPathBooleanFunction(ctxt, 1);
4476 valuePush(ctxt, val);
4477 return(xmlXPathCompareValues(ctxt, inf, strict));
4478 default:
4479 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004480 }
4481 return(0);
4482}
4483
4484/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004485 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004486 * @arg: the nodeset object argument
4487 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004488 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004489 *
4490 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4491 * If one object to be compared is a node-set and the other is a string,
4492 * then the comparison will be true if and only if there is a node in
4493 * the node-set such that the result of performing the comparison on the
4494 * string-value of the node and the other string is true.
4495 *
4496 * Returns 0 or 1 depending on the results of the test.
4497 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004498static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004499xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004500{
Owen Taylor3473f882001-02-23 17:55:21 +00004501 int i;
4502 xmlNodeSetPtr ns;
4503 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004504 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004505
4506 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004507 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4508 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004509 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004510 /*
4511 * A NULL nodeset compared with a string is always false
4512 * (since there is no node equal, and no node not equal)
4513 */
4514 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004515 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004516 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004517 for (i = 0; i < ns->nodeNr; i++) {
4518 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4519 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4520 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4521 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004522 if (neq)
4523 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004524 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004525 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4526 if (neq)
4527 continue;
4528 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004529 } else if (neq) {
4530 if (str2 != NULL)
4531 xmlFree(str2);
4532 return (1);
4533 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004534 if (str2 != NULL)
4535 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004536 } else if (neq)
4537 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004538 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004539 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004540}
4541
4542/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004543 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004544 * @arg: the nodeset object argument
4545 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004546 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004547 *
4548 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4549 * If one object to be compared is a node-set and the other is a number,
4550 * then the comparison will be true if and only if there is a node in
4551 * the node-set such that the result of performing the comparison on the
4552 * number to be compared and on the result of converting the string-value
4553 * of that node to a number using the number function is true.
4554 *
4555 * Returns 0 or 1 depending on the results of the test.
4556 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004557static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004558xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4559 xmlXPathObjectPtr arg, double f, int neq) {
4560 int i, ret=0;
4561 xmlNodeSetPtr ns;
4562 xmlChar *str2;
4563 xmlXPathObjectPtr val;
4564 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004565
4566 if ((arg == NULL) ||
4567 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4568 return(0);
4569
William M. Brack0c022ad2002-07-12 00:56:01 +00004570 ns = arg->nodesetval;
4571 if (ns != NULL) {
4572 for (i=0;i<ns->nodeNr;i++) {
4573 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4574 if (str2 != NULL) {
4575 valuePush(ctxt, xmlXPathNewString(str2));
4576 xmlFree(str2);
4577 xmlXPathNumberFunction(ctxt, 1);
4578 val = valuePop(ctxt);
4579 v = val->floatval;
4580 xmlXPathFreeObject(val);
4581 if (!xmlXPathIsNaN(v)) {
4582 if ((!neq) && (v==f)) {
4583 ret = 1;
4584 break;
4585 } else if ((neq) && (v!=f)) {
4586 ret = 1;
4587 break;
4588 }
William M. Brack32f0f712005-07-14 07:00:33 +00004589 } else { /* NaN is unequal to any value */
4590 if (neq)
4591 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00004592 }
4593 }
4594 }
4595 }
4596
4597 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004598}
4599
4600
4601/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004602 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004603 * @arg1: first nodeset object argument
4604 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004605 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004606 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004607 * Implement the equal / not equal operation on XPath nodesets:
4608 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004609 * If both objects to be compared are node-sets, then the comparison
4610 * will be true if and only if there is a node in the first node-set and
4611 * a node in the second node-set such that the result of performing the
4612 * comparison on the string-values of the two nodes is true.
4613 *
4614 * (needless to say, this is a costly operation)
4615 *
4616 * Returns 0 or 1 depending on the results of the test.
4617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004618static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004619xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004620 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004621 unsigned int *hashs1;
4622 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004623 xmlChar **values1;
4624 xmlChar **values2;
4625 int ret = 0;
4626 xmlNodeSetPtr ns1;
4627 xmlNodeSetPtr ns2;
4628
4629 if ((arg1 == NULL) ||
4630 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4631 return(0);
4632 if ((arg2 == NULL) ||
4633 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4634 return(0);
4635
4636 ns1 = arg1->nodesetval;
4637 ns2 = arg2->nodesetval;
4638
Daniel Veillard911f49a2001-04-07 15:39:35 +00004639 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004640 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004641 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004642 return(0);
4643
4644 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004645 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004646 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004647 if (neq == 0)
4648 for (i = 0;i < ns1->nodeNr;i++)
4649 for (j = 0;j < ns2->nodeNr;j++)
4650 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4651 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004652
4653 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004654 if (values1 == NULL) {
4655 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004656 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004657 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004658 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4659 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004660 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004661 xmlFree(values1);
4662 return(0);
4663 }
Owen Taylor3473f882001-02-23 17:55:21 +00004664 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4665 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4666 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004667 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004668 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004669 xmlFree(values1);
4670 return(0);
4671 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004672 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4673 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004674 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004675 xmlFree(hashs1);
4676 xmlFree(values1);
4677 xmlFree(values2);
4678 return(0);
4679 }
Owen Taylor3473f882001-02-23 17:55:21 +00004680 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4681 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004682 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004683 for (j = 0;j < ns2->nodeNr;j++) {
4684 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004685 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004686 if (hashs1[i] != hashs2[j]) {
4687 if (neq) {
4688 ret = 1;
4689 break;
4690 }
4691 }
4692 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004693 if (values1[i] == NULL)
4694 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4695 if (values2[j] == NULL)
4696 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004697 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004698 if (ret)
4699 break;
4700 }
Owen Taylor3473f882001-02-23 17:55:21 +00004701 }
4702 if (ret)
4703 break;
4704 }
4705 for (i = 0;i < ns1->nodeNr;i++)
4706 if (values1[i] != NULL)
4707 xmlFree(values1[i]);
4708 for (j = 0;j < ns2->nodeNr;j++)
4709 if (values2[j] != NULL)
4710 xmlFree(values2[j]);
4711 xmlFree(values1);
4712 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004713 xmlFree(hashs1);
4714 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004715 return(ret);
4716}
4717
William M. Brack0c022ad2002-07-12 00:56:01 +00004718static int
4719xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4720 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004721 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004722 /*
4723 *At this point we are assured neither arg1 nor arg2
4724 *is a nodeset, so we can just pick the appropriate routine.
4725 */
Owen Taylor3473f882001-02-23 17:55:21 +00004726 switch (arg1->type) {
4727 case XPATH_UNDEFINED:
4728#ifdef DEBUG_EXPR
4729 xmlGenericError(xmlGenericErrorContext,
4730 "Equal: undefined\n");
4731#endif
4732 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004733 case XPATH_BOOLEAN:
4734 switch (arg2->type) {
4735 case XPATH_UNDEFINED:
4736#ifdef DEBUG_EXPR
4737 xmlGenericError(xmlGenericErrorContext,
4738 "Equal: undefined\n");
4739#endif
4740 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004741 case XPATH_BOOLEAN:
4742#ifdef DEBUG_EXPR
4743 xmlGenericError(xmlGenericErrorContext,
4744 "Equal: %d boolean %d \n",
4745 arg1->boolval, arg2->boolval);
4746#endif
4747 ret = (arg1->boolval == arg2->boolval);
4748 break;
4749 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004750 ret = (arg1->boolval ==
4751 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004752 break;
4753 case XPATH_STRING:
4754 if ((arg2->stringval == NULL) ||
4755 (arg2->stringval[0] == 0)) ret = 0;
4756 else
4757 ret = 1;
4758 ret = (arg1->boolval == ret);
4759 break;
4760 case XPATH_USERS:
4761 case XPATH_POINT:
4762 case XPATH_RANGE:
4763 case XPATH_LOCATIONSET:
4764 TODO
4765 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004766 case XPATH_NODESET:
4767 case XPATH_XSLT_TREE:
4768 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004769 }
4770 break;
4771 case XPATH_NUMBER:
4772 switch (arg2->type) {
4773 case XPATH_UNDEFINED:
4774#ifdef DEBUG_EXPR
4775 xmlGenericError(xmlGenericErrorContext,
4776 "Equal: undefined\n");
4777#endif
4778 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004779 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004780 ret = (arg2->boolval==
4781 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004782 break;
4783 case XPATH_STRING:
4784 valuePush(ctxt, arg2);
4785 xmlXPathNumberFunction(ctxt, 1);
4786 arg2 = valuePop(ctxt);
4787 /* no break on purpose */
4788 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004789 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004790 if (xmlXPathIsNaN(arg1->floatval) ||
4791 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004792 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004793 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4794 if (xmlXPathIsInf(arg2->floatval) == 1)
4795 ret = 1;
4796 else
4797 ret = 0;
4798 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4799 if (xmlXPathIsInf(arg2->floatval) == -1)
4800 ret = 1;
4801 else
4802 ret = 0;
4803 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4804 if (xmlXPathIsInf(arg1->floatval) == 1)
4805 ret = 1;
4806 else
4807 ret = 0;
4808 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4809 if (xmlXPathIsInf(arg1->floatval) == -1)
4810 ret = 1;
4811 else
4812 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004813 } else {
4814 ret = (arg1->floatval == arg2->floatval);
4815 }
Owen Taylor3473f882001-02-23 17:55:21 +00004816 break;
4817 case XPATH_USERS:
4818 case XPATH_POINT:
4819 case XPATH_RANGE:
4820 case XPATH_LOCATIONSET:
4821 TODO
4822 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004823 case XPATH_NODESET:
4824 case XPATH_XSLT_TREE:
4825 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004826 }
4827 break;
4828 case XPATH_STRING:
4829 switch (arg2->type) {
4830 case XPATH_UNDEFINED:
4831#ifdef DEBUG_EXPR
4832 xmlGenericError(xmlGenericErrorContext,
4833 "Equal: undefined\n");
4834#endif
4835 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004836 case XPATH_BOOLEAN:
4837 if ((arg1->stringval == NULL) ||
4838 (arg1->stringval[0] == 0)) ret = 0;
4839 else
4840 ret = 1;
4841 ret = (arg2->boolval == ret);
4842 break;
4843 case XPATH_STRING:
4844 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4845 break;
4846 case XPATH_NUMBER:
4847 valuePush(ctxt, arg1);
4848 xmlXPathNumberFunction(ctxt, 1);
4849 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004850 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004851 if (xmlXPathIsNaN(arg1->floatval) ||
4852 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004853 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004854 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4855 if (xmlXPathIsInf(arg2->floatval) == 1)
4856 ret = 1;
4857 else
4858 ret = 0;
4859 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4860 if (xmlXPathIsInf(arg2->floatval) == -1)
4861 ret = 1;
4862 else
4863 ret = 0;
4864 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4865 if (xmlXPathIsInf(arg1->floatval) == 1)
4866 ret = 1;
4867 else
4868 ret = 0;
4869 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4870 if (xmlXPathIsInf(arg1->floatval) == -1)
4871 ret = 1;
4872 else
4873 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004874 } else {
4875 ret = (arg1->floatval == arg2->floatval);
4876 }
Owen Taylor3473f882001-02-23 17:55:21 +00004877 break;
4878 case XPATH_USERS:
4879 case XPATH_POINT:
4880 case XPATH_RANGE:
4881 case XPATH_LOCATIONSET:
4882 TODO
4883 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004884 case XPATH_NODESET:
4885 case XPATH_XSLT_TREE:
4886 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004887 }
4888 break;
4889 case XPATH_USERS:
4890 case XPATH_POINT:
4891 case XPATH_RANGE:
4892 case XPATH_LOCATIONSET:
4893 TODO
4894 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004895 case XPATH_NODESET:
4896 case XPATH_XSLT_TREE:
4897 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004898 }
4899 xmlXPathFreeObject(arg1);
4900 xmlXPathFreeObject(arg2);
4901 return(ret);
4902}
4903
William M. Brack0c022ad2002-07-12 00:56:01 +00004904/**
4905 * xmlXPathEqualValues:
4906 * @ctxt: the XPath Parser context
4907 *
4908 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4909 *
4910 * Returns 0 or 1 depending on the results of the test.
4911 */
4912int
4913xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4914 xmlXPathObjectPtr arg1, arg2, argtmp;
4915 int ret = 0;
4916
Daniel Veillard6128c012004-11-08 17:16:15 +00004917 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004918 arg2 = valuePop(ctxt);
4919 arg1 = valuePop(ctxt);
4920 if ((arg1 == NULL) || (arg2 == NULL)) {
4921 if (arg1 != NULL)
4922 xmlXPathFreeObject(arg1);
4923 else
4924 xmlXPathFreeObject(arg2);
4925 XP_ERROR0(XPATH_INVALID_OPERAND);
4926 }
4927
4928 if (arg1 == arg2) {
4929#ifdef DEBUG_EXPR
4930 xmlGenericError(xmlGenericErrorContext,
4931 "Equal: by pointer\n");
4932#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00004933 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004934 return(1);
4935 }
4936
4937 /*
4938 *If either argument is a nodeset, it's a 'special case'
4939 */
4940 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4941 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4942 /*
4943 *Hack it to assure arg1 is the nodeset
4944 */
4945 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4946 argtmp = arg2;
4947 arg2 = arg1;
4948 arg1 = argtmp;
4949 }
4950 switch (arg2->type) {
4951 case XPATH_UNDEFINED:
4952#ifdef DEBUG_EXPR
4953 xmlGenericError(xmlGenericErrorContext,
4954 "Equal: undefined\n");
4955#endif
4956 break;
4957 case XPATH_NODESET:
4958 case XPATH_XSLT_TREE:
4959 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4960 break;
4961 case XPATH_BOOLEAN:
4962 if ((arg1->nodesetval == NULL) ||
4963 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4964 else
4965 ret = 1;
4966 ret = (ret == arg2->boolval);
4967 break;
4968 case XPATH_NUMBER:
4969 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4970 break;
4971 case XPATH_STRING:
4972 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4973 break;
4974 case XPATH_USERS:
4975 case XPATH_POINT:
4976 case XPATH_RANGE:
4977 case XPATH_LOCATIONSET:
4978 TODO
4979 break;
4980 }
4981 xmlXPathFreeObject(arg1);
4982 xmlXPathFreeObject(arg2);
4983 return(ret);
4984 }
4985
4986 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4987}
4988
4989/**
4990 * xmlXPathNotEqualValues:
4991 * @ctxt: the XPath Parser context
4992 *
4993 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4994 *
4995 * Returns 0 or 1 depending on the results of the test.
4996 */
4997int
4998xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4999 xmlXPathObjectPtr arg1, arg2, argtmp;
5000 int ret = 0;
5001
Daniel Veillard6128c012004-11-08 17:16:15 +00005002 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005003 arg2 = valuePop(ctxt);
5004 arg1 = valuePop(ctxt);
5005 if ((arg1 == NULL) || (arg2 == NULL)) {
5006 if (arg1 != NULL)
5007 xmlXPathFreeObject(arg1);
5008 else
5009 xmlXPathFreeObject(arg2);
5010 XP_ERROR0(XPATH_INVALID_OPERAND);
5011 }
5012
5013 if (arg1 == arg2) {
5014#ifdef DEBUG_EXPR
5015 xmlGenericError(xmlGenericErrorContext,
5016 "NotEqual: by pointer\n");
5017#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005018 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005019 return(0);
5020 }
5021
5022 /*
5023 *If either argument is a nodeset, it's a 'special case'
5024 */
5025 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5026 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5027 /*
5028 *Hack it to assure arg1 is the nodeset
5029 */
5030 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5031 argtmp = arg2;
5032 arg2 = arg1;
5033 arg1 = argtmp;
5034 }
5035 switch (arg2->type) {
5036 case XPATH_UNDEFINED:
5037#ifdef DEBUG_EXPR
5038 xmlGenericError(xmlGenericErrorContext,
5039 "NotEqual: undefined\n");
5040#endif
5041 break;
5042 case XPATH_NODESET:
5043 case XPATH_XSLT_TREE:
5044 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5045 break;
5046 case XPATH_BOOLEAN:
5047 if ((arg1->nodesetval == NULL) ||
5048 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5049 else
5050 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005051 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005052 break;
5053 case XPATH_NUMBER:
5054 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5055 break;
5056 case XPATH_STRING:
5057 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5058 break;
5059 case XPATH_USERS:
5060 case XPATH_POINT:
5061 case XPATH_RANGE:
5062 case XPATH_LOCATIONSET:
5063 TODO
5064 break;
5065 }
5066 xmlXPathFreeObject(arg1);
5067 xmlXPathFreeObject(arg2);
5068 return(ret);
5069 }
5070
5071 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5072}
Owen Taylor3473f882001-02-23 17:55:21 +00005073
5074/**
5075 * xmlXPathCompareValues:
5076 * @ctxt: the XPath Parser context
5077 * @inf: less than (1) or greater than (0)
5078 * @strict: is the comparison strict
5079 *
5080 * Implement the compare operation on XPath objects:
5081 * @arg1 < @arg2 (1, 1, ...
5082 * @arg1 <= @arg2 (1, 0, ...
5083 * @arg1 > @arg2 (0, 1, ...
5084 * @arg1 >= @arg2 (0, 0, ...
5085 *
5086 * When neither object to be compared is a node-set and the operator is
5087 * <=, <, >=, >, then the objects are compared by converted both objects
5088 * to numbers and comparing the numbers according to IEEE 754. The <
5089 * comparison will be true if and only if the first number is less than the
5090 * second number. The <= comparison will be true if and only if the first
5091 * number is less than or equal to the second number. The > comparison
5092 * will be true if and only if the first number is greater than the second
5093 * number. The >= comparison will be true if and only if the first number
5094 * is greater than or equal to the second number.
5095 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005096 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005097 */
5098int
5099xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005100 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005101 xmlXPathObjectPtr arg1, arg2;
5102
Daniel Veillard6128c012004-11-08 17:16:15 +00005103 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005104 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005105 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005106 if ((arg1 == NULL) || (arg2 == NULL)) {
5107 if (arg1 != NULL)
5108 xmlXPathFreeObject(arg1);
5109 else
5110 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005111 XP_ERROR0(XPATH_INVALID_OPERAND);
5112 }
5113
William M. Brack0c022ad2002-07-12 00:56:01 +00005114 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5115 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00005116 /*
5117 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5118 * are not freed from within this routine; they will be freed from the
5119 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5120 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005121 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5122 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005123 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005124 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005125 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005126 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5127 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005128 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005129 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5130 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005131 }
5132 }
5133 return(ret);
5134 }
5135
5136 if (arg1->type != XPATH_NUMBER) {
5137 valuePush(ctxt, arg1);
5138 xmlXPathNumberFunction(ctxt, 1);
5139 arg1 = valuePop(ctxt);
5140 }
5141 if (arg1->type != XPATH_NUMBER) {
5142 xmlXPathFreeObject(arg1);
5143 xmlXPathFreeObject(arg2);
5144 XP_ERROR0(XPATH_INVALID_OPERAND);
5145 }
5146 if (arg2->type != XPATH_NUMBER) {
5147 valuePush(ctxt, arg2);
5148 xmlXPathNumberFunction(ctxt, 1);
5149 arg2 = valuePop(ctxt);
5150 }
5151 if (arg2->type != XPATH_NUMBER) {
5152 xmlXPathFreeObject(arg1);
5153 xmlXPathFreeObject(arg2);
5154 XP_ERROR0(XPATH_INVALID_OPERAND);
5155 }
5156 /*
5157 * Add tests for infinity and nan
5158 * => feedback on 3.4 for Inf and NaN
5159 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005160 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005161 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005162 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005163 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005164 arg1i=xmlXPathIsInf(arg1->floatval);
5165 arg2i=xmlXPathIsInf(arg2->floatval);
5166 if (inf && strict) {
5167 if ((arg1i == -1 && arg2i != -1) ||
5168 (arg2i == 1 && arg1i != 1)) {
5169 ret = 1;
5170 } else if (arg1i == 0 && arg2i == 0) {
5171 ret = (arg1->floatval < arg2->floatval);
5172 } else {
5173 ret = 0;
5174 }
5175 }
5176 else if (inf && !strict) {
5177 if (arg1i == -1 || arg2i == 1) {
5178 ret = 1;
5179 } else if (arg1i == 0 && arg2i == 0) {
5180 ret = (arg1->floatval <= arg2->floatval);
5181 } else {
5182 ret = 0;
5183 }
5184 }
5185 else if (!inf && strict) {
5186 if ((arg1i == 1 && arg2i != 1) ||
5187 (arg2i == -1 && arg1i != -1)) {
5188 ret = 1;
5189 } else if (arg1i == 0 && arg2i == 0) {
5190 ret = (arg1->floatval > arg2->floatval);
5191 } else {
5192 ret = 0;
5193 }
5194 }
5195 else if (!inf && !strict) {
5196 if (arg1i == 1 || arg2i == -1) {
5197 ret = 1;
5198 } else if (arg1i == 0 && arg2i == 0) {
5199 ret = (arg1->floatval >= arg2->floatval);
5200 } else {
5201 ret = 0;
5202 }
5203 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005204 }
Owen Taylor3473f882001-02-23 17:55:21 +00005205 xmlXPathFreeObject(arg1);
5206 xmlXPathFreeObject(arg2);
5207 return(ret);
5208}
5209
5210/**
5211 * xmlXPathValueFlipSign:
5212 * @ctxt: the XPath Parser context
5213 *
5214 * Implement the unary - operation on an XPath object
5215 * The numeric operators convert their operands to numbers as if
5216 * by calling the number function.
5217 */
5218void
5219xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005220 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005221 CAST_TO_NUMBER;
5222 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005223 if (xmlXPathIsNaN(ctxt->value->floatval))
5224 ctxt->value->floatval=xmlXPathNAN;
5225 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5226 ctxt->value->floatval=xmlXPathNINF;
5227 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5228 ctxt->value->floatval=xmlXPathPINF;
5229 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005230 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5231 ctxt->value->floatval = xmlXPathNZERO;
5232 else
5233 ctxt->value->floatval = 0;
5234 }
5235 else
5236 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005237}
5238
5239/**
5240 * xmlXPathAddValues:
5241 * @ctxt: the XPath Parser context
5242 *
5243 * Implement the add operation on XPath objects:
5244 * The numeric operators convert their operands to numbers as if
5245 * by calling the number function.
5246 */
5247void
5248xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5249 xmlXPathObjectPtr arg;
5250 double val;
5251
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005252 arg = valuePop(ctxt);
5253 if (arg == NULL)
5254 XP_ERROR(XPATH_INVALID_OPERAND);
5255 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005256 xmlXPathFreeObject(arg);
5257
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005258 CAST_TO_NUMBER;
5259 CHECK_TYPE(XPATH_NUMBER);
5260 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005261}
5262
5263/**
5264 * xmlXPathSubValues:
5265 * @ctxt: the XPath Parser context
5266 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005267 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005268 * The numeric operators convert their operands to numbers as if
5269 * by calling the number function.
5270 */
5271void
5272xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5273 xmlXPathObjectPtr arg;
5274 double val;
5275
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005276 arg = valuePop(ctxt);
5277 if (arg == NULL)
5278 XP_ERROR(XPATH_INVALID_OPERAND);
5279 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005280 xmlXPathFreeObject(arg);
5281
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005282 CAST_TO_NUMBER;
5283 CHECK_TYPE(XPATH_NUMBER);
5284 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005285}
5286
5287/**
5288 * xmlXPathMultValues:
5289 * @ctxt: the XPath Parser context
5290 *
5291 * Implement the multiply operation on XPath objects:
5292 * The numeric operators convert their operands to numbers as if
5293 * by calling the number function.
5294 */
5295void
5296xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5297 xmlXPathObjectPtr arg;
5298 double val;
5299
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005300 arg = valuePop(ctxt);
5301 if (arg == NULL)
5302 XP_ERROR(XPATH_INVALID_OPERAND);
5303 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005304 xmlXPathFreeObject(arg);
5305
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005306 CAST_TO_NUMBER;
5307 CHECK_TYPE(XPATH_NUMBER);
5308 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005309}
5310
5311/**
5312 * xmlXPathDivValues:
5313 * @ctxt: the XPath Parser context
5314 *
5315 * Implement the div operation on XPath objects @arg1 / @arg2:
5316 * The numeric operators convert their operands to numbers as if
5317 * by calling the number function.
5318 */
5319void
5320xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5321 xmlXPathObjectPtr arg;
5322 double val;
5323
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005324 arg = valuePop(ctxt);
5325 if (arg == NULL)
5326 XP_ERROR(XPATH_INVALID_OPERAND);
5327 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005328 xmlXPathFreeObject(arg);
5329
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005330 CAST_TO_NUMBER;
5331 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005332 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5333 ctxt->value->floatval = xmlXPathNAN;
5334 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005335 if (ctxt->value->floatval == 0)
5336 ctxt->value->floatval = xmlXPathNAN;
5337 else if (ctxt->value->floatval > 0)
5338 ctxt->value->floatval = xmlXPathNINF;
5339 else if (ctxt->value->floatval < 0)
5340 ctxt->value->floatval = xmlXPathPINF;
5341 }
5342 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005343 if (ctxt->value->floatval == 0)
5344 ctxt->value->floatval = xmlXPathNAN;
5345 else if (ctxt->value->floatval > 0)
5346 ctxt->value->floatval = xmlXPathPINF;
5347 else if (ctxt->value->floatval < 0)
5348 ctxt->value->floatval = xmlXPathNINF;
5349 } else
5350 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005351}
5352
5353/**
5354 * xmlXPathModValues:
5355 * @ctxt: the XPath Parser context
5356 *
5357 * Implement the mod operation on XPath objects: @arg1 / @arg2
5358 * The numeric operators convert their operands to numbers as if
5359 * by calling the number function.
5360 */
5361void
5362xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5363 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005364 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005365
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005366 arg = valuePop(ctxt);
5367 if (arg == NULL)
5368 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005369 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005370 xmlXPathFreeObject(arg);
5371
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005372 CAST_TO_NUMBER;
5373 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005374 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005375 if (arg2 == 0)
5376 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005377 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005378 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005379 }
Owen Taylor3473f882001-02-23 17:55:21 +00005380}
5381
5382/************************************************************************
5383 * *
5384 * The traversal functions *
5385 * *
5386 ************************************************************************/
5387
Owen Taylor3473f882001-02-23 17:55:21 +00005388/*
5389 * A traversal function enumerates nodes along an axis.
5390 * Initially it must be called with NULL, and it indicates
5391 * termination on the axis by returning NULL.
5392 */
5393typedef xmlNodePtr (*xmlXPathTraversalFunction)
5394 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5395
5396/**
5397 * xmlXPathNextSelf:
5398 * @ctxt: the XPath Parser context
5399 * @cur: the current node in the traversal
5400 *
5401 * Traversal function for the "self" direction
5402 * The self axis contains just the context node itself
5403 *
5404 * Returns the next element following that axis
5405 */
5406xmlNodePtr
5407xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005408 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005409 if (cur == NULL)
5410 return(ctxt->context->node);
5411 return(NULL);
5412}
5413
5414/**
5415 * xmlXPathNextChild:
5416 * @ctxt: the XPath Parser context
5417 * @cur: the current node in the traversal
5418 *
5419 * Traversal function for the "child" direction
5420 * The child axis contains the children of the context node in document order.
5421 *
5422 * Returns the next element following that axis
5423 */
5424xmlNodePtr
5425xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005426 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005427 if (cur == NULL) {
5428 if (ctxt->context->node == NULL) return(NULL);
5429 switch (ctxt->context->node->type) {
5430 case XML_ELEMENT_NODE:
5431 case XML_TEXT_NODE:
5432 case XML_CDATA_SECTION_NODE:
5433 case XML_ENTITY_REF_NODE:
5434 case XML_ENTITY_NODE:
5435 case XML_PI_NODE:
5436 case XML_COMMENT_NODE:
5437 case XML_NOTATION_NODE:
5438 case XML_DTD_NODE:
5439 return(ctxt->context->node->children);
5440 case XML_DOCUMENT_NODE:
5441 case XML_DOCUMENT_TYPE_NODE:
5442 case XML_DOCUMENT_FRAG_NODE:
5443 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005444#ifdef LIBXML_DOCB_ENABLED
5445 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005446#endif
5447 return(((xmlDocPtr) ctxt->context->node)->children);
5448 case XML_ELEMENT_DECL:
5449 case XML_ATTRIBUTE_DECL:
5450 case XML_ENTITY_DECL:
5451 case XML_ATTRIBUTE_NODE:
5452 case XML_NAMESPACE_DECL:
5453 case XML_XINCLUDE_START:
5454 case XML_XINCLUDE_END:
5455 return(NULL);
5456 }
5457 return(NULL);
5458 }
5459 if ((cur->type == XML_DOCUMENT_NODE) ||
5460 (cur->type == XML_HTML_DOCUMENT_NODE))
5461 return(NULL);
5462 return(cur->next);
5463}
5464
5465/**
5466 * xmlXPathNextDescendant:
5467 * @ctxt: the XPath Parser context
5468 * @cur: the current node in the traversal
5469 *
5470 * Traversal function for the "descendant" direction
5471 * the descendant axis contains the descendants of the context node in document
5472 * order; a descendant is a child or a child of a child and so on.
5473 *
5474 * Returns the next element following that axis
5475 */
5476xmlNodePtr
5477xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005478 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005479 if (cur == NULL) {
5480 if (ctxt->context->node == NULL)
5481 return(NULL);
5482 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5483 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5484 return(NULL);
5485
5486 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5487 return(ctxt->context->doc->children);
5488 return(ctxt->context->node->children);
5489 }
5490
Daniel Veillard567e1b42001-08-01 15:53:47 +00005491 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005492 /*
5493 * Do not descend on entities declarations
5494 */
5495 if (cur->children->type != XML_ENTITY_DECL) {
5496 cur = cur->children;
5497 /*
5498 * Skip DTDs
5499 */
5500 if (cur->type != XML_DTD_NODE)
5501 return(cur);
5502 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005503 }
5504
5505 if (cur == ctxt->context->node) return(NULL);
5506
Daniel Veillard68e9e742002-11-16 15:35:11 +00005507 while (cur->next != NULL) {
5508 cur = cur->next;
5509 if ((cur->type != XML_ENTITY_DECL) &&
5510 (cur->type != XML_DTD_NODE))
5511 return(cur);
5512 }
Owen Taylor3473f882001-02-23 17:55:21 +00005513
5514 do {
5515 cur = cur->parent;
5516 if (cur == NULL) return(NULL);
5517 if (cur == ctxt->context->node) return(NULL);
5518 if (cur->next != NULL) {
5519 cur = cur->next;
5520 return(cur);
5521 }
5522 } while (cur != NULL);
5523 return(cur);
5524}
5525
5526/**
5527 * xmlXPathNextDescendantOrSelf:
5528 * @ctxt: the XPath Parser context
5529 * @cur: the current node in the traversal
5530 *
5531 * Traversal function for the "descendant-or-self" direction
5532 * the descendant-or-self axis contains the context node and the descendants
5533 * of the context node in document order; thus the context node is the first
5534 * node on the axis, and the first child of the context node is the second node
5535 * on the axis
5536 *
5537 * Returns the next element following that axis
5538 */
5539xmlNodePtr
5540xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005541 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005542 if (cur == NULL) {
5543 if (ctxt->context->node == NULL)
5544 return(NULL);
5545 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5546 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5547 return(NULL);
5548 return(ctxt->context->node);
5549 }
5550
5551 return(xmlXPathNextDescendant(ctxt, cur));
5552}
5553
5554/**
5555 * xmlXPathNextParent:
5556 * @ctxt: the XPath Parser context
5557 * @cur: the current node in the traversal
5558 *
5559 * Traversal function for the "parent" direction
5560 * The parent axis contains the parent of the context node, if there is one.
5561 *
5562 * Returns the next element following that axis
5563 */
5564xmlNodePtr
5565xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005566 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005567 /*
5568 * the parent of an attribute or namespace node is the element
5569 * to which the attribute or namespace node is attached
5570 * Namespace handling !!!
5571 */
5572 if (cur == NULL) {
5573 if (ctxt->context->node == NULL) return(NULL);
5574 switch (ctxt->context->node->type) {
5575 case XML_ELEMENT_NODE:
5576 case XML_TEXT_NODE:
5577 case XML_CDATA_SECTION_NODE:
5578 case XML_ENTITY_REF_NODE:
5579 case XML_ENTITY_NODE:
5580 case XML_PI_NODE:
5581 case XML_COMMENT_NODE:
5582 case XML_NOTATION_NODE:
5583 case XML_DTD_NODE:
5584 case XML_ELEMENT_DECL:
5585 case XML_ATTRIBUTE_DECL:
5586 case XML_XINCLUDE_START:
5587 case XML_XINCLUDE_END:
5588 case XML_ENTITY_DECL:
5589 if (ctxt->context->node->parent == NULL)
5590 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005591 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005592 ((ctxt->context->node->parent->name[0] == ' ') ||
5593 (xmlStrEqual(ctxt->context->node->parent->name,
5594 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005595 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005596 return(ctxt->context->node->parent);
5597 case XML_ATTRIBUTE_NODE: {
5598 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5599
5600 return(att->parent);
5601 }
5602 case XML_DOCUMENT_NODE:
5603 case XML_DOCUMENT_TYPE_NODE:
5604 case XML_DOCUMENT_FRAG_NODE:
5605 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005606#ifdef LIBXML_DOCB_ENABLED
5607 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005608#endif
5609 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005610 case XML_NAMESPACE_DECL: {
5611 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5612
5613 if ((ns->next != NULL) &&
5614 (ns->next->type != XML_NAMESPACE_DECL))
5615 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005616 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005617 }
Owen Taylor3473f882001-02-23 17:55:21 +00005618 }
5619 }
5620 return(NULL);
5621}
5622
5623/**
5624 * xmlXPathNextAncestor:
5625 * @ctxt: the XPath Parser context
5626 * @cur: the current node in the traversal
5627 *
5628 * Traversal function for the "ancestor" direction
5629 * the ancestor axis contains the ancestors of the context node; the ancestors
5630 * of the context node consist of the parent of context node and the parent's
5631 * parent and so on; the nodes are ordered in reverse document order; thus the
5632 * parent is the first node on the axis, and the parent's parent is the second
5633 * node on the axis
5634 *
5635 * Returns the next element following that axis
5636 */
5637xmlNodePtr
5638xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005639 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005640 /*
5641 * the parent of an attribute or namespace node is the element
5642 * to which the attribute or namespace node is attached
5643 * !!!!!!!!!!!!!
5644 */
5645 if (cur == NULL) {
5646 if (ctxt->context->node == NULL) return(NULL);
5647 switch (ctxt->context->node->type) {
5648 case XML_ELEMENT_NODE:
5649 case XML_TEXT_NODE:
5650 case XML_CDATA_SECTION_NODE:
5651 case XML_ENTITY_REF_NODE:
5652 case XML_ENTITY_NODE:
5653 case XML_PI_NODE:
5654 case XML_COMMENT_NODE:
5655 case XML_DTD_NODE:
5656 case XML_ELEMENT_DECL:
5657 case XML_ATTRIBUTE_DECL:
5658 case XML_ENTITY_DECL:
5659 case XML_NOTATION_NODE:
5660 case XML_XINCLUDE_START:
5661 case XML_XINCLUDE_END:
5662 if (ctxt->context->node->parent == NULL)
5663 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005664 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005665 ((ctxt->context->node->parent->name[0] == ' ') ||
5666 (xmlStrEqual(ctxt->context->node->parent->name,
5667 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005668 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005669 return(ctxt->context->node->parent);
5670 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005671 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005672
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005673 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005674 }
5675 case XML_DOCUMENT_NODE:
5676 case XML_DOCUMENT_TYPE_NODE:
5677 case XML_DOCUMENT_FRAG_NODE:
5678 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005679#ifdef LIBXML_DOCB_ENABLED
5680 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005681#endif
5682 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005683 case XML_NAMESPACE_DECL: {
5684 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5685
5686 if ((ns->next != NULL) &&
5687 (ns->next->type != XML_NAMESPACE_DECL))
5688 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005689 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005690 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005691 }
Owen Taylor3473f882001-02-23 17:55:21 +00005692 }
5693 return(NULL);
5694 }
5695 if (cur == ctxt->context->doc->children)
5696 return((xmlNodePtr) ctxt->context->doc);
5697 if (cur == (xmlNodePtr) ctxt->context->doc)
5698 return(NULL);
5699 switch (cur->type) {
5700 case XML_ELEMENT_NODE:
5701 case XML_TEXT_NODE:
5702 case XML_CDATA_SECTION_NODE:
5703 case XML_ENTITY_REF_NODE:
5704 case XML_ENTITY_NODE:
5705 case XML_PI_NODE:
5706 case XML_COMMENT_NODE:
5707 case XML_NOTATION_NODE:
5708 case XML_DTD_NODE:
5709 case XML_ELEMENT_DECL:
5710 case XML_ATTRIBUTE_DECL:
5711 case XML_ENTITY_DECL:
5712 case XML_XINCLUDE_START:
5713 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005714 if (cur->parent == NULL)
5715 return(NULL);
5716 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005717 ((cur->parent->name[0] == ' ') ||
5718 (xmlStrEqual(cur->parent->name,
5719 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005720 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005721 return(cur->parent);
5722 case XML_ATTRIBUTE_NODE: {
5723 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5724
5725 return(att->parent);
5726 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005727 case XML_NAMESPACE_DECL: {
5728 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5729
5730 if ((ns->next != NULL) &&
5731 (ns->next->type != XML_NAMESPACE_DECL))
5732 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005733 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005734 return(NULL);
5735 }
Owen Taylor3473f882001-02-23 17:55:21 +00005736 case XML_DOCUMENT_NODE:
5737 case XML_DOCUMENT_TYPE_NODE:
5738 case XML_DOCUMENT_FRAG_NODE:
5739 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005740#ifdef LIBXML_DOCB_ENABLED
5741 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005742#endif
5743 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005744 }
5745 return(NULL);
5746}
5747
5748/**
5749 * xmlXPathNextAncestorOrSelf:
5750 * @ctxt: the XPath Parser context
5751 * @cur: the current node in the traversal
5752 *
5753 * Traversal function for the "ancestor-or-self" direction
5754 * he ancestor-or-self axis contains the context node and ancestors of
5755 * the context node in reverse document order; thus the context node is
5756 * the first node on the axis, and the context node's parent the second;
5757 * parent here is defined the same as with the parent axis.
5758 *
5759 * Returns the next element following that axis
5760 */
5761xmlNodePtr
5762xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005763 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005764 if (cur == NULL)
5765 return(ctxt->context->node);
5766 return(xmlXPathNextAncestor(ctxt, cur));
5767}
5768
5769/**
5770 * xmlXPathNextFollowingSibling:
5771 * @ctxt: the XPath Parser context
5772 * @cur: the current node in the traversal
5773 *
5774 * Traversal function for the "following-sibling" direction
5775 * The following-sibling axis contains the following siblings of the context
5776 * node in document order.
5777 *
5778 * Returns the next element following that axis
5779 */
5780xmlNodePtr
5781xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005782 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005783 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5784 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5785 return(NULL);
5786 if (cur == (xmlNodePtr) ctxt->context->doc)
5787 return(NULL);
5788 if (cur == NULL)
5789 return(ctxt->context->node->next);
5790 return(cur->next);
5791}
5792
5793/**
5794 * xmlXPathNextPrecedingSibling:
5795 * @ctxt: the XPath Parser context
5796 * @cur: the current node in the traversal
5797 *
5798 * Traversal function for the "preceding-sibling" direction
5799 * The preceding-sibling axis contains the preceding siblings of the context
5800 * node in reverse document order; the first preceding sibling is first on the
5801 * axis; the sibling preceding that node is the second on the axis and so on.
5802 *
5803 * Returns the next element following that axis
5804 */
5805xmlNodePtr
5806xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005807 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005808 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5809 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5810 return(NULL);
5811 if (cur == (xmlNodePtr) ctxt->context->doc)
5812 return(NULL);
5813 if (cur == NULL)
5814 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005815 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5816 cur = cur->prev;
5817 if (cur == NULL)
5818 return(ctxt->context->node->prev);
5819 }
Owen Taylor3473f882001-02-23 17:55:21 +00005820 return(cur->prev);
5821}
5822
5823/**
5824 * xmlXPathNextFollowing:
5825 * @ctxt: the XPath Parser context
5826 * @cur: the current node in the traversal
5827 *
5828 * Traversal function for the "following" direction
5829 * The following axis contains all nodes in the same document as the context
5830 * node that are after the context node in document order, excluding any
5831 * descendants and excluding attribute nodes and namespace nodes; the nodes
5832 * are ordered in document order
5833 *
5834 * Returns the next element following that axis
5835 */
5836xmlNodePtr
5837xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005838 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005839 if (cur != NULL && cur->children != NULL)
5840 return cur->children ;
5841 if (cur == NULL) cur = ctxt->context->node;
5842 if (cur == NULL) return(NULL) ; /* ERROR */
5843 if (cur->next != NULL) return(cur->next) ;
5844 do {
5845 cur = cur->parent;
5846 if (cur == NULL) return(NULL);
5847 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5848 if (cur->next != NULL) return(cur->next);
5849 } while (cur != NULL);
5850 return(cur);
5851}
5852
5853/*
5854 * xmlXPathIsAncestor:
5855 * @ancestor: the ancestor node
5856 * @node: the current node
5857 *
5858 * Check that @ancestor is a @node's ancestor
5859 *
5860 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5861 */
5862static int
5863xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5864 if ((ancestor == NULL) || (node == NULL)) return(0);
5865 /* nodes need to be in the same document */
5866 if (ancestor->doc != node->doc) return(0);
5867 /* avoid searching if ancestor or node is the root node */
5868 if (ancestor == (xmlNodePtr) node->doc) return(1);
5869 if (node == (xmlNodePtr) ancestor->doc) return(0);
5870 while (node->parent != NULL) {
5871 if (node->parent == ancestor)
5872 return(1);
5873 node = node->parent;
5874 }
5875 return(0);
5876}
5877
5878/**
5879 * xmlXPathNextPreceding:
5880 * @ctxt: the XPath Parser context
5881 * @cur: the current node in the traversal
5882 *
5883 * Traversal function for the "preceding" direction
5884 * the preceding axis contains all nodes in the same document as the context
5885 * node that are before the context node in document order, excluding any
5886 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5887 * ordered in reverse document order
5888 *
5889 * Returns the next element following that axis
5890 */
5891xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005892xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5893{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005894 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005895 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005896 cur = ctxt->context->node;
5897 if (cur == NULL)
5898 return (NULL);
5899 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5900 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005901 do {
5902 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005903 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5904 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005905 }
5906
5907 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005908 if (cur == NULL)
5909 return (NULL);
5910 if (cur == ctxt->context->doc->children)
5911 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005912 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005913 return (cur);
5914}
5915
5916/**
5917 * xmlXPathNextPrecedingInternal:
5918 * @ctxt: the XPath Parser context
5919 * @cur: the current node in the traversal
5920 *
5921 * Traversal function for the "preceding" direction
5922 * the preceding axis contains all nodes in the same document as the context
5923 * node that are before the context node in document order, excluding any
5924 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5925 * ordered in reverse document order
5926 * This is a faster implementation but internal only since it requires a
5927 * state kept in the parser context: ctxt->ancestor.
5928 *
5929 * Returns the next element following that axis
5930 */
5931static xmlNodePtr
5932xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5933 xmlNodePtr cur)
5934{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005935 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005936 if (cur == NULL) {
5937 cur = ctxt->context->node;
5938 if (cur == NULL)
5939 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005940 if (cur->type == XML_NAMESPACE_DECL)
5941 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005942 ctxt->ancestor = cur->parent;
5943 }
5944 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5945 cur = cur->prev;
5946 while (cur->prev == NULL) {
5947 cur = cur->parent;
5948 if (cur == NULL)
5949 return (NULL);
5950 if (cur == ctxt->context->doc->children)
5951 return (NULL);
5952 if (cur != ctxt->ancestor)
5953 return (cur);
5954 ctxt->ancestor = cur->parent;
5955 }
5956 cur = cur->prev;
5957 while (cur->last != NULL)
5958 cur = cur->last;
5959 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005960}
5961
5962/**
5963 * xmlXPathNextNamespace:
5964 * @ctxt: the XPath Parser context
5965 * @cur: the current attribute in the traversal
5966 *
5967 * Traversal function for the "namespace" direction
5968 * the namespace axis contains the namespace nodes of the context node;
5969 * the order of nodes on this axis is implementation-defined; the axis will
5970 * be empty unless the context node is an element
5971 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005972 * We keep the XML namespace node at the end of the list.
5973 *
Owen Taylor3473f882001-02-23 17:55:21 +00005974 * Returns the next element following that axis
5975 */
5976xmlNodePtr
5977xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005978 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005979 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005980 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005981 if (ctxt->context->tmpNsList != NULL)
5982 xmlFree(ctxt->context->tmpNsList);
5983 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005984 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005985 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005986 if (ctxt->context->tmpNsList != NULL) {
5987 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5988 ctxt->context->tmpNsNr++;
5989 }
5990 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005991 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005992 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005993 if (ctxt->context->tmpNsNr > 0) {
5994 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5995 } else {
5996 if (ctxt->context->tmpNsList != NULL)
5997 xmlFree(ctxt->context->tmpNsList);
5998 ctxt->context->tmpNsList = NULL;
5999 return(NULL);
6000 }
Owen Taylor3473f882001-02-23 17:55:21 +00006001}
6002
6003/**
6004 * xmlXPathNextAttribute:
6005 * @ctxt: the XPath Parser context
6006 * @cur: the current attribute in the traversal
6007 *
6008 * Traversal function for the "attribute" direction
6009 * TODO: support DTD inherited default attributes
6010 *
6011 * Returns the next element following that axis
6012 */
6013xmlNodePtr
6014xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006015 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006016 if (ctxt->context->node == NULL)
6017 return(NULL);
6018 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6019 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006020 if (cur == NULL) {
6021 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6022 return(NULL);
6023 return((xmlNodePtr)ctxt->context->node->properties);
6024 }
6025 return((xmlNodePtr)cur->next);
6026}
6027
6028/************************************************************************
6029 * *
6030 * NodeTest Functions *
6031 * *
6032 ************************************************************************/
6033
Owen Taylor3473f882001-02-23 17:55:21 +00006034#define IS_FUNCTION 200
6035
Owen Taylor3473f882001-02-23 17:55:21 +00006036
6037/************************************************************************
6038 * *
6039 * Implicit tree core function library *
6040 * *
6041 ************************************************************************/
6042
6043/**
6044 * xmlXPathRoot:
6045 * @ctxt: the XPath Parser context
6046 *
6047 * Initialize the context to the root of the document
6048 */
6049void
6050xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006051 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006052 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6053 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6054}
6055
6056/************************************************************************
6057 * *
6058 * The explicit core function library *
6059 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6060 * *
6061 ************************************************************************/
6062
6063
6064/**
6065 * xmlXPathLastFunction:
6066 * @ctxt: the XPath Parser context
6067 * @nargs: the number of arguments
6068 *
6069 * Implement the last() XPath function
6070 * number last()
6071 * The last function returns the number of nodes in the context node list.
6072 */
6073void
6074xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6075 CHECK_ARITY(0);
6076 if (ctxt->context->contextSize >= 0) {
6077 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6078#ifdef DEBUG_EXPR
6079 xmlGenericError(xmlGenericErrorContext,
6080 "last() : %d\n", ctxt->context->contextSize);
6081#endif
6082 } else {
6083 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6084 }
6085}
6086
6087/**
6088 * xmlXPathPositionFunction:
6089 * @ctxt: the XPath Parser context
6090 * @nargs: the number of arguments
6091 *
6092 * Implement the position() XPath function
6093 * number position()
6094 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006095 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006096 * will be equal to last().
6097 */
6098void
6099xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6100 CHECK_ARITY(0);
6101 if (ctxt->context->proximityPosition >= 0) {
6102 valuePush(ctxt,
6103 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6104#ifdef DEBUG_EXPR
6105 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6106 ctxt->context->proximityPosition);
6107#endif
6108 } else {
6109 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6110 }
6111}
6112
6113/**
6114 * xmlXPathCountFunction:
6115 * @ctxt: the XPath Parser context
6116 * @nargs: the number of arguments
6117 *
6118 * Implement the count() XPath function
6119 * number count(node-set)
6120 */
6121void
6122xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6123 xmlXPathObjectPtr cur;
6124
6125 CHECK_ARITY(1);
6126 if ((ctxt->value == NULL) ||
6127 ((ctxt->value->type != XPATH_NODESET) &&
6128 (ctxt->value->type != XPATH_XSLT_TREE)))
6129 XP_ERROR(XPATH_INVALID_TYPE);
6130 cur = valuePop(ctxt);
6131
Daniel Veillard911f49a2001-04-07 15:39:35 +00006132 if ((cur == NULL) || (cur->nodesetval == NULL))
6133 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006134 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006135 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006136 } else {
6137 if ((cur->nodesetval->nodeNr != 1) ||
6138 (cur->nodesetval->nodeTab == NULL)) {
6139 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6140 } else {
6141 xmlNodePtr tmp;
6142 int i = 0;
6143
6144 tmp = cur->nodesetval->nodeTab[0];
6145 if (tmp != NULL) {
6146 tmp = tmp->children;
6147 while (tmp != NULL) {
6148 tmp = tmp->next;
6149 i++;
6150 }
6151 }
6152 valuePush(ctxt, xmlXPathNewFloat((double) i));
6153 }
6154 }
Owen Taylor3473f882001-02-23 17:55:21 +00006155 xmlXPathFreeObject(cur);
6156}
6157
6158/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006159 * xmlXPathGetElementsByIds:
6160 * @doc: the document
6161 * @ids: a whitespace separated list of IDs
6162 *
6163 * Selects elements by their unique ID.
6164 *
6165 * Returns a node-set of selected elements.
6166 */
6167static xmlNodeSetPtr
6168xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6169 xmlNodeSetPtr ret;
6170 const xmlChar *cur = ids;
6171 xmlChar *ID;
6172 xmlAttrPtr attr;
6173 xmlNodePtr elem = NULL;
6174
Daniel Veillard7a985a12003-07-06 17:57:42 +00006175 if (ids == NULL) return(NULL);
6176
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006177 ret = xmlXPathNodeSetCreate(NULL);
6178
William M. Brack76e95df2003-10-18 16:20:14 +00006179 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006180 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006181 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006182 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006183
6184 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006185 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006186 /*
6187 * We used to check the fact that the value passed
6188 * was an NCName, but this generated much troubles for
6189 * me and Aleksey Sanin, people blatantly violated that
6190 * constaint, like Visa3D spec.
6191 * if (xmlValidateNCName(ID, 1) == 0)
6192 */
6193 attr = xmlGetID(doc, ID);
6194 if (attr != NULL) {
6195 if (attr->type == XML_ATTRIBUTE_NODE)
6196 elem = attr->parent;
6197 else if (attr->type == XML_ELEMENT_NODE)
6198 elem = (xmlNodePtr) attr;
6199 else
6200 elem = NULL;
6201 if (elem != NULL)
6202 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006203 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006204 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006205 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006206
William M. Brack76e95df2003-10-18 16:20:14 +00006207 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006208 ids = cur;
6209 }
6210 return(ret);
6211}
6212
6213/**
Owen Taylor3473f882001-02-23 17:55:21 +00006214 * xmlXPathIdFunction:
6215 * @ctxt: the XPath Parser context
6216 * @nargs: the number of arguments
6217 *
6218 * Implement the id() XPath function
6219 * node-set id(object)
6220 * The id function selects elements by their unique ID
6221 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6222 * then the result is the union of the result of applying id to the
6223 * string value of each of the nodes in the argument node-set. When the
6224 * argument to id is of any other type, the argument is converted to a
6225 * string as if by a call to the string function; the string is split
6226 * into a whitespace-separated list of tokens (whitespace is any sequence
6227 * of characters matching the production S); the result is a node-set
6228 * containing the elements in the same document as the context node that
6229 * have a unique ID equal to any of the tokens in the list.
6230 */
6231void
6232xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006233 xmlChar *tokens;
6234 xmlNodeSetPtr ret;
6235 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006236
6237 CHECK_ARITY(1);
6238 obj = valuePop(ctxt);
6239 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006240 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006241 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006242 int i;
6243
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006244 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006245
Daniel Veillard911f49a2001-04-07 15:39:35 +00006246 if (obj->nodesetval != NULL) {
6247 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006248 tokens =
6249 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6250 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6251 ret = xmlXPathNodeSetMerge(ret, ns);
6252 xmlXPathFreeNodeSet(ns);
6253 if (tokens != NULL)
6254 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006255 }
Owen Taylor3473f882001-02-23 17:55:21 +00006256 }
6257
6258 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006259 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006260 return;
6261 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006262 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006263
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006264 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6265 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006266
Owen Taylor3473f882001-02-23 17:55:21 +00006267 xmlXPathFreeObject(obj);
6268 return;
6269}
6270
6271/**
6272 * xmlXPathLocalNameFunction:
6273 * @ctxt: the XPath Parser context
6274 * @nargs: the number of arguments
6275 *
6276 * Implement the local-name() XPath function
6277 * string local-name(node-set?)
6278 * The local-name function returns a string containing the local part
6279 * of the name of the node in the argument node-set that is first in
6280 * document order. If the node-set is empty or the first node has no
6281 * name, an empty string is returned. If the argument is omitted it
6282 * defaults to the context node.
6283 */
6284void
6285xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6286 xmlXPathObjectPtr cur;
6287
Daniel Veillarda82b1822004-11-08 16:24:57 +00006288 if (ctxt == NULL) return;
6289
Owen Taylor3473f882001-02-23 17:55:21 +00006290 if (nargs == 0) {
6291 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6292 nargs = 1;
6293 }
6294
6295 CHECK_ARITY(1);
6296 if ((ctxt->value == NULL) ||
6297 ((ctxt->value->type != XPATH_NODESET) &&
6298 (ctxt->value->type != XPATH_XSLT_TREE)))
6299 XP_ERROR(XPATH_INVALID_TYPE);
6300 cur = valuePop(ctxt);
6301
Daniel Veillard911f49a2001-04-07 15:39:35 +00006302 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006303 valuePush(ctxt, xmlXPathNewCString(""));
6304 } else {
6305 int i = 0; /* Should be first in document order !!!!! */
6306 switch (cur->nodesetval->nodeTab[i]->type) {
6307 case XML_ELEMENT_NODE:
6308 case XML_ATTRIBUTE_NODE:
6309 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006310 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6311 valuePush(ctxt, xmlXPathNewCString(""));
6312 else
6313 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006314 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6315 break;
6316 case XML_NAMESPACE_DECL:
6317 valuePush(ctxt, xmlXPathNewString(
6318 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6319 break;
6320 default:
6321 valuePush(ctxt, xmlXPathNewCString(""));
6322 }
6323 }
6324 xmlXPathFreeObject(cur);
6325}
6326
6327/**
6328 * xmlXPathNamespaceURIFunction:
6329 * @ctxt: the XPath Parser context
6330 * @nargs: the number of arguments
6331 *
6332 * Implement the namespace-uri() XPath function
6333 * string namespace-uri(node-set?)
6334 * The namespace-uri function returns a string containing the
6335 * namespace URI of the expanded name of the node in the argument
6336 * node-set that is first in document order. If the node-set is empty,
6337 * the first node has no name, or the expanded name has no namespace
6338 * URI, an empty string is returned. If the argument is omitted it
6339 * defaults to the context node.
6340 */
6341void
6342xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6343 xmlXPathObjectPtr cur;
6344
Daniel Veillarda82b1822004-11-08 16:24:57 +00006345 if (ctxt == NULL) return;
6346
Owen Taylor3473f882001-02-23 17:55:21 +00006347 if (nargs == 0) {
6348 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6349 nargs = 1;
6350 }
6351 CHECK_ARITY(1);
6352 if ((ctxt->value == NULL) ||
6353 ((ctxt->value->type != XPATH_NODESET) &&
6354 (ctxt->value->type != XPATH_XSLT_TREE)))
6355 XP_ERROR(XPATH_INVALID_TYPE);
6356 cur = valuePop(ctxt);
6357
Daniel Veillard911f49a2001-04-07 15:39:35 +00006358 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006359 valuePush(ctxt, xmlXPathNewCString(""));
6360 } else {
6361 int i = 0; /* Should be first in document order !!!!! */
6362 switch (cur->nodesetval->nodeTab[i]->type) {
6363 case XML_ELEMENT_NODE:
6364 case XML_ATTRIBUTE_NODE:
6365 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6366 valuePush(ctxt, xmlXPathNewCString(""));
6367 else
6368 valuePush(ctxt, xmlXPathNewString(
6369 cur->nodesetval->nodeTab[i]->ns->href));
6370 break;
6371 default:
6372 valuePush(ctxt, xmlXPathNewCString(""));
6373 }
6374 }
6375 xmlXPathFreeObject(cur);
6376}
6377
6378/**
6379 * xmlXPathNameFunction:
6380 * @ctxt: the XPath Parser context
6381 * @nargs: the number of arguments
6382 *
6383 * Implement the name() XPath function
6384 * string name(node-set?)
6385 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006386 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006387 * order. The QName must represent the name with respect to the namespace
6388 * declarations in effect on the node whose name is being represented.
6389 * Typically, this will be the form in which the name occurred in the XML
6390 * source. This need not be the case if there are namespace declarations
6391 * in effect on the node that associate multiple prefixes with the same
6392 * namespace. However, an implementation may include information about
6393 * the original prefix in its representation of nodes; in this case, an
6394 * implementation can ensure that the returned string is always the same
6395 * as the QName used in the XML source. If the argument it omitted it
6396 * defaults to the context node.
6397 * Libxml keep the original prefix so the "real qualified name" used is
6398 * returned.
6399 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006400static void
Daniel Veillard04383752001-07-08 14:27:15 +00006401xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6402{
Owen Taylor3473f882001-02-23 17:55:21 +00006403 xmlXPathObjectPtr cur;
6404
6405 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006406 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6407 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006408 }
6409
6410 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006411 if ((ctxt->value == NULL) ||
6412 ((ctxt->value->type != XPATH_NODESET) &&
6413 (ctxt->value->type != XPATH_XSLT_TREE)))
6414 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006415 cur = valuePop(ctxt);
6416
Daniel Veillard911f49a2001-04-07 15:39:35 +00006417 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006418 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006419 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006420 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006421
Daniel Veillard04383752001-07-08 14:27:15 +00006422 switch (cur->nodesetval->nodeTab[i]->type) {
6423 case XML_ELEMENT_NODE:
6424 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006425 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6426 valuePush(ctxt, xmlXPathNewCString(""));
6427 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6428 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006429 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006430 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006431
Daniel Veillard652d8a92003-02-04 19:28:49 +00006432 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006433 xmlChar *fullname;
6434
6435 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6436 cur->nodesetval->nodeTab[i]->ns->prefix,
6437 NULL, 0);
6438 if (fullname == cur->nodesetval->nodeTab[i]->name)
6439 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6440 if (fullname == NULL) {
6441 XP_ERROR(XPATH_MEMORY_ERROR);
6442 }
6443 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006444 }
6445 break;
6446 default:
6447 valuePush(ctxt,
6448 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6449 xmlXPathLocalNameFunction(ctxt, 1);
6450 }
Owen Taylor3473f882001-02-23 17:55:21 +00006451 }
6452 xmlXPathFreeObject(cur);
6453}
6454
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006455
6456/**
Owen Taylor3473f882001-02-23 17:55:21 +00006457 * xmlXPathStringFunction:
6458 * @ctxt: the XPath Parser context
6459 * @nargs: the number of arguments
6460 *
6461 * Implement the string() XPath function
6462 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006463 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006464 * - A node-set is converted to a string by returning the value of
6465 * the node in the node-set that is first in document order.
6466 * If the node-set is empty, an empty string is returned.
6467 * - A number is converted to a string as follows
6468 * + NaN is converted to the string NaN
6469 * + positive zero is converted to the string 0
6470 * + negative zero is converted to the string 0
6471 * + positive infinity is converted to the string Infinity
6472 * + negative infinity is converted to the string -Infinity
6473 * + if the number is an integer, the number is represented in
6474 * decimal form as a Number with no decimal point and no leading
6475 * zeros, preceded by a minus sign (-) if the number is negative
6476 * + otherwise, the number is represented in decimal form as a
6477 * Number including a decimal point with at least one digit
6478 * before the decimal point and at least one digit after the
6479 * decimal point, preceded by a minus sign (-) if the number
6480 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006481 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006482 * before the decimal point; beyond the one required digit
6483 * after the decimal point there must be as many, but only as
6484 * many, more digits as are needed to uniquely distinguish the
6485 * number from all other IEEE 754 numeric values.
6486 * - The boolean false value is converted to the string false.
6487 * The boolean true value is converted to the string true.
6488 *
6489 * If the argument is omitted, it defaults to a node-set with the
6490 * context node as its only member.
6491 */
6492void
6493xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6494 xmlXPathObjectPtr cur;
6495
Daniel Veillarda82b1822004-11-08 16:24:57 +00006496 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006497 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006498 valuePush(ctxt,
6499 xmlXPathWrapString(
6500 xmlXPathCastNodeToString(ctxt->context->node)));
6501 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006502 }
6503
6504 CHECK_ARITY(1);
6505 cur = valuePop(ctxt);
6506 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006507 cur = xmlXPathConvertString(cur);
6508 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006509}
6510
6511/**
6512 * xmlXPathStringLengthFunction:
6513 * @ctxt: the XPath Parser context
6514 * @nargs: the number of arguments
6515 *
6516 * Implement the string-length() XPath function
6517 * number string-length(string?)
6518 * The string-length returns the number of characters in the string
6519 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6520 * the context node converted to a string, in other words the value
6521 * of the context node.
6522 */
6523void
6524xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6525 xmlXPathObjectPtr cur;
6526
6527 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006528 if ((ctxt == NULL) || (ctxt->context == NULL))
6529 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006530 if (ctxt->context->node == NULL) {
6531 valuePush(ctxt, xmlXPathNewFloat(0));
6532 } else {
6533 xmlChar *content;
6534
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006535 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006536 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006537 xmlFree(content);
6538 }
6539 return;
6540 }
6541 CHECK_ARITY(1);
6542 CAST_TO_STRING;
6543 CHECK_TYPE(XPATH_STRING);
6544 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006545 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006546 xmlXPathFreeObject(cur);
6547}
6548
6549/**
6550 * xmlXPathConcatFunction:
6551 * @ctxt: the XPath Parser context
6552 * @nargs: the number of arguments
6553 *
6554 * Implement the concat() XPath function
6555 * string concat(string, string, string*)
6556 * The concat function returns the concatenation of its arguments.
6557 */
6558void
6559xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6560 xmlXPathObjectPtr cur, newobj;
6561 xmlChar *tmp;
6562
Daniel Veillarda82b1822004-11-08 16:24:57 +00006563 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006564 if (nargs < 2) {
6565 CHECK_ARITY(2);
6566 }
6567
6568 CAST_TO_STRING;
6569 cur = valuePop(ctxt);
6570 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6571 xmlXPathFreeObject(cur);
6572 return;
6573 }
6574 nargs--;
6575
6576 while (nargs > 0) {
6577 CAST_TO_STRING;
6578 newobj = valuePop(ctxt);
6579 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6580 xmlXPathFreeObject(newobj);
6581 xmlXPathFreeObject(cur);
6582 XP_ERROR(XPATH_INVALID_TYPE);
6583 }
6584 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6585 newobj->stringval = cur->stringval;
6586 cur->stringval = tmp;
6587
6588 xmlXPathFreeObject(newobj);
6589 nargs--;
6590 }
6591 valuePush(ctxt, cur);
6592}
6593
6594/**
6595 * xmlXPathContainsFunction:
6596 * @ctxt: the XPath Parser context
6597 * @nargs: the number of arguments
6598 *
6599 * Implement the contains() XPath function
6600 * boolean contains(string, string)
6601 * The contains function returns true if the first argument string
6602 * contains the second argument string, and otherwise returns false.
6603 */
6604void
6605xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6606 xmlXPathObjectPtr hay, needle;
6607
6608 CHECK_ARITY(2);
6609 CAST_TO_STRING;
6610 CHECK_TYPE(XPATH_STRING);
6611 needle = valuePop(ctxt);
6612 CAST_TO_STRING;
6613 hay = valuePop(ctxt);
6614 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6615 xmlXPathFreeObject(hay);
6616 xmlXPathFreeObject(needle);
6617 XP_ERROR(XPATH_INVALID_TYPE);
6618 }
6619 if (xmlStrstr(hay->stringval, needle->stringval))
6620 valuePush(ctxt, xmlXPathNewBoolean(1));
6621 else
6622 valuePush(ctxt, xmlXPathNewBoolean(0));
6623 xmlXPathFreeObject(hay);
6624 xmlXPathFreeObject(needle);
6625}
6626
6627/**
6628 * xmlXPathStartsWithFunction:
6629 * @ctxt: the XPath Parser context
6630 * @nargs: the number of arguments
6631 *
6632 * Implement the starts-with() XPath function
6633 * boolean starts-with(string, string)
6634 * The starts-with function returns true if the first argument string
6635 * starts with the second argument string, and otherwise returns false.
6636 */
6637void
6638xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6639 xmlXPathObjectPtr hay, needle;
6640 int n;
6641
6642 CHECK_ARITY(2);
6643 CAST_TO_STRING;
6644 CHECK_TYPE(XPATH_STRING);
6645 needle = valuePop(ctxt);
6646 CAST_TO_STRING;
6647 hay = valuePop(ctxt);
6648 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6649 xmlXPathFreeObject(hay);
6650 xmlXPathFreeObject(needle);
6651 XP_ERROR(XPATH_INVALID_TYPE);
6652 }
6653 n = xmlStrlen(needle->stringval);
6654 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6655 valuePush(ctxt, xmlXPathNewBoolean(0));
6656 else
6657 valuePush(ctxt, xmlXPathNewBoolean(1));
6658 xmlXPathFreeObject(hay);
6659 xmlXPathFreeObject(needle);
6660}
6661
6662/**
6663 * xmlXPathSubstringFunction:
6664 * @ctxt: the XPath Parser context
6665 * @nargs: the number of arguments
6666 *
6667 * Implement the substring() XPath function
6668 * string substring(string, number, number?)
6669 * The substring function returns the substring of the first argument
6670 * starting at the position specified in the second argument with
6671 * length specified in the third argument. For example,
6672 * substring("12345",2,3) returns "234". If the third argument is not
6673 * specified, it returns the substring starting at the position specified
6674 * in the second argument and continuing to the end of the string. For
6675 * example, substring("12345",2) returns "2345". More precisely, each
6676 * character in the string (see [3.6 Strings]) is considered to have a
6677 * numeric position: the position of the first character is 1, the position
6678 * of the second character is 2 and so on. The returned substring contains
6679 * those characters for which the position of the character is greater than
6680 * or equal to the second argument and, if the third argument is specified,
6681 * less than the sum of the second and third arguments; the comparisons
6682 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6683 * - substring("12345", 1.5, 2.6) returns "234"
6684 * - substring("12345", 0, 3) returns "12"
6685 * - substring("12345", 0 div 0, 3) returns ""
6686 * - substring("12345", 1, 0 div 0) returns ""
6687 * - substring("12345", -42, 1 div 0) returns "12345"
6688 * - substring("12345", -1 div 0, 1 div 0) returns ""
6689 */
6690void
6691xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6692 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006693 double le=0, in;
6694 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006695 xmlChar *ret;
6696
Owen Taylor3473f882001-02-23 17:55:21 +00006697 if (nargs < 2) {
6698 CHECK_ARITY(2);
6699 }
6700 if (nargs > 3) {
6701 CHECK_ARITY(3);
6702 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006703 /*
6704 * take care of possible last (position) argument
6705 */
Owen Taylor3473f882001-02-23 17:55:21 +00006706 if (nargs == 3) {
6707 CAST_TO_NUMBER;
6708 CHECK_TYPE(XPATH_NUMBER);
6709 len = valuePop(ctxt);
6710 le = len->floatval;
6711 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006712 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006713
Owen Taylor3473f882001-02-23 17:55:21 +00006714 CAST_TO_NUMBER;
6715 CHECK_TYPE(XPATH_NUMBER);
6716 start = valuePop(ctxt);
6717 in = start->floatval;
6718 xmlXPathFreeObject(start);
6719 CAST_TO_STRING;
6720 CHECK_TYPE(XPATH_STRING);
6721 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006722 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006723
Daniel Veillard97ac1312001-05-30 19:14:17 +00006724 /*
6725 * If last pos not present, calculate last position
6726 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006727 if (nargs != 3) {
6728 le = (double)m;
6729 if (in < 1.0)
6730 in = 1.0;
6731 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006732
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006733 /* Need to check for the special cases where either
6734 * the index is NaN, the length is NaN, or both
6735 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006736 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006737 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006738 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006739 * To meet the requirements of the spec, the arguments
6740 * must be converted to integer format before
6741 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006742 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006743 * First we go to integer form, rounding up
6744 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006745 */
6746 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006747 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006748
Daniel Veillard9e412302002-06-10 15:59:44 +00006749 if (xmlXPathIsInf(le) == 1) {
6750 l = m;
6751 if (i < 1)
6752 i = 1;
6753 }
6754 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6755 l = 0;
6756 else {
6757 l = (int) le;
6758 if (((double)l)+0.5 <= le) l++;
6759 }
6760
6761 /* Now we normalize inidices */
6762 i -= 1;
6763 l += i;
6764 if (i < 0)
6765 i = 0;
6766 if (l > m)
6767 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006768
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006769 /* number of chars to copy */
6770 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006771
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006772 ret = xmlUTF8Strsub(str->stringval, i, l);
6773 }
6774 else {
6775 ret = NULL;
6776 }
6777
Owen Taylor3473f882001-02-23 17:55:21 +00006778 if (ret == NULL)
6779 valuePush(ctxt, xmlXPathNewCString(""));
6780 else {
6781 valuePush(ctxt, xmlXPathNewString(ret));
6782 xmlFree(ret);
6783 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006784
Owen Taylor3473f882001-02-23 17:55:21 +00006785 xmlXPathFreeObject(str);
6786}
6787
6788/**
6789 * xmlXPathSubstringBeforeFunction:
6790 * @ctxt: the XPath Parser context
6791 * @nargs: the number of arguments
6792 *
6793 * Implement the substring-before() XPath function
6794 * string substring-before(string, string)
6795 * The substring-before function returns the substring of the first
6796 * argument string that precedes the first occurrence of the second
6797 * argument string in the first argument string, or the empty string
6798 * if the first argument string does not contain the second argument
6799 * string. For example, substring-before("1999/04/01","/") returns 1999.
6800 */
6801void
6802xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6803 xmlXPathObjectPtr str;
6804 xmlXPathObjectPtr find;
6805 xmlBufferPtr target;
6806 const xmlChar *point;
6807 int offset;
6808
6809 CHECK_ARITY(2);
6810 CAST_TO_STRING;
6811 find = valuePop(ctxt);
6812 CAST_TO_STRING;
6813 str = valuePop(ctxt);
6814
6815 target = xmlBufferCreate();
6816 if (target) {
6817 point = xmlStrstr(str->stringval, find->stringval);
6818 if (point) {
6819 offset = (int)(point - str->stringval);
6820 xmlBufferAdd(target, str->stringval, offset);
6821 }
6822 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6823 xmlBufferFree(target);
6824 }
6825
6826 xmlXPathFreeObject(str);
6827 xmlXPathFreeObject(find);
6828}
6829
6830/**
6831 * xmlXPathSubstringAfterFunction:
6832 * @ctxt: the XPath Parser context
6833 * @nargs: the number of arguments
6834 *
6835 * Implement the substring-after() XPath function
6836 * string substring-after(string, string)
6837 * The substring-after function returns the substring of the first
6838 * argument string that follows the first occurrence of the second
6839 * argument string in the first argument string, or the empty stringi
6840 * if the first argument string does not contain the second argument
6841 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6842 * and substring-after("1999/04/01","19") returns 99/04/01.
6843 */
6844void
6845xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6846 xmlXPathObjectPtr str;
6847 xmlXPathObjectPtr find;
6848 xmlBufferPtr target;
6849 const xmlChar *point;
6850 int offset;
6851
6852 CHECK_ARITY(2);
6853 CAST_TO_STRING;
6854 find = valuePop(ctxt);
6855 CAST_TO_STRING;
6856 str = valuePop(ctxt);
6857
6858 target = xmlBufferCreate();
6859 if (target) {
6860 point = xmlStrstr(str->stringval, find->stringval);
6861 if (point) {
6862 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6863 xmlBufferAdd(target, &str->stringval[offset],
6864 xmlStrlen(str->stringval) - offset);
6865 }
6866 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6867 xmlBufferFree(target);
6868 }
6869
6870 xmlXPathFreeObject(str);
6871 xmlXPathFreeObject(find);
6872}
6873
6874/**
6875 * xmlXPathNormalizeFunction:
6876 * @ctxt: the XPath Parser context
6877 * @nargs: the number of arguments
6878 *
6879 * Implement the normalize-space() XPath function
6880 * string normalize-space(string?)
6881 * The normalize-space function returns the argument string with white
6882 * space normalized by stripping leading and trailing whitespace
6883 * and replacing sequences of whitespace characters by a single
6884 * space. Whitespace characters are the same allowed by the S production
6885 * in XML. If the argument is omitted, it defaults to the context
6886 * node converted to a string, in other words the value of the context node.
6887 */
6888void
6889xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6890 xmlXPathObjectPtr obj = NULL;
6891 xmlChar *source = NULL;
6892 xmlBufferPtr target;
6893 xmlChar blank;
6894
Daniel Veillarda82b1822004-11-08 16:24:57 +00006895 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006896 if (nargs == 0) {
6897 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006898 valuePush(ctxt,
6899 xmlXPathWrapString(
6900 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006901 nargs = 1;
6902 }
6903
6904 CHECK_ARITY(1);
6905 CAST_TO_STRING;
6906 CHECK_TYPE(XPATH_STRING);
6907 obj = valuePop(ctxt);
6908 source = obj->stringval;
6909
6910 target = xmlBufferCreate();
6911 if (target && source) {
6912
6913 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006914 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006915 source++;
6916
6917 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6918 blank = 0;
6919 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006920 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006921 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006922 } else {
6923 if (blank) {
6924 xmlBufferAdd(target, &blank, 1);
6925 blank = 0;
6926 }
6927 xmlBufferAdd(target, source, 1);
6928 }
6929 source++;
6930 }
6931
6932 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6933 xmlBufferFree(target);
6934 }
6935 xmlXPathFreeObject(obj);
6936}
6937
6938/**
6939 * xmlXPathTranslateFunction:
6940 * @ctxt: the XPath Parser context
6941 * @nargs: the number of arguments
6942 *
6943 * Implement the translate() XPath function
6944 * string translate(string, string, string)
6945 * The translate function returns the first argument string with
6946 * occurrences of characters in the second argument string replaced
6947 * by the character at the corresponding position in the third argument
6948 * string. For example, translate("bar","abc","ABC") returns the string
6949 * BAr. If there is a character in the second argument string with no
6950 * character at a corresponding position in the third argument string
6951 * (because the second argument string is longer than the third argument
6952 * string), then occurrences of that character in the first argument
6953 * string are removed. For example, translate("--aaa--","abc-","ABC")
6954 * returns "AAA". If a character occurs more than once in second
6955 * argument string, then the first occurrence determines the replacement
6956 * character. If the third argument string is longer than the second
6957 * argument string, then excess characters are ignored.
6958 */
6959void
6960xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006961 xmlXPathObjectPtr str;
6962 xmlXPathObjectPtr from;
6963 xmlXPathObjectPtr to;
6964 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006965 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006966 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006967 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006968 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006969
Daniel Veillarde043ee12001-04-16 14:08:07 +00006970 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006971
Daniel Veillarde043ee12001-04-16 14:08:07 +00006972 CAST_TO_STRING;
6973 to = valuePop(ctxt);
6974 CAST_TO_STRING;
6975 from = valuePop(ctxt);
6976 CAST_TO_STRING;
6977 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006978
Daniel Veillarde043ee12001-04-16 14:08:07 +00006979 target = xmlBufferCreate();
6980 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006981 max = xmlUTF8Strlen(to->stringval);
6982 for (cptr = str->stringval; (ch=*cptr); ) {
6983 offset = xmlUTF8Strloc(from->stringval, cptr);
6984 if (offset >= 0) {
6985 if (offset < max) {
6986 point = xmlUTF8Strpos(to->stringval, offset);
6987 if (point)
6988 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6989 }
6990 } else
6991 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6992
6993 /* Step to next character in input */
6994 cptr++;
6995 if ( ch & 0x80 ) {
6996 /* if not simple ascii, verify proper format */
6997 if ( (ch & 0xc0) != 0xc0 ) {
6998 xmlGenericError(xmlGenericErrorContext,
6999 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7000 break;
7001 }
7002 /* then skip over remaining bytes for this char */
7003 while ( (ch <<= 1) & 0x80 )
7004 if ( (*cptr++ & 0xc0) != 0x80 ) {
7005 xmlGenericError(xmlGenericErrorContext,
7006 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
7007 break;
7008 }
7009 if (ch & 0x80) /* must have had error encountered */
7010 break;
7011 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007012 }
Owen Taylor3473f882001-02-23 17:55:21 +00007013 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007014 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7015 xmlBufferFree(target);
7016 xmlXPathFreeObject(str);
7017 xmlXPathFreeObject(from);
7018 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007019}
7020
7021/**
7022 * xmlXPathBooleanFunction:
7023 * @ctxt: the XPath Parser context
7024 * @nargs: the number of arguments
7025 *
7026 * Implement the boolean() XPath function
7027 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007028 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007029 * - a number is true if and only if it is neither positive or
7030 * negative zero nor NaN
7031 * - a node-set is true if and only if it is non-empty
7032 * - a string is true if and only if its length is non-zero
7033 */
7034void
7035xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7036 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007037
7038 CHECK_ARITY(1);
7039 cur = valuePop(ctxt);
7040 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007041 cur = xmlXPathConvertBoolean(cur);
7042 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007043}
7044
7045/**
7046 * xmlXPathNotFunction:
7047 * @ctxt: the XPath Parser context
7048 * @nargs: the number of arguments
7049 *
7050 * Implement the not() XPath function
7051 * boolean not(boolean)
7052 * The not function returns true if its argument is false,
7053 * and false otherwise.
7054 */
7055void
7056xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7057 CHECK_ARITY(1);
7058 CAST_TO_BOOLEAN;
7059 CHECK_TYPE(XPATH_BOOLEAN);
7060 ctxt->value->boolval = ! ctxt->value->boolval;
7061}
7062
7063/**
7064 * xmlXPathTrueFunction:
7065 * @ctxt: the XPath Parser context
7066 * @nargs: the number of arguments
7067 *
7068 * Implement the true() XPath function
7069 * boolean true()
7070 */
7071void
7072xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7073 CHECK_ARITY(0);
7074 valuePush(ctxt, xmlXPathNewBoolean(1));
7075}
7076
7077/**
7078 * xmlXPathFalseFunction:
7079 * @ctxt: the XPath Parser context
7080 * @nargs: the number of arguments
7081 *
7082 * Implement the false() XPath function
7083 * boolean false()
7084 */
7085void
7086xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7087 CHECK_ARITY(0);
7088 valuePush(ctxt, xmlXPathNewBoolean(0));
7089}
7090
7091/**
7092 * xmlXPathLangFunction:
7093 * @ctxt: the XPath Parser context
7094 * @nargs: the number of arguments
7095 *
7096 * Implement the lang() XPath function
7097 * boolean lang(string)
7098 * The lang function returns true or false depending on whether the
7099 * language of the context node as specified by xml:lang attributes
7100 * is the same as or is a sublanguage of the language specified by
7101 * the argument string. The language of the context node is determined
7102 * by the value of the xml:lang attribute on the context node, or, if
7103 * the context node has no xml:lang attribute, by the value of the
7104 * xml:lang attribute on the nearest ancestor of the context node that
7105 * has an xml:lang attribute. If there is no such attribute, then lang
7106 * returns false. If there is such an attribute, then lang returns
7107 * true if the attribute value is equal to the argument ignoring case,
7108 * or if there is some suffix starting with - such that the attribute
7109 * value is equal to the argument ignoring that suffix of the attribute
7110 * value and ignoring case.
7111 */
7112void
7113xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007114 xmlXPathObjectPtr val = NULL;
7115 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007116 const xmlChar *lang;
7117 int ret = 0;
7118 int i;
7119
7120 CHECK_ARITY(1);
7121 CAST_TO_STRING;
7122 CHECK_TYPE(XPATH_STRING);
7123 val = valuePop(ctxt);
7124 lang = val->stringval;
7125 theLang = xmlNodeGetLang(ctxt->context->node);
7126 if ((theLang != NULL) && (lang != NULL)) {
7127 for (i = 0;lang[i] != 0;i++)
7128 if (toupper(lang[i]) != toupper(theLang[i]))
7129 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007130 if ((theLang[i] == 0) || (theLang[i] == '-'))
7131 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007132 }
7133not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007134 if (theLang != NULL)
7135 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007136 xmlXPathFreeObject(val);
7137 valuePush(ctxt, xmlXPathNewBoolean(ret));
7138}
7139
7140/**
7141 * xmlXPathNumberFunction:
7142 * @ctxt: the XPath Parser context
7143 * @nargs: the number of arguments
7144 *
7145 * Implement the number() XPath function
7146 * number number(object?)
7147 */
7148void
7149xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7150 xmlXPathObjectPtr cur;
7151 double res;
7152
Daniel Veillarda82b1822004-11-08 16:24:57 +00007153 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007154 if (nargs == 0) {
7155 if (ctxt->context->node == NULL) {
7156 valuePush(ctxt, xmlXPathNewFloat(0.0));
7157 } else {
7158 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7159
7160 res = xmlXPathStringEvalNumber(content);
7161 valuePush(ctxt, xmlXPathNewFloat(res));
7162 xmlFree(content);
7163 }
7164 return;
7165 }
7166
7167 CHECK_ARITY(1);
7168 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007169 cur = xmlXPathConvertNumber(cur);
7170 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007171}
7172
7173/**
7174 * xmlXPathSumFunction:
7175 * @ctxt: the XPath Parser context
7176 * @nargs: the number of arguments
7177 *
7178 * Implement the sum() XPath function
7179 * number sum(node-set)
7180 * The sum function returns the sum of the values of the nodes in
7181 * the argument node-set.
7182 */
7183void
7184xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7185 xmlXPathObjectPtr cur;
7186 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007187 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007188
7189 CHECK_ARITY(1);
7190 if ((ctxt->value == NULL) ||
7191 ((ctxt->value->type != XPATH_NODESET) &&
7192 (ctxt->value->type != XPATH_XSLT_TREE)))
7193 XP_ERROR(XPATH_INVALID_TYPE);
7194 cur = valuePop(ctxt);
7195
William M. Brack08171912003-12-29 02:52:11 +00007196 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007197 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7198 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007199 }
7200 }
William M. Brack08171912003-12-29 02:52:11 +00007201 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007202 xmlXPathFreeObject(cur);
7203}
7204
William M. Brack3d426662005-04-19 14:40:28 +00007205/*
7206 * To assure working code on multiple platforms, we want to only depend
7207 * upon the characteristic truncation of converting a floating point value
7208 * to an integer. Unfortunately, because of the different storage sizes
7209 * of our internal floating point value (double) and integer (int), we
7210 * can't directly convert (see bug 301162). This macro is a messy
7211 * 'workaround'
7212 */
7213#define XTRUNC(f, v) \
7214 f = fmod((v), INT_MAX); \
7215 f = (v) - (f) + (double)((int)(f));
7216
Owen Taylor3473f882001-02-23 17:55:21 +00007217/**
7218 * xmlXPathFloorFunction:
7219 * @ctxt: the XPath Parser context
7220 * @nargs: the number of arguments
7221 *
7222 * Implement the floor() XPath function
7223 * number floor(number)
7224 * The floor function returns the largest (closest to positive infinity)
7225 * number that is not greater than the argument and that is an integer.
7226 */
7227void
7228xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007229 double f;
7230
Owen Taylor3473f882001-02-23 17:55:21 +00007231 CHECK_ARITY(1);
7232 CAST_TO_NUMBER;
7233 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007234
William M. Brack3d426662005-04-19 14:40:28 +00007235 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007236 if (f != ctxt->value->floatval) {
7237 if (ctxt->value->floatval > 0)
7238 ctxt->value->floatval = f;
7239 else
7240 ctxt->value->floatval = f - 1;
7241 }
Owen Taylor3473f882001-02-23 17:55:21 +00007242}
7243
7244/**
7245 * xmlXPathCeilingFunction:
7246 * @ctxt: the XPath Parser context
7247 * @nargs: the number of arguments
7248 *
7249 * Implement the ceiling() XPath function
7250 * number ceiling(number)
7251 * The ceiling function returns the smallest (closest to negative infinity)
7252 * number that is not less than the argument and that is an integer.
7253 */
7254void
7255xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7256 double f;
7257
7258 CHECK_ARITY(1);
7259 CAST_TO_NUMBER;
7260 CHECK_TYPE(XPATH_NUMBER);
7261
7262#if 0
7263 ctxt->value->floatval = ceil(ctxt->value->floatval);
7264#else
William M. Brack3d426662005-04-19 14:40:28 +00007265 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007266 if (f != ctxt->value->floatval) {
7267 if (ctxt->value->floatval > 0)
7268 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007269 else {
7270 if (ctxt->value->floatval < 0 && f == 0)
7271 ctxt->value->floatval = xmlXPathNZERO;
7272 else
7273 ctxt->value->floatval = f;
7274 }
7275
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007276 }
Owen Taylor3473f882001-02-23 17:55:21 +00007277#endif
7278}
7279
7280/**
7281 * xmlXPathRoundFunction:
7282 * @ctxt: the XPath Parser context
7283 * @nargs: the number of arguments
7284 *
7285 * Implement the round() XPath function
7286 * number round(number)
7287 * The round function returns the number that is closest to the
7288 * argument and that is an integer. If there are two such numbers,
7289 * then the one that is even is returned.
7290 */
7291void
7292xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7293 double f;
7294
7295 CHECK_ARITY(1);
7296 CAST_TO_NUMBER;
7297 CHECK_TYPE(XPATH_NUMBER);
7298
Daniel Veillardcda96922001-08-21 10:56:31 +00007299 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7300 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7301 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007302 (ctxt->value->floatval == 0.0))
7303 return;
7304
William M. Brack3d426662005-04-19 14:40:28 +00007305 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007306 if (ctxt->value->floatval < 0) {
7307 if (ctxt->value->floatval < f - 0.5)
7308 ctxt->value->floatval = f - 1;
7309 else
7310 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007311 if (ctxt->value->floatval == 0)
7312 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007313 } else {
7314 if (ctxt->value->floatval < f + 0.5)
7315 ctxt->value->floatval = f;
7316 else
7317 ctxt->value->floatval = f + 1;
7318 }
Owen Taylor3473f882001-02-23 17:55:21 +00007319}
7320
7321/************************************************************************
7322 * *
7323 * The Parser *
7324 * *
7325 ************************************************************************/
7326
7327/*
William M. Brack08171912003-12-29 02:52:11 +00007328 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007329 * implementation.
7330 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007331static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007332static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007333static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007334static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007335static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7336 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007337
7338/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007339 * xmlXPathCurrentChar:
7340 * @ctxt: the XPath parser context
7341 * @cur: pointer to the beginning of the char
7342 * @len: pointer to the length of the char read
7343 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007344 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007345 * bytes in the input buffer.
7346 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007347 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007348 */
7349
7350static int
7351xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7352 unsigned char c;
7353 unsigned int val;
7354 const xmlChar *cur;
7355
7356 if (ctxt == NULL)
7357 return(0);
7358 cur = ctxt->cur;
7359
7360 /*
7361 * We are supposed to handle UTF8, check it's valid
7362 * From rfc2044: encoding of the Unicode values on UTF-8:
7363 *
7364 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7365 * 0000 0000-0000 007F 0xxxxxxx
7366 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7367 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7368 *
7369 * Check for the 0x110000 limit too
7370 */
7371 c = *cur;
7372 if (c & 0x80) {
7373 if ((cur[1] & 0xc0) != 0x80)
7374 goto encoding_error;
7375 if ((c & 0xe0) == 0xe0) {
7376
7377 if ((cur[2] & 0xc0) != 0x80)
7378 goto encoding_error;
7379 if ((c & 0xf0) == 0xf0) {
7380 if (((c & 0xf8) != 0xf0) ||
7381 ((cur[3] & 0xc0) != 0x80))
7382 goto encoding_error;
7383 /* 4-byte code */
7384 *len = 4;
7385 val = (cur[0] & 0x7) << 18;
7386 val |= (cur[1] & 0x3f) << 12;
7387 val |= (cur[2] & 0x3f) << 6;
7388 val |= cur[3] & 0x3f;
7389 } else {
7390 /* 3-byte code */
7391 *len = 3;
7392 val = (cur[0] & 0xf) << 12;
7393 val |= (cur[1] & 0x3f) << 6;
7394 val |= cur[2] & 0x3f;
7395 }
7396 } else {
7397 /* 2-byte code */
7398 *len = 2;
7399 val = (cur[0] & 0x1f) << 6;
7400 val |= cur[1] & 0x3f;
7401 }
7402 if (!IS_CHAR(val)) {
7403 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7404 }
7405 return(val);
7406 } else {
7407 /* 1-byte code */
7408 *len = 1;
7409 return((int) *cur);
7410 }
7411encoding_error:
7412 /*
William M. Brack08171912003-12-29 02:52:11 +00007413 * If we detect an UTF8 error that probably means that the
7414 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007415 * declaration header. Report the error and switch the encoding
7416 * to ISO-Latin-1 (if you don't like this policy, just declare the
7417 * encoding !)
7418 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007419 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007420 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007421}
7422
7423/**
Owen Taylor3473f882001-02-23 17:55:21 +00007424 * xmlXPathParseNCName:
7425 * @ctxt: the XPath Parser context
7426 *
7427 * parse an XML namespace non qualified name.
7428 *
7429 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7430 *
7431 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7432 * CombiningChar | Extender
7433 *
7434 * Returns the namespace name or NULL
7435 */
7436
7437xmlChar *
7438xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007439 const xmlChar *in;
7440 xmlChar *ret;
7441 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007442
Daniel Veillarda82b1822004-11-08 16:24:57 +00007443 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007444 /*
7445 * Accelerator for simple ASCII names
7446 */
7447 in = ctxt->cur;
7448 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7449 ((*in >= 0x41) && (*in <= 0x5A)) ||
7450 (*in == '_')) {
7451 in++;
7452 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7453 ((*in >= 0x41) && (*in <= 0x5A)) ||
7454 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007455 (*in == '_') || (*in == '.') ||
7456 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007457 in++;
7458 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7459 (*in == '[') || (*in == ']') || (*in == ':') ||
7460 (*in == '@') || (*in == '*')) {
7461 count = in - ctxt->cur;
7462 if (count == 0)
7463 return(NULL);
7464 ret = xmlStrndup(ctxt->cur, count);
7465 ctxt->cur = in;
7466 return(ret);
7467 }
7468 }
7469 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007470}
7471
Daniel Veillard2156a562001-04-28 12:24:34 +00007472
Owen Taylor3473f882001-02-23 17:55:21 +00007473/**
7474 * xmlXPathParseQName:
7475 * @ctxt: the XPath Parser context
7476 * @prefix: a xmlChar **
7477 *
7478 * parse an XML qualified name
7479 *
7480 * [NS 5] QName ::= (Prefix ':')? LocalPart
7481 *
7482 * [NS 6] Prefix ::= NCName
7483 *
7484 * [NS 7] LocalPart ::= NCName
7485 *
7486 * Returns the function returns the local part, and prefix is updated
7487 * to get the Prefix if any.
7488 */
7489
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007490static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007491xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7492 xmlChar *ret = NULL;
7493
7494 *prefix = NULL;
7495 ret = xmlXPathParseNCName(ctxt);
7496 if (CUR == ':') {
7497 *prefix = ret;
7498 NEXT;
7499 ret = xmlXPathParseNCName(ctxt);
7500 }
7501 return(ret);
7502}
7503
7504/**
7505 * xmlXPathParseName:
7506 * @ctxt: the XPath Parser context
7507 *
7508 * parse an XML name
7509 *
7510 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7511 * CombiningChar | Extender
7512 *
7513 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7514 *
7515 * Returns the namespace name or NULL
7516 */
7517
7518xmlChar *
7519xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007520 const xmlChar *in;
7521 xmlChar *ret;
7522 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007523
Daniel Veillarda82b1822004-11-08 16:24:57 +00007524 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007525 /*
7526 * Accelerator for simple ASCII names
7527 */
7528 in = ctxt->cur;
7529 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7530 ((*in >= 0x41) && (*in <= 0x5A)) ||
7531 (*in == '_') || (*in == ':')) {
7532 in++;
7533 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7534 ((*in >= 0x41) && (*in <= 0x5A)) ||
7535 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007536 (*in == '_') || (*in == '-') ||
7537 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007538 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007539 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007540 count = in - ctxt->cur;
7541 ret = xmlStrndup(ctxt->cur, count);
7542 ctxt->cur = in;
7543 return(ret);
7544 }
7545 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007546 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007547}
7548
Daniel Veillard61d80a22001-04-27 17:13:01 +00007549static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007550xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007551 xmlChar buf[XML_MAX_NAMELEN + 5];
7552 int len = 0, l;
7553 int c;
7554
7555 /*
7556 * Handler for more complex cases
7557 */
7558 c = CUR_CHAR(l);
7559 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007560 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7561 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007562 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007563 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007564 return(NULL);
7565 }
7566
7567 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7568 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7569 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007570 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007571 (IS_COMBINING(c)) ||
7572 (IS_EXTENDER(c)))) {
7573 COPY_BUF(l,buf,len,c);
7574 NEXTL(l);
7575 c = CUR_CHAR(l);
7576 if (len >= XML_MAX_NAMELEN) {
7577 /*
7578 * Okay someone managed to make a huge name, so he's ready to pay
7579 * for the processing speed.
7580 */
7581 xmlChar *buffer;
7582 int max = len * 2;
7583
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007584 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007585 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007586 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007587 }
7588 memcpy(buffer, buf, len);
7589 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7590 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007591 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007592 (IS_COMBINING(c)) ||
7593 (IS_EXTENDER(c))) {
7594 if (len + 10 > max) {
7595 max *= 2;
7596 buffer = (xmlChar *) xmlRealloc(buffer,
7597 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007598 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007599 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007600 }
7601 }
7602 COPY_BUF(l,buffer,len,c);
7603 NEXTL(l);
7604 c = CUR_CHAR(l);
7605 }
7606 buffer[len] = 0;
7607 return(buffer);
7608 }
7609 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007610 if (len == 0)
7611 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007612 return(xmlStrndup(buf, len));
7613}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007614
7615#define MAX_FRAC 20
7616
William M. Brack372a4452004-02-17 13:09:23 +00007617/*
7618 * These are used as divisors for the fractional part of a number.
7619 * Since the table includes 1.0 (representing '0' fractional digits),
7620 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7621 */
7622static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007623 1.0, 10.0, 100.0, 1000.0, 10000.0,
7624 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7625 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7626 100000000000000.0,
7627 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007628 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007629};
7630
Owen Taylor3473f882001-02-23 17:55:21 +00007631/**
7632 * xmlXPathStringEvalNumber:
7633 * @str: A string to scan
7634 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007635 * [30a] Float ::= Number ('e' Digits?)?
7636 *
Owen Taylor3473f882001-02-23 17:55:21 +00007637 * [30] Number ::= Digits ('.' Digits?)?
7638 * | '.' Digits
7639 * [31] Digits ::= [0-9]+
7640 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007641 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007642 * In complement of the Number expression, this function also handles
7643 * negative values : '-' Number.
7644 *
7645 * Returns the double value.
7646 */
7647double
7648xmlXPathStringEvalNumber(const xmlChar *str) {
7649 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007650 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007651 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007652 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007653 int exponent = 0;
7654 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007655#ifdef __GNUC__
7656 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007657 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007658#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007659 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007660 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007661 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7662 return(xmlXPathNAN);
7663 }
7664 if (*cur == '-') {
7665 isneg = 1;
7666 cur++;
7667 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007668
7669#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007670 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007671 * tmp/temp is a workaround against a gcc compiler bug
7672 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007673 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007674 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007675 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007676 ret = ret * 10;
7677 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007678 ok = 1;
7679 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007680 temp = (double) tmp;
7681 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007682 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007683#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007684 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007685 while ((*cur >= '0') && (*cur <= '9')) {
7686 ret = ret * 10 + (*cur - '0');
7687 ok = 1;
7688 cur++;
7689 }
7690#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007691
Owen Taylor3473f882001-02-23 17:55:21 +00007692 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007693 int v, frac = 0;
7694 double fraction = 0;
7695
Owen Taylor3473f882001-02-23 17:55:21 +00007696 cur++;
7697 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7698 return(xmlXPathNAN);
7699 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007700 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7701 v = (*cur - '0');
7702 fraction = fraction * 10 + v;
7703 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007704 cur++;
7705 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007706 fraction /= my_pow10[frac];
7707 ret = ret + fraction;
7708 while ((*cur >= '0') && (*cur <= '9'))
7709 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007710 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007711 if ((*cur == 'e') || (*cur == 'E')) {
7712 cur++;
7713 if (*cur == '-') {
7714 is_exponent_negative = 1;
7715 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007716 } else if (*cur == '+') {
7717 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007718 }
7719 while ((*cur >= '0') && (*cur <= '9')) {
7720 exponent = exponent * 10 + (*cur - '0');
7721 cur++;
7722 }
7723 }
William M. Brack76e95df2003-10-18 16:20:14 +00007724 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007725 if (*cur != 0) return(xmlXPathNAN);
7726 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007727 if (is_exponent_negative) exponent = -exponent;
7728 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007729 return(ret);
7730}
7731
7732/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007733 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007734 * @ctxt: the XPath Parser context
7735 *
7736 * [30] Number ::= Digits ('.' Digits?)?
7737 * | '.' Digits
7738 * [31] Digits ::= [0-9]+
7739 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007740 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007741 *
7742 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007743static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007744xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7745{
Owen Taylor3473f882001-02-23 17:55:21 +00007746 double ret = 0.0;
7747 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007748 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007749 int exponent = 0;
7750 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007751#ifdef __GNUC__
7752 unsigned long tmp = 0;
7753 double temp;
7754#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007755
7756 CHECK_ERROR;
7757 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7758 XP_ERROR(XPATH_NUMBER_ERROR);
7759 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007760#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007761 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007762 * tmp/temp is a workaround against a gcc compiler bug
7763 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007764 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007765 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007766 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007767 ret = ret * 10;
7768 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007769 ok = 1;
7770 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007771 temp = (double) tmp;
7772 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007773 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007774#else
7775 ret = 0;
7776 while ((CUR >= '0') && (CUR <= '9')) {
7777 ret = ret * 10 + (CUR - '0');
7778 ok = 1;
7779 NEXT;
7780 }
7781#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007782 if (CUR == '.') {
7783 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007784 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7785 XP_ERROR(XPATH_NUMBER_ERROR);
7786 }
7787 while ((CUR >= '0') && (CUR <= '9')) {
7788 mult /= 10;
7789 ret = ret + (CUR - '0') * mult;
7790 NEXT;
7791 }
Owen Taylor3473f882001-02-23 17:55:21 +00007792 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007793 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007794 NEXT;
7795 if (CUR == '-') {
7796 is_exponent_negative = 1;
7797 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007798 } else if (CUR == '+') {
7799 NEXT;
7800 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007801 while ((CUR >= '0') && (CUR <= '9')) {
7802 exponent = exponent * 10 + (CUR - '0');
7803 NEXT;
7804 }
7805 if (is_exponent_negative)
7806 exponent = -exponent;
7807 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007808 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007809 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007810 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007811}
7812
7813/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007814 * xmlXPathParseLiteral:
7815 * @ctxt: the XPath Parser context
7816 *
7817 * Parse a Literal
7818 *
7819 * [29] Literal ::= '"' [^"]* '"'
7820 * | "'" [^']* "'"
7821 *
7822 * Returns the value found or NULL in case of error
7823 */
7824static xmlChar *
7825xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7826 const xmlChar *q;
7827 xmlChar *ret = NULL;
7828
7829 if (CUR == '"') {
7830 NEXT;
7831 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007832 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007833 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007834 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007835 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007836 } else {
7837 ret = xmlStrndup(q, CUR_PTR - q);
7838 NEXT;
7839 }
7840 } else if (CUR == '\'') {
7841 NEXT;
7842 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007843 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007844 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007845 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007846 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007847 } else {
7848 ret = xmlStrndup(q, CUR_PTR - q);
7849 NEXT;
7850 }
7851 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00007852 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007853 }
7854 return(ret);
7855}
7856
7857/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007858 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007859 * @ctxt: the XPath Parser context
7860 *
7861 * Parse a Literal and push it on the stack.
7862 *
7863 * [29] Literal ::= '"' [^"]* '"'
7864 * | "'" [^']* "'"
7865 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007866 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007867 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007868static void
7869xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007870 const xmlChar *q;
7871 xmlChar *ret = NULL;
7872
7873 if (CUR == '"') {
7874 NEXT;
7875 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007876 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007877 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007878 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007879 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7880 } else {
7881 ret = xmlStrndup(q, CUR_PTR - q);
7882 NEXT;
7883 }
7884 } else if (CUR == '\'') {
7885 NEXT;
7886 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007887 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007888 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007889 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007890 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7891 } else {
7892 ret = xmlStrndup(q, CUR_PTR - q);
7893 NEXT;
7894 }
7895 } else {
7896 XP_ERROR(XPATH_START_LITERAL_ERROR);
7897 }
7898 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007899 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7900 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007901 xmlFree(ret);
7902}
7903
7904/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007905 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007906 * @ctxt: the XPath Parser context
7907 *
7908 * Parse a VariableReference, evaluate it and push it on the stack.
7909 *
7910 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007911 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007912 * of any of the types that are possible for the value of an expression,
7913 * and may also be of additional types not specified here.
7914 *
7915 * Early evaluation is possible since:
7916 * The variable bindings [...] used to evaluate a subexpression are
7917 * always the same as those used to evaluate the containing expression.
7918 *
7919 * [36] VariableReference ::= '$' QName
7920 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007921static void
7922xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007923 xmlChar *name;
7924 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007925
7926 SKIP_BLANKS;
7927 if (CUR != '$') {
7928 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7929 }
7930 NEXT;
7931 name = xmlXPathParseQName(ctxt, &prefix);
7932 if (name == NULL) {
7933 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7934 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007935 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007936 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7937 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007938 SKIP_BLANKS;
7939}
7940
7941/**
7942 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007943 * @name: a name string
7944 *
7945 * Is the name given a NodeType one.
7946 *
7947 * [38] NodeType ::= 'comment'
7948 * | 'text'
7949 * | 'processing-instruction'
7950 * | 'node'
7951 *
7952 * Returns 1 if true 0 otherwise
7953 */
7954int
7955xmlXPathIsNodeType(const xmlChar *name) {
7956 if (name == NULL)
7957 return(0);
7958
Daniel Veillard1971ee22002-01-31 20:29:19 +00007959 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007960 return(1);
7961 if (xmlStrEqual(name, BAD_CAST "text"))
7962 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007963 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007964 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007965 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007966 return(1);
7967 return(0);
7968}
7969
7970/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007971 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007972 * @ctxt: the XPath Parser context
7973 *
7974 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7975 * [17] Argument ::= Expr
7976 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007977 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007978 * pushed on the stack
7979 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007980static void
7981xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007982 xmlChar *name;
7983 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007984 int nbargs = 0;
7985
7986 name = xmlXPathParseQName(ctxt, &prefix);
7987 if (name == NULL) {
7988 XP_ERROR(XPATH_EXPR_ERROR);
7989 }
7990 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007991#ifdef DEBUG_EXPR
7992 if (prefix == NULL)
7993 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7994 name);
7995 else
7996 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7997 prefix, name);
7998#endif
7999
Owen Taylor3473f882001-02-23 17:55:21 +00008000 if (CUR != '(') {
8001 XP_ERROR(XPATH_EXPR_ERROR);
8002 }
8003 NEXT;
8004 SKIP_BLANKS;
8005
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008006 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00008007 if (CUR != ')') {
8008 while (CUR != 0) {
8009 int op1 = ctxt->comp->last;
8010 ctxt->comp->last = -1;
8011 xmlXPathCompileExpr(ctxt);
8012 CHECK_ERROR;
8013 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8014 nbargs++;
8015 if (CUR == ')') break;
8016 if (CUR != ',') {
8017 XP_ERROR(XPATH_EXPR_ERROR);
8018 }
8019 NEXT;
8020 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008021 }
Owen Taylor3473f882001-02-23 17:55:21 +00008022 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008023 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8024 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008025 NEXT;
8026 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008027}
8028
8029/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008030 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008031 * @ctxt: the XPath Parser context
8032 *
8033 * [15] PrimaryExpr ::= VariableReference
8034 * | '(' Expr ')'
8035 * | Literal
8036 * | Number
8037 * | FunctionCall
8038 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008039 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008040 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008041static void
8042xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008043 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008044 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008045 else if (CUR == '(') {
8046 NEXT;
8047 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008048 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008049 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008050 if (CUR != ')') {
8051 XP_ERROR(XPATH_EXPR_ERROR);
8052 }
8053 NEXT;
8054 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008055 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008056 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008057 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008058 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008059 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008060 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008061 }
8062 SKIP_BLANKS;
8063}
8064
8065/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008067 * @ctxt: the XPath Parser context
8068 *
8069 * [20] FilterExpr ::= PrimaryExpr
8070 * | FilterExpr Predicate
8071 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008072 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008073 * Square brackets are used to filter expressions in the same way that
8074 * they are used in location paths. It is an error if the expression to
8075 * be filtered does not evaluate to a node-set. The context node list
8076 * used for evaluating the expression in square brackets is the node-set
8077 * to be filtered listed in document order.
8078 */
8079
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008080static void
8081xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8082 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008083 CHECK_ERROR;
8084 SKIP_BLANKS;
8085
8086 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008087 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008088 SKIP_BLANKS;
8089 }
8090
8091
8092}
8093
8094/**
8095 * xmlXPathScanName:
8096 * @ctxt: the XPath Parser context
8097 *
8098 * Trickery: parse an XML name but without consuming the input flow
8099 * Needed to avoid insanity in the parser state.
8100 *
8101 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8102 * CombiningChar | Extender
8103 *
8104 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8105 *
8106 * [6] Names ::= Name (S Name)*
8107 *
8108 * Returns the Name parsed or NULL
8109 */
8110
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008111static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008112xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008113 int len = 0, l;
8114 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008115 const xmlChar *cur;
8116 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008117
Daniel Veillard03226812004-11-01 14:55:21 +00008118 cur = ctxt->cur;
8119
8120 c = CUR_CHAR(l);
8121 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8122 (!IS_LETTER(c) && (c != '_') &&
8123 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008124 return(NULL);
8125 }
8126
Daniel Veillard03226812004-11-01 14:55:21 +00008127 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8128 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8129 (c == '.') || (c == '-') ||
8130 (c == '_') || (c == ':') ||
8131 (IS_COMBINING(c)) ||
8132 (IS_EXTENDER(c)))) {
8133 len += l;
8134 NEXTL(l);
8135 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008136 }
Daniel Veillard03226812004-11-01 14:55:21 +00008137 ret = xmlStrndup(cur, ctxt->cur - cur);
8138 ctxt->cur = cur;
8139 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008140}
8141
8142/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008143 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008144 * @ctxt: the XPath Parser context
8145 *
8146 * [19] PathExpr ::= LocationPath
8147 * | FilterExpr
8148 * | FilterExpr '/' RelativeLocationPath
8149 * | FilterExpr '//' RelativeLocationPath
8150 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008151 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008152 * The / operator and // operators combine an arbitrary expression
8153 * and a relative location path. It is an error if the expression
8154 * does not evaluate to a node-set.
8155 * The / operator does composition in the same way as when / is
8156 * used in a location path. As in location paths, // is short for
8157 * /descendant-or-self::node()/.
8158 */
8159
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008160static void
8161xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008162 int lc = 1; /* Should we branch to LocationPath ? */
8163 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8164
8165 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008166 if ((CUR == '$') || (CUR == '(') ||
8167 (IS_ASCII_DIGIT(CUR)) ||
8168 (CUR == '\'') || (CUR == '"') ||
8169 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008170 lc = 0;
8171 } else if (CUR == '*') {
8172 /* relative or absolute location path */
8173 lc = 1;
8174 } else if (CUR == '/') {
8175 /* relative or absolute location path */
8176 lc = 1;
8177 } else if (CUR == '@') {
8178 /* relative abbreviated attribute location path */
8179 lc = 1;
8180 } else if (CUR == '.') {
8181 /* relative abbreviated attribute location path */
8182 lc = 1;
8183 } else {
8184 /*
8185 * Problem is finding if we have a name here whether it's:
8186 * - a nodetype
8187 * - a function call in which case it's followed by '('
8188 * - an axis in which case it's followed by ':'
8189 * - a element name
8190 * We do an a priori analysis here rather than having to
8191 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008192 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008193 * read/write/debug.
8194 */
8195 SKIP_BLANKS;
8196 name = xmlXPathScanName(ctxt);
8197 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8198#ifdef DEBUG_STEP
8199 xmlGenericError(xmlGenericErrorContext,
8200 "PathExpr: Axis\n");
8201#endif
8202 lc = 1;
8203 xmlFree(name);
8204 } else if (name != NULL) {
8205 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008206
8207
8208 while (NXT(len) != 0) {
8209 if (NXT(len) == '/') {
8210 /* element name */
8211#ifdef DEBUG_STEP
8212 xmlGenericError(xmlGenericErrorContext,
8213 "PathExpr: AbbrRelLocation\n");
8214#endif
8215 lc = 1;
8216 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008217 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008218 /* ignore blanks */
8219 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008220 } else if (NXT(len) == ':') {
8221#ifdef DEBUG_STEP
8222 xmlGenericError(xmlGenericErrorContext,
8223 "PathExpr: AbbrRelLocation\n");
8224#endif
8225 lc = 1;
8226 break;
8227 } else if ((NXT(len) == '(')) {
8228 /* Note Type or Function */
8229 if (xmlXPathIsNodeType(name)) {
8230#ifdef DEBUG_STEP
8231 xmlGenericError(xmlGenericErrorContext,
8232 "PathExpr: Type search\n");
8233#endif
8234 lc = 1;
8235 } else {
8236#ifdef DEBUG_STEP
8237 xmlGenericError(xmlGenericErrorContext,
8238 "PathExpr: function call\n");
8239#endif
8240 lc = 0;
8241 }
8242 break;
8243 } else if ((NXT(len) == '[')) {
8244 /* element name */
8245#ifdef DEBUG_STEP
8246 xmlGenericError(xmlGenericErrorContext,
8247 "PathExpr: AbbrRelLocation\n");
8248#endif
8249 lc = 1;
8250 break;
8251 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8252 (NXT(len) == '=')) {
8253 lc = 1;
8254 break;
8255 } else {
8256 lc = 1;
8257 break;
8258 }
8259 len++;
8260 }
8261 if (NXT(len) == 0) {
8262#ifdef DEBUG_STEP
8263 xmlGenericError(xmlGenericErrorContext,
8264 "PathExpr: AbbrRelLocation\n");
8265#endif
8266 /* element name */
8267 lc = 1;
8268 }
8269 xmlFree(name);
8270 } else {
William M. Brack08171912003-12-29 02:52:11 +00008271 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008272 XP_ERROR(XPATH_EXPR_ERROR);
8273 }
8274 }
8275
8276 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008277 if (CUR == '/') {
8278 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8279 } else {
8280 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008281 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008282 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008283 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008284 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008285 CHECK_ERROR;
8286 if ((CUR == '/') && (NXT(1) == '/')) {
8287 SKIP(2);
8288 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008289
8290 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8291 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8292 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8293
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008296 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008297 }
8298 }
8299 SKIP_BLANKS;
8300}
8301
8302/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008303 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008304 * @ctxt: the XPath Parser context
8305 *
8306 * [18] UnionExpr ::= PathExpr
8307 * | UnionExpr '|' PathExpr
8308 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008309 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008310 */
8311
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312static void
8313xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8314 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008315 CHECK_ERROR;
8316 SKIP_BLANKS;
8317 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008318 int op1 = ctxt->comp->last;
8319 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008320
8321 NEXT;
8322 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008323 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008324
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008325 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8326
Owen Taylor3473f882001-02-23 17:55:21 +00008327 SKIP_BLANKS;
8328 }
Owen Taylor3473f882001-02-23 17:55:21 +00008329}
8330
8331/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008333 * @ctxt: the XPath Parser context
8334 *
8335 * [27] UnaryExpr ::= UnionExpr
8336 * | '-' UnaryExpr
8337 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008338 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008339 */
8340
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008341static void
8342xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008343 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008344 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008345
8346 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008347 while (CUR == '-') {
8348 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008349 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008350 NEXT;
8351 SKIP_BLANKS;
8352 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008353
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008354 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008355 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008356 if (found) {
8357 if (minus)
8358 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8359 else
8360 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008361 }
8362}
8363
8364/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008365 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008366 * @ctxt: the XPath Parser context
8367 *
8368 * [26] MultiplicativeExpr ::= UnaryExpr
8369 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8370 * | MultiplicativeExpr 'div' UnaryExpr
8371 * | MultiplicativeExpr 'mod' UnaryExpr
8372 * [34] MultiplyOperator ::= '*'
8373 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008374 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008375 */
8376
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008377static void
8378xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8379 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008380 CHECK_ERROR;
8381 SKIP_BLANKS;
8382 while ((CUR == '*') ||
8383 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8384 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8385 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008386 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008387
8388 if (CUR == '*') {
8389 op = 0;
8390 NEXT;
8391 } else if (CUR == 'd') {
8392 op = 1;
8393 SKIP(3);
8394 } else if (CUR == 'm') {
8395 op = 2;
8396 SKIP(3);
8397 }
8398 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008399 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008400 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008401 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008402 SKIP_BLANKS;
8403 }
8404}
8405
8406/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008407 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008408 * @ctxt: the XPath Parser context
8409 *
8410 * [25] AdditiveExpr ::= MultiplicativeExpr
8411 * | AdditiveExpr '+' MultiplicativeExpr
8412 * | AdditiveExpr '-' MultiplicativeExpr
8413 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008414 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008415 */
8416
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008417static void
8418xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008419
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008420 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008421 CHECK_ERROR;
8422 SKIP_BLANKS;
8423 while ((CUR == '+') || (CUR == '-')) {
8424 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008425 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008426
8427 if (CUR == '+') plus = 1;
8428 else plus = 0;
8429 NEXT;
8430 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008431 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008432 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008433 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008434 SKIP_BLANKS;
8435 }
8436}
8437
8438/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008439 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008440 * @ctxt: the XPath Parser context
8441 *
8442 * [24] RelationalExpr ::= AdditiveExpr
8443 * | RelationalExpr '<' AdditiveExpr
8444 * | RelationalExpr '>' AdditiveExpr
8445 * | RelationalExpr '<=' AdditiveExpr
8446 * | RelationalExpr '>=' AdditiveExpr
8447 *
8448 * A <= B > C is allowed ? Answer from James, yes with
8449 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8450 * which is basically what got implemented.
8451 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008452 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008453 * on the stack
8454 */
8455
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008456static void
8457xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8458 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008459 CHECK_ERROR;
8460 SKIP_BLANKS;
8461 while ((CUR == '<') ||
8462 (CUR == '>') ||
8463 ((CUR == '<') && (NXT(1) == '=')) ||
8464 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008465 int inf, strict;
8466 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008467
8468 if (CUR == '<') inf = 1;
8469 else inf = 0;
8470 if (NXT(1) == '=') strict = 0;
8471 else strict = 1;
8472 NEXT;
8473 if (!strict) NEXT;
8474 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008475 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008476 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008477 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008478 SKIP_BLANKS;
8479 }
8480}
8481
8482/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008483 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008484 * @ctxt: the XPath Parser context
8485 *
8486 * [23] EqualityExpr ::= RelationalExpr
8487 * | EqualityExpr '=' RelationalExpr
8488 * | EqualityExpr '!=' RelationalExpr
8489 *
8490 * A != B != C is allowed ? Answer from James, yes with
8491 * (RelationalExpr = RelationalExpr) = RelationalExpr
8492 * (RelationalExpr != RelationalExpr) != RelationalExpr
8493 * which is basically what got implemented.
8494 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008495 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008496 *
8497 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008498static void
8499xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8500 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008501 CHECK_ERROR;
8502 SKIP_BLANKS;
8503 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008504 int eq;
8505 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008506
8507 if (CUR == '=') eq = 1;
8508 else eq = 0;
8509 NEXT;
8510 if (!eq) NEXT;
8511 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008512 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008513 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008514 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008515 SKIP_BLANKS;
8516 }
8517}
8518
8519/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008520 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008521 * @ctxt: the XPath Parser context
8522 *
8523 * [22] AndExpr ::= EqualityExpr
8524 * | AndExpr 'and' EqualityExpr
8525 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008526 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008527 *
8528 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008529static void
8530xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8531 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008532 CHECK_ERROR;
8533 SKIP_BLANKS;
8534 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008535 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008536 SKIP(3);
8537 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008538 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008539 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008540 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008541 SKIP_BLANKS;
8542 }
8543}
8544
8545/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008546 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008547 * @ctxt: the XPath Parser context
8548 *
8549 * [14] Expr ::= OrExpr
8550 * [21] OrExpr ::= AndExpr
8551 * | OrExpr 'or' AndExpr
8552 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008553 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008554 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008555static void
8556xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8557 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008558 CHECK_ERROR;
8559 SKIP_BLANKS;
8560 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008561 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008562 SKIP(2);
8563 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008564 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008565 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008566 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8567 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008568 SKIP_BLANKS;
8569 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008570 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8571 /* more ops could be optimized too */
8572 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8573 }
Owen Taylor3473f882001-02-23 17:55:21 +00008574}
8575
8576/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008577 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008578 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008579 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008580 *
8581 * [8] Predicate ::= '[' PredicateExpr ']'
8582 * [9] PredicateExpr ::= Expr
8583 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008584 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008585 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008586static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008587xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008588 int op1 = ctxt->comp->last;
8589
8590 SKIP_BLANKS;
8591 if (CUR != '[') {
8592 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8593 }
8594 NEXT;
8595 SKIP_BLANKS;
8596
8597 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008598 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008599 CHECK_ERROR;
8600
8601 if (CUR != ']') {
8602 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8603 }
8604
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008605 if (filter)
8606 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8607 else
8608 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008609
8610 NEXT;
8611 SKIP_BLANKS;
8612}
8613
8614/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008615 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008616 * @ctxt: the XPath Parser context
8617 * @test: pointer to a xmlXPathTestVal
8618 * @type: pointer to a xmlXPathTypeVal
8619 * @prefix: placeholder for a possible name prefix
8620 *
8621 * [7] NodeTest ::= NameTest
8622 * | NodeType '(' ')'
8623 * | 'processing-instruction' '(' Literal ')'
8624 *
8625 * [37] NameTest ::= '*'
8626 * | NCName ':' '*'
8627 * | QName
8628 * [38] NodeType ::= 'comment'
8629 * | 'text'
8630 * | 'processing-instruction'
8631 * | 'node'
8632 *
William M. Brack08171912003-12-29 02:52:11 +00008633 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008634 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008635static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008636xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8637 xmlXPathTypeVal *type, const xmlChar **prefix,
8638 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008639 int blanks;
8640
8641 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8642 STRANGE;
8643 return(NULL);
8644 }
William M. Brack78637da2003-07-31 14:47:38 +00008645 *type = (xmlXPathTypeVal) 0;
8646 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008647 *prefix = NULL;
8648 SKIP_BLANKS;
8649
8650 if ((name == NULL) && (CUR == '*')) {
8651 /*
8652 * All elements
8653 */
8654 NEXT;
8655 *test = NODE_TEST_ALL;
8656 return(NULL);
8657 }
8658
8659 if (name == NULL)
8660 name = xmlXPathParseNCName(ctxt);
8661 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008662 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008663 }
8664
William M. Brack76e95df2003-10-18 16:20:14 +00008665 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008666 SKIP_BLANKS;
8667 if (CUR == '(') {
8668 NEXT;
8669 /*
8670 * NodeType or PI search
8671 */
8672 if (xmlStrEqual(name, BAD_CAST "comment"))
8673 *type = NODE_TYPE_COMMENT;
8674 else if (xmlStrEqual(name, BAD_CAST "node"))
8675 *type = NODE_TYPE_NODE;
8676 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8677 *type = NODE_TYPE_PI;
8678 else if (xmlStrEqual(name, BAD_CAST "text"))
8679 *type = NODE_TYPE_TEXT;
8680 else {
8681 if (name != NULL)
8682 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00008683 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008684 }
8685
8686 *test = NODE_TEST_TYPE;
8687
8688 SKIP_BLANKS;
8689 if (*type == NODE_TYPE_PI) {
8690 /*
8691 * Specific case: search a PI by name.
8692 */
Owen Taylor3473f882001-02-23 17:55:21 +00008693 if (name != NULL)
8694 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008695 name = NULL;
8696 if (CUR != ')') {
8697 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +00008698 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008699 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008700 SKIP_BLANKS;
8701 }
Owen Taylor3473f882001-02-23 17:55:21 +00008702 }
8703 if (CUR != ')') {
8704 if (name != NULL)
8705 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00008706 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008707 }
8708 NEXT;
8709 return(name);
8710 }
8711 *test = NODE_TEST_NAME;
8712 if ((!blanks) && (CUR == ':')) {
8713 NEXT;
8714
8715 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008716 * Since currently the parser context don't have a
8717 * namespace list associated:
8718 * The namespace name for this prefix can be computed
8719 * only at evaluation time. The compilation is done
8720 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008721 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008722#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008723 *prefix = xmlXPathNsLookup(ctxt->context, name);
8724 if (name != NULL)
8725 xmlFree(name);
8726 if (*prefix == NULL) {
8727 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8728 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008729#else
8730 *prefix = name;
8731#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008732
8733 if (CUR == '*') {
8734 /*
8735 * All elements
8736 */
8737 NEXT;
8738 *test = NODE_TEST_ALL;
8739 return(NULL);
8740 }
8741
8742 name = xmlXPathParseNCName(ctxt);
8743 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008744 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008745 }
8746 }
8747 return(name);
8748}
8749
8750/**
8751 * xmlXPathIsAxisName:
8752 * @name: a preparsed name token
8753 *
8754 * [6] AxisName ::= 'ancestor'
8755 * | 'ancestor-or-self'
8756 * | 'attribute'
8757 * | 'child'
8758 * | 'descendant'
8759 * | 'descendant-or-self'
8760 * | 'following'
8761 * | 'following-sibling'
8762 * | 'namespace'
8763 * | 'parent'
8764 * | 'preceding'
8765 * | 'preceding-sibling'
8766 * | 'self'
8767 *
8768 * Returns the axis or 0
8769 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008770static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008771xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008772 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008773 switch (name[0]) {
8774 case 'a':
8775 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8776 ret = AXIS_ANCESTOR;
8777 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8778 ret = AXIS_ANCESTOR_OR_SELF;
8779 if (xmlStrEqual(name, BAD_CAST "attribute"))
8780 ret = AXIS_ATTRIBUTE;
8781 break;
8782 case 'c':
8783 if (xmlStrEqual(name, BAD_CAST "child"))
8784 ret = AXIS_CHILD;
8785 break;
8786 case 'd':
8787 if (xmlStrEqual(name, BAD_CAST "descendant"))
8788 ret = AXIS_DESCENDANT;
8789 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8790 ret = AXIS_DESCENDANT_OR_SELF;
8791 break;
8792 case 'f':
8793 if (xmlStrEqual(name, BAD_CAST "following"))
8794 ret = AXIS_FOLLOWING;
8795 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8796 ret = AXIS_FOLLOWING_SIBLING;
8797 break;
8798 case 'n':
8799 if (xmlStrEqual(name, BAD_CAST "namespace"))
8800 ret = AXIS_NAMESPACE;
8801 break;
8802 case 'p':
8803 if (xmlStrEqual(name, BAD_CAST "parent"))
8804 ret = AXIS_PARENT;
8805 if (xmlStrEqual(name, BAD_CAST "preceding"))
8806 ret = AXIS_PRECEDING;
8807 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8808 ret = AXIS_PRECEDING_SIBLING;
8809 break;
8810 case 's':
8811 if (xmlStrEqual(name, BAD_CAST "self"))
8812 ret = AXIS_SELF;
8813 break;
8814 }
8815 return(ret);
8816}
8817
8818/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008819 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008820 * @ctxt: the XPath Parser context
8821 *
8822 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8823 * | AbbreviatedStep
8824 *
8825 * [12] AbbreviatedStep ::= '.' | '..'
8826 *
8827 * [5] AxisSpecifier ::= AxisName '::'
8828 * | AbbreviatedAxisSpecifier
8829 *
8830 * [13] AbbreviatedAxisSpecifier ::= '@'?
8831 *
8832 * Modified for XPtr range support as:
8833 *
8834 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8835 * | AbbreviatedStep
8836 * | 'range-to' '(' Expr ')' Predicate*
8837 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008838 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008839 * A location step of . is short for self::node(). This is
8840 * particularly useful in conjunction with //. For example, the
8841 * location path .//para is short for
8842 * self::node()/descendant-or-self::node()/child::para
8843 * and so will select all para descendant elements of the context
8844 * node.
8845 * Similarly, a location step of .. is short for parent::node().
8846 * For example, ../title is short for parent::node()/child::title
8847 * and so will select the title children of the parent of the context
8848 * node.
8849 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008850static void
8851xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008852#ifdef LIBXML_XPTR_ENABLED
8853 int rangeto = 0;
8854 int op2 = -1;
8855#endif
8856
Owen Taylor3473f882001-02-23 17:55:21 +00008857 SKIP_BLANKS;
8858 if ((CUR == '.') && (NXT(1) == '.')) {
8859 SKIP(2);
8860 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008861 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8862 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008863 } else if (CUR == '.') {
8864 NEXT;
8865 SKIP_BLANKS;
8866 } else {
8867 xmlChar *name = NULL;
8868 const xmlChar *prefix = NULL;
8869 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008870 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008871 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008872 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008873
8874 /*
8875 * The modification needed for XPointer change to the production
8876 */
8877#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008878 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008879 name = xmlXPathParseNCName(ctxt);
8880 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008881 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008882 xmlFree(name);
8883 SKIP_BLANKS;
8884 if (CUR != '(') {
8885 XP_ERROR(XPATH_EXPR_ERROR);
8886 }
8887 NEXT;
8888 SKIP_BLANKS;
8889
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008890 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008891 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008892 CHECK_ERROR;
8893
8894 SKIP_BLANKS;
8895 if (CUR != ')') {
8896 XP_ERROR(XPATH_EXPR_ERROR);
8897 }
8898 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008899 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008900 goto eval_predicates;
8901 }
8902 }
8903#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008904 if (CUR == '*') {
8905 axis = AXIS_CHILD;
8906 } else {
8907 if (name == NULL)
8908 name = xmlXPathParseNCName(ctxt);
8909 if (name != NULL) {
8910 axis = xmlXPathIsAxisName(name);
8911 if (axis != 0) {
8912 SKIP_BLANKS;
8913 if ((CUR == ':') && (NXT(1) == ':')) {
8914 SKIP(2);
8915 xmlFree(name);
8916 name = NULL;
8917 } else {
8918 /* an element name can conflict with an axis one :-\ */
8919 axis = AXIS_CHILD;
8920 }
Owen Taylor3473f882001-02-23 17:55:21 +00008921 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008922 axis = AXIS_CHILD;
8923 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008924 } else if (CUR == '@') {
8925 NEXT;
8926 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008927 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008928 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008929 }
Owen Taylor3473f882001-02-23 17:55:21 +00008930 }
8931
8932 CHECK_ERROR;
8933
Daniel Veillard8bda20f2005-08-24 09:36:47 +00008934 type = (xmlXPathTypeVal) 0;
8935 test = (xmlXPathTestVal) 0;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008936 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008937 if (test == 0)
8938 return;
8939
Daniel Veillarded6c5492005-07-23 15:00:22 +00008940 if ((prefix != NULL) && (ctxt->context != NULL) &&
8941 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
8942 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
8943 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
8944 }
8945 }
Owen Taylor3473f882001-02-23 17:55:21 +00008946#ifdef DEBUG_STEP
8947 xmlGenericError(xmlGenericErrorContext,
8948 "Basis : computing new set\n");
8949#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008950
Owen Taylor3473f882001-02-23 17:55:21 +00008951#ifdef DEBUG_STEP
8952 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008953 if (ctxt->value == NULL)
8954 xmlGenericError(xmlGenericErrorContext, "no value\n");
8955 else if (ctxt->value->nodesetval == NULL)
8956 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8957 else
8958 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008959#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008960
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008961#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008962eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008963#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008964 op1 = ctxt->comp->last;
8965 ctxt->comp->last = -1;
8966
Owen Taylor3473f882001-02-23 17:55:21 +00008967 SKIP_BLANKS;
8968 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008969 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008970 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008971
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008972#ifdef LIBXML_XPTR_ENABLED
8973 if (rangeto) {
8974 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8975 } else
8976#endif
8977 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8978 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008979
Owen Taylor3473f882001-02-23 17:55:21 +00008980 }
8981#ifdef DEBUG_STEP
8982 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008983 if (ctxt->value == NULL)
8984 xmlGenericError(xmlGenericErrorContext, "no value\n");
8985 else if (ctxt->value->nodesetval == NULL)
8986 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8987 else
8988 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8989 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008990#endif
8991}
8992
8993/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008994 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008995 * @ctxt: the XPath Parser context
8996 *
8997 * [3] RelativeLocationPath ::= Step
8998 * | RelativeLocationPath '/' Step
8999 * | AbbreviatedRelativeLocationPath
9000 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
9001 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009002 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00009003 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009004static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009005xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00009006(xmlXPathParserContextPtr ctxt) {
9007 SKIP_BLANKS;
9008 if ((CUR == '/') && (NXT(1) == '/')) {
9009 SKIP(2);
9010 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009011 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9012 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009013 } else if (CUR == '/') {
9014 NEXT;
9015 SKIP_BLANKS;
9016 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009017 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009018 SKIP_BLANKS;
9019 while (CUR == '/') {
9020 if ((CUR == '/') && (NXT(1) == '/')) {
9021 SKIP(2);
9022 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009023 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009024 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009025 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009026 } else if (CUR == '/') {
9027 NEXT;
9028 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009029 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009030 }
9031 SKIP_BLANKS;
9032 }
9033}
9034
9035/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009036 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009037 * @ctxt: the XPath Parser context
9038 *
9039 * [1] LocationPath ::= RelativeLocationPath
9040 * | AbsoluteLocationPath
9041 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9042 * | AbbreviatedAbsoluteLocationPath
9043 * [10] AbbreviatedAbsoluteLocationPath ::=
9044 * '//' RelativeLocationPath
9045 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009046 * Compile a location path
9047 *
Owen Taylor3473f882001-02-23 17:55:21 +00009048 * // is short for /descendant-or-self::node()/. For example,
9049 * //para is short for /descendant-or-self::node()/child::para and
9050 * so will select any para element in the document (even a para element
9051 * that is a document element will be selected by //para since the
9052 * document element node is a child of the root node); div//para is
9053 * short for div/descendant-or-self::node()/child::para and so will
9054 * select all para descendants of div children.
9055 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009056static void
9057xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009058 SKIP_BLANKS;
9059 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009060 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009061 } else {
9062 while (CUR == '/') {
9063 if ((CUR == '/') && (NXT(1) == '/')) {
9064 SKIP(2);
9065 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009066 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9067 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009068 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009069 } else if (CUR == '/') {
9070 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009071 SKIP_BLANKS;
9072 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009073 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009074 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009075 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009076 }
9077 }
9078 }
9079}
9080
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009081/************************************************************************
9082 * *
9083 * XPath precompiled expression evaluation *
9084 * *
9085 ************************************************************************/
9086
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9089
9090/**
9091 * xmlXPathNodeCollectAndTest:
9092 * @ctxt: the XPath Parser context
9093 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 * @first: pointer to the first element in document order
9095 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009096 *
9097 * This is the function implementing a step: based on the current list
9098 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009099 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100 *
9101 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009102 *
William M. Brack08171912003-12-29 02:52:11 +00009103 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009106xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009107 xmlXPathStepOpPtr op,
9108 xmlNodePtr * first, xmlNodePtr * last)
9109{
William M. Brack78637da2003-07-31 14:47:38 +00009110 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9111 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9112 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113 const xmlChar *prefix = op->value4;
9114 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009115 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009116
9117#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121 xmlNodeSetPtr ret, list;
9122 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009123 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009124 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125 xmlNodePtr cur = NULL;
9126 xmlXPathObjectPtr obj;
9127 xmlNodeSetPtr nodelist;
9128 xmlNodePtr tmp;
9129
Daniel Veillardf06307e2001-07-03 10:35:50 +00009130 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009131 obj = valuePop(ctxt);
9132 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009133 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009134 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009135 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009136 if (URI == NULL) {
9137 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009139 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009140 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009143#endif
9144 switch (axis) {
9145 case AXIS_ANCESTOR:
9146#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009148#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009149 first = NULL;
9150 next = xmlXPathNextAncestor;
9151 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009152 case AXIS_ANCESTOR_OR_SELF:
9153#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009154 xmlGenericError(xmlGenericErrorContext,
9155 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 first = NULL;
9158 next = xmlXPathNextAncestorOrSelf;
9159 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009160 case AXIS_ATTRIBUTE:
9161#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009163#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009164 first = NULL;
9165 last = NULL;
9166 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009167 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009168 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009169 case AXIS_CHILD:
9170#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009171 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009172#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009173 last = NULL;
9174 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009175 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009177 case AXIS_DESCENDANT:
9178#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009179 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009180#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 last = NULL;
9182 next = xmlXPathNextDescendant;
9183 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009184 case AXIS_DESCENDANT_OR_SELF:
9185#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009186 xmlGenericError(xmlGenericErrorContext,
9187 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009188#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009189 last = NULL;
9190 next = xmlXPathNextDescendantOrSelf;
9191 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009192 case AXIS_FOLLOWING:
9193#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009194 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009195#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009196 last = NULL;
9197 next = xmlXPathNextFollowing;
9198 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009199 case AXIS_FOLLOWING_SIBLING:
9200#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009201 xmlGenericError(xmlGenericErrorContext,
9202 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009203#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009204 last = NULL;
9205 next = xmlXPathNextFollowingSibling;
9206 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009207 case AXIS_NAMESPACE:
9208#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009209 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009210#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009211 first = NULL;
9212 last = NULL;
9213 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009214 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009216 case AXIS_PARENT:
9217#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009218 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 first = NULL;
9221 next = xmlXPathNextParent;
9222 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009223 case AXIS_PRECEDING:
9224#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009225 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009226#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009227 first = NULL;
9228 next = xmlXPathNextPrecedingInternal;
9229 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009230 case AXIS_PRECEDING_SIBLING:
9231#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009232 xmlGenericError(xmlGenericErrorContext,
9233 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009234#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 first = NULL;
9236 next = xmlXPathNextPrecedingSibling;
9237 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009238 case AXIS_SELF:
9239#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009241#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009242 first = NULL;
9243 last = NULL;
9244 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009245 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009246 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009247 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009248 if (next == NULL) {
9249 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009250 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009251 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009252
9253 nodelist = obj->nodesetval;
9254 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009255 xmlXPathFreeObject(obj);
9256 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9257 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258 }
9259 addNode = xmlXPathNodeSetAddUnique;
9260 ret = NULL;
9261#ifdef DEBUG_STEP
9262 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009264 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 case NODE_TEST_NONE:
9266 xmlGenericError(xmlGenericErrorContext,
9267 " searching for none !!!\n");
9268 break;
9269 case NODE_TEST_TYPE:
9270 xmlGenericError(xmlGenericErrorContext,
9271 " searching for type %d\n", type);
9272 break;
9273 case NODE_TEST_PI:
9274 xmlGenericError(xmlGenericErrorContext,
9275 " searching for PI !!!\n");
9276 break;
9277 case NODE_TEST_ALL:
9278 xmlGenericError(xmlGenericErrorContext,
9279 " searching for *\n");
9280 break;
9281 case NODE_TEST_NS:
9282 xmlGenericError(xmlGenericErrorContext,
9283 " searching for namespace %s\n",
9284 prefix);
9285 break;
9286 case NODE_TEST_NAME:
9287 xmlGenericError(xmlGenericErrorContext,
9288 " searching for name %s\n", name);
9289 if (prefix != NULL)
9290 xmlGenericError(xmlGenericErrorContext,
9291 " with namespace %s\n", prefix);
9292 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009293 }
9294 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9295#endif
9296 /*
9297 * 2.3 Node Tests
9298 * - For the attribute axis, the principal node type is attribute.
9299 * - For the namespace axis, the principal node type is namespace.
9300 * - For other axes, the principal node type is element.
9301 *
9302 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009303 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009304 * select all element children of the context node
9305 */
9306 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009307 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009308 ctxt->context->node = nodelist->nodeTab[i];
9309
Daniel Veillardf06307e2001-07-03 10:35:50 +00009310 cur = NULL;
9311 list = xmlXPathNodeSetCreate(NULL);
9312 do {
9313 cur = next(ctxt, cur);
9314 if (cur == NULL)
9315 break;
9316 if ((first != NULL) && (*first == cur))
9317 break;
9318 if (((t % 256) == 0) &&
9319 (first != NULL) && (*first != NULL) &&
9320 (xmlXPathCmpNodes(*first, cur) >= 0))
9321 break;
9322 if ((last != NULL) && (*last == cur))
9323 break;
9324 if (((t % 256) == 0) &&
9325 (last != NULL) && (*last != NULL) &&
9326 (xmlXPathCmpNodes(cur, *last) >= 0))
9327 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009328 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009329#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009330 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9331#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009332 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009333 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009334 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009335 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009336 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009337 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009338 if ((cur->type == type) ||
9339 ((type == NODE_TYPE_NODE) &&
9340 ((cur->type == XML_DOCUMENT_NODE) ||
9341 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9342 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009343 (cur->type == XML_NAMESPACE_DECL) ||
9344 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 (cur->type == XML_PI_NODE) ||
9346 (cur->type == XML_COMMENT_NODE) ||
9347 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009348 (cur->type == XML_TEXT_NODE))) ||
9349 ((type == NODE_TYPE_TEXT) &&
9350 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009351#ifdef DEBUG_STEP
9352 n++;
9353#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009354 addNode(list, cur);
9355 }
9356 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009357 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009358 if (cur->type == XML_PI_NODE) {
9359 if ((name != NULL) &&
9360 (!xmlStrEqual(name, cur->name)))
9361 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009362#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009363 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009364#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009365 addNode(list, cur);
9366 }
9367 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009368 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009369 if (axis == AXIS_ATTRIBUTE) {
9370 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009371#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009372 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009373#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009374 addNode(list, cur);
9375 }
9376 } else if (axis == AXIS_NAMESPACE) {
9377 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009378#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009379 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009380#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009381 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9382 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009383 }
9384 } else {
9385 if (cur->type == XML_ELEMENT_NODE) {
9386 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009387#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009388 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009389#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009390 addNode(list, cur);
9391 } else if ((cur->ns != NULL) &&
9392 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009393#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009395#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009396 addNode(list, cur);
9397 }
9398 }
9399 }
9400 break;
9401 case NODE_TEST_NS:{
9402 TODO;
9403 break;
9404 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009405 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 switch (cur->type) {
9407 case XML_ELEMENT_NODE:
9408 if (xmlStrEqual(name, cur->name)) {
9409 if (prefix == NULL) {
9410 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009411#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009412 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009413#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009414 addNode(list, cur);
9415 }
9416 } else {
9417 if ((cur->ns != NULL) &&
9418 (xmlStrEqual(URI,
9419 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009420#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009422#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009423 addNode(list, cur);
9424 }
9425 }
9426 }
9427 break;
9428 case XML_ATTRIBUTE_NODE:{
9429 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009430
Daniel Veillardf06307e2001-07-03 10:35:50 +00009431 if (xmlStrEqual(name, attr->name)) {
9432 if (prefix == NULL) {
9433 if ((attr->ns == NULL) ||
9434 (attr->ns->prefix == NULL)) {
9435#ifdef DEBUG_STEP
9436 n++;
9437#endif
9438 addNode(list,
9439 (xmlNodePtr) attr);
9440 }
9441 } else {
9442 if ((attr->ns != NULL) &&
9443 (xmlStrEqual(URI,
9444 attr->ns->
9445 href))) {
9446#ifdef DEBUG_STEP
9447 n++;
9448#endif
9449 addNode(list,
9450 (xmlNodePtr) attr);
9451 }
9452 }
9453 }
9454 break;
9455 }
9456 case XML_NAMESPACE_DECL:
9457 if (cur->type == XML_NAMESPACE_DECL) {
9458 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009459
Daniel Veillardf06307e2001-07-03 10:35:50 +00009460 if ((ns->prefix != NULL) && (name != NULL)
9461 && (xmlStrEqual(ns->prefix, name))) {
9462#ifdef DEBUG_STEP
9463 n++;
9464#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009465 xmlXPathNodeSetAddNs(list,
9466 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009467 }
9468 }
9469 break;
9470 default:
9471 break;
9472 }
9473 break;
9474 break;
9475 }
9476 } while (cur != NULL);
9477
9478 /*
9479 * If there is some predicate filtering do it now
9480 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009481 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009482 xmlXPathObjectPtr obj2;
9483
9484 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9485 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9486 CHECK_TYPE0(XPATH_NODESET);
9487 obj2 = valuePop(ctxt);
9488 list = obj2->nodesetval;
9489 obj2->nodesetval = NULL;
9490 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009491 if (ctxt->error != XPATH_EXPRESSION_OK) {
9492 xmlXPathFreeObject(obj);
9493 xmlXPathFreeNodeSet(list);
9494 return(0);
9495 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009496 }
9497 if (ret == NULL) {
9498 ret = list;
9499 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009500 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009501 xmlXPathFreeNodeSet(list);
9502 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009503 }
9504 ctxt->context->node = tmp;
9505#ifdef DEBUG_STEP
9506 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009507 "\nExamined %d nodes, found %d nodes at that step\n",
9508 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009509#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009510 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009511 if ((obj->boolval) && (obj->user != NULL)) {
9512 ctxt->value->boolval = 1;
9513 ctxt->value->user = obj->user;
9514 obj->user = NULL;
9515 obj->boolval = 0;
9516 }
9517 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009518 return(t);
9519}
9520
9521/**
9522 * xmlXPathNodeCollectAndTestNth:
9523 * @ctxt: the XPath Parser context
9524 * @op: the XPath precompiled step operation
9525 * @indx: the index to collect
9526 * @first: pointer to the first element in document order
9527 * @last: pointer to the last element in document order
9528 *
9529 * This is the function implementing a step: based on the current list
9530 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009531 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009532 *
9533 * Pushes the new NodeSet resulting from the search.
9534 * Returns the number of node traversed
9535 */
9536static int
9537xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9538 xmlXPathStepOpPtr op, int indx,
9539 xmlNodePtr * first, xmlNodePtr * last)
9540{
William M. Brack78637da2003-07-31 14:47:38 +00009541 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9542 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9543 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009544 const xmlChar *prefix = op->value4;
9545 const xmlChar *name = op->value5;
9546 const xmlChar *URI = NULL;
9547 int n = 0, t = 0;
9548
9549 int i;
9550 xmlNodeSetPtr list;
9551 xmlXPathTraversalFunction next = NULL;
9552 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9553 xmlNodePtr cur = NULL;
9554 xmlXPathObjectPtr obj;
9555 xmlNodeSetPtr nodelist;
9556 xmlNodePtr tmp;
9557
9558 CHECK_TYPE0(XPATH_NODESET);
9559 obj = valuePop(ctxt);
9560 addNode = xmlXPathNodeSetAdd;
9561 if (prefix != NULL) {
9562 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009563 if (URI == NULL) {
9564 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009565 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009566 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009567 }
9568#ifdef DEBUG_STEP_NTH
9569 xmlGenericError(xmlGenericErrorContext, "new step : ");
9570 if (first != NULL) {
9571 if (*first != NULL)
9572 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9573 (*first)->name);
9574 else
9575 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9576 }
9577 if (last != NULL) {
9578 if (*last != NULL)
9579 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9580 (*last)->name);
9581 else
9582 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9583 }
9584#endif
9585 switch (axis) {
9586 case AXIS_ANCESTOR:
9587#ifdef DEBUG_STEP_NTH
9588 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9589#endif
9590 first = NULL;
9591 next = xmlXPathNextAncestor;
9592 break;
9593 case AXIS_ANCESTOR_OR_SELF:
9594#ifdef DEBUG_STEP_NTH
9595 xmlGenericError(xmlGenericErrorContext,
9596 "axis 'ancestors-or-self' ");
9597#endif
9598 first = NULL;
9599 next = xmlXPathNextAncestorOrSelf;
9600 break;
9601 case AXIS_ATTRIBUTE:
9602#ifdef DEBUG_STEP_NTH
9603 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9604#endif
9605 first = NULL;
9606 last = NULL;
9607 next = xmlXPathNextAttribute;
9608 break;
9609 case AXIS_CHILD:
9610#ifdef DEBUG_STEP_NTH
9611 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9612#endif
9613 last = NULL;
9614 next = xmlXPathNextChild;
9615 break;
9616 case AXIS_DESCENDANT:
9617#ifdef DEBUG_STEP_NTH
9618 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9619#endif
9620 last = NULL;
9621 next = xmlXPathNextDescendant;
9622 break;
9623 case AXIS_DESCENDANT_OR_SELF:
9624#ifdef DEBUG_STEP_NTH
9625 xmlGenericError(xmlGenericErrorContext,
9626 "axis 'descendant-or-self' ");
9627#endif
9628 last = NULL;
9629 next = xmlXPathNextDescendantOrSelf;
9630 break;
9631 case AXIS_FOLLOWING:
9632#ifdef DEBUG_STEP_NTH
9633 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9634#endif
9635 last = NULL;
9636 next = xmlXPathNextFollowing;
9637 break;
9638 case AXIS_FOLLOWING_SIBLING:
9639#ifdef DEBUG_STEP_NTH
9640 xmlGenericError(xmlGenericErrorContext,
9641 "axis 'following-siblings' ");
9642#endif
9643 last = NULL;
9644 next = xmlXPathNextFollowingSibling;
9645 break;
9646 case AXIS_NAMESPACE:
9647#ifdef DEBUG_STEP_NTH
9648 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9649#endif
9650 last = NULL;
9651 first = NULL;
9652 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9653 break;
9654 case AXIS_PARENT:
9655#ifdef DEBUG_STEP_NTH
9656 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9657#endif
9658 first = NULL;
9659 next = xmlXPathNextParent;
9660 break;
9661 case AXIS_PRECEDING:
9662#ifdef DEBUG_STEP_NTH
9663 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9664#endif
9665 first = NULL;
9666 next = xmlXPathNextPrecedingInternal;
9667 break;
9668 case AXIS_PRECEDING_SIBLING:
9669#ifdef DEBUG_STEP_NTH
9670 xmlGenericError(xmlGenericErrorContext,
9671 "axis 'preceding-sibling' ");
9672#endif
9673 first = NULL;
9674 next = xmlXPathNextPrecedingSibling;
9675 break;
9676 case AXIS_SELF:
9677#ifdef DEBUG_STEP_NTH
9678 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9679#endif
9680 first = NULL;
9681 last = NULL;
9682 next = xmlXPathNextSelf;
9683 break;
9684 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009685 if (next == NULL) {
9686 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009687 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009688 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009689
9690 nodelist = obj->nodesetval;
9691 if (nodelist == NULL) {
9692 xmlXPathFreeObject(obj);
9693 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9694 return(0);
9695 }
9696 addNode = xmlXPathNodeSetAddUnique;
9697#ifdef DEBUG_STEP_NTH
9698 xmlGenericError(xmlGenericErrorContext,
9699 " context contains %d nodes\n", nodelist->nodeNr);
9700 switch (test) {
9701 case NODE_TEST_NONE:
9702 xmlGenericError(xmlGenericErrorContext,
9703 " searching for none !!!\n");
9704 break;
9705 case NODE_TEST_TYPE:
9706 xmlGenericError(xmlGenericErrorContext,
9707 " searching for type %d\n", type);
9708 break;
9709 case NODE_TEST_PI:
9710 xmlGenericError(xmlGenericErrorContext,
9711 " searching for PI !!!\n");
9712 break;
9713 case NODE_TEST_ALL:
9714 xmlGenericError(xmlGenericErrorContext,
9715 " searching for *\n");
9716 break;
9717 case NODE_TEST_NS:
9718 xmlGenericError(xmlGenericErrorContext,
9719 " searching for namespace %s\n",
9720 prefix);
9721 break;
9722 case NODE_TEST_NAME:
9723 xmlGenericError(xmlGenericErrorContext,
9724 " searching for name %s\n", name);
9725 if (prefix != NULL)
9726 xmlGenericError(xmlGenericErrorContext,
9727 " with namespace %s\n", prefix);
9728 break;
9729 }
9730 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9731#endif
9732 /*
9733 * 2.3 Node Tests
9734 * - For the attribute axis, the principal node type is attribute.
9735 * - For the namespace axis, the principal node type is namespace.
9736 * - For other axes, the principal node type is element.
9737 *
9738 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009739 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009740 * select all element children of the context node
9741 */
9742 tmp = ctxt->context->node;
9743 list = xmlXPathNodeSetCreate(NULL);
9744 for (i = 0; i < nodelist->nodeNr; i++) {
9745 ctxt->context->node = nodelist->nodeTab[i];
9746
9747 cur = NULL;
9748 n = 0;
9749 do {
9750 cur = next(ctxt, cur);
9751 if (cur == NULL)
9752 break;
9753 if ((first != NULL) && (*first == cur))
9754 break;
9755 if (((t % 256) == 0) &&
9756 (first != NULL) && (*first != NULL) &&
9757 (xmlXPathCmpNodes(*first, cur) >= 0))
9758 break;
9759 if ((last != NULL) && (*last == cur))
9760 break;
9761 if (((t % 256) == 0) &&
9762 (last != NULL) && (*last != NULL) &&
9763 (xmlXPathCmpNodes(cur, *last) >= 0))
9764 break;
9765 t++;
9766 switch (test) {
9767 case NODE_TEST_NONE:
9768 ctxt->context->node = tmp;
9769 STRANGE return(0);
9770 case NODE_TEST_TYPE:
9771 if ((cur->type == type) ||
9772 ((type == NODE_TYPE_NODE) &&
9773 ((cur->type == XML_DOCUMENT_NODE) ||
9774 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9775 (cur->type == XML_ELEMENT_NODE) ||
9776 (cur->type == XML_PI_NODE) ||
9777 (cur->type == XML_COMMENT_NODE) ||
9778 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009779 (cur->type == XML_TEXT_NODE))) ||
9780 ((type == NODE_TYPE_TEXT) &&
9781 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009782 n++;
9783 if (n == indx)
9784 addNode(list, cur);
9785 }
9786 break;
9787 case NODE_TEST_PI:
9788 if (cur->type == XML_PI_NODE) {
9789 if ((name != NULL) &&
9790 (!xmlStrEqual(name, cur->name)))
9791 break;
9792 n++;
9793 if (n == indx)
9794 addNode(list, cur);
9795 }
9796 break;
9797 case NODE_TEST_ALL:
9798 if (axis == AXIS_ATTRIBUTE) {
9799 if (cur->type == XML_ATTRIBUTE_NODE) {
9800 n++;
9801 if (n == indx)
9802 addNode(list, cur);
9803 }
9804 } else if (axis == AXIS_NAMESPACE) {
9805 if (cur->type == XML_NAMESPACE_DECL) {
9806 n++;
9807 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009808 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9809 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009810 }
9811 } else {
9812 if (cur->type == XML_ELEMENT_NODE) {
9813 if (prefix == NULL) {
9814 n++;
9815 if (n == indx)
9816 addNode(list, cur);
9817 } else if ((cur->ns != NULL) &&
9818 (xmlStrEqual(URI, cur->ns->href))) {
9819 n++;
9820 if (n == indx)
9821 addNode(list, cur);
9822 }
9823 }
9824 }
9825 break;
9826 case NODE_TEST_NS:{
9827 TODO;
9828 break;
9829 }
9830 case NODE_TEST_NAME:
9831 switch (cur->type) {
9832 case XML_ELEMENT_NODE:
9833 if (xmlStrEqual(name, cur->name)) {
9834 if (prefix == NULL) {
9835 if (cur->ns == NULL) {
9836 n++;
9837 if (n == indx)
9838 addNode(list, cur);
9839 }
9840 } else {
9841 if ((cur->ns != NULL) &&
9842 (xmlStrEqual(URI,
9843 cur->ns->href))) {
9844 n++;
9845 if (n == indx)
9846 addNode(list, cur);
9847 }
9848 }
9849 }
9850 break;
9851 case XML_ATTRIBUTE_NODE:{
9852 xmlAttrPtr attr = (xmlAttrPtr) cur;
9853
9854 if (xmlStrEqual(name, attr->name)) {
9855 if (prefix == NULL) {
9856 if ((attr->ns == NULL) ||
9857 (attr->ns->prefix == NULL)) {
9858 n++;
9859 if (n == indx)
9860 addNode(list, cur);
9861 }
9862 } else {
9863 if ((attr->ns != NULL) &&
9864 (xmlStrEqual(URI,
9865 attr->ns->
9866 href))) {
9867 n++;
9868 if (n == indx)
9869 addNode(list, cur);
9870 }
9871 }
9872 }
9873 break;
9874 }
9875 case XML_NAMESPACE_DECL:
9876 if (cur->type == XML_NAMESPACE_DECL) {
9877 xmlNsPtr ns = (xmlNsPtr) cur;
9878
9879 if ((ns->prefix != NULL) && (name != NULL)
9880 && (xmlStrEqual(ns->prefix, name))) {
9881 n++;
9882 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009883 xmlXPathNodeSetAddNs(list,
9884 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009885 }
9886 }
9887 break;
9888 default:
9889 break;
9890 }
9891 break;
9892 break;
9893 }
9894 } while (n < indx);
9895 }
9896 ctxt->context->node = tmp;
9897#ifdef DEBUG_STEP_NTH
9898 xmlGenericError(xmlGenericErrorContext,
9899 "\nExamined %d nodes, found %d nodes at that step\n",
9900 t, list->nodeNr);
9901#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009902 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009903 if ((obj->boolval) && (obj->user != NULL)) {
9904 ctxt->value->boolval = 1;
9905 ctxt->value->user = obj->user;
9906 obj->user = NULL;
9907 obj->boolval = 0;
9908 }
9909 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009910 return(t);
9911}
9912
9913/**
9914 * xmlXPathCompOpEvalFirst:
9915 * @ctxt: the XPath parser context with the compiled expression
9916 * @op: an XPath compiled operation
9917 * @first: the first elem found so far
9918 *
9919 * Evaluate the Precompiled XPath operation searching only the first
9920 * element in document order
9921 *
9922 * Returns the number of examined objects.
9923 */
9924static int
9925xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9926 xmlXPathStepOpPtr op, xmlNodePtr * first)
9927{
9928 int total = 0, cur;
9929 xmlXPathCompExprPtr comp;
9930 xmlXPathObjectPtr arg1, arg2;
9931
Daniel Veillard556c6682001-10-06 09:59:51 +00009932 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009933 comp = ctxt->comp;
9934 switch (op->op) {
9935 case XPATH_OP_END:
9936 return (0);
9937 case XPATH_OP_UNION:
9938 total =
9939 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9940 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009941 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009942 if ((ctxt->value != NULL)
9943 && (ctxt->value->type == XPATH_NODESET)
9944 && (ctxt->value->nodesetval != NULL)
9945 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9946 /*
9947 * limit tree traversing to first node in the result
9948 */
9949 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9950 *first = ctxt->value->nodesetval->nodeTab[0];
9951 }
9952 cur =
9953 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9954 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009955 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009956 CHECK_TYPE0(XPATH_NODESET);
9957 arg2 = valuePop(ctxt);
9958
9959 CHECK_TYPE0(XPATH_NODESET);
9960 arg1 = valuePop(ctxt);
9961
9962 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9963 arg2->nodesetval);
9964 valuePush(ctxt, arg1);
9965 xmlXPathFreeObject(arg2);
9966 /* optimizer */
9967 if (total > cur)
9968 xmlXPathCompSwap(op);
9969 return (total + cur);
9970 case XPATH_OP_ROOT:
9971 xmlXPathRoot(ctxt);
9972 return (0);
9973 case XPATH_OP_NODE:
9974 if (op->ch1 != -1)
9975 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009976 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977 if (op->ch2 != -1)
9978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009979 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9981 return (total);
9982 case XPATH_OP_RESET:
9983 if (op->ch1 != -1)
9984 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009985 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009986 if (op->ch2 != -1)
9987 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009988 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009989 ctxt->context->node = NULL;
9990 return (total);
9991 case XPATH_OP_COLLECT:{
9992 if (op->ch1 == -1)
9993 return (total);
9994
9995 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009996 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009997
9998 /*
9999 * Optimization for [n] selection where n is a number
10000 */
10001 if ((op->ch2 != -1) &&
10002 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10003 (comp->steps[op->ch2].ch1 == -1) &&
10004 (comp->steps[op->ch2].ch2 != -1) &&
10005 (comp->steps[comp->steps[op->ch2].ch2].op ==
10006 XPATH_OP_VALUE)) {
10007 xmlXPathObjectPtr val;
10008
10009 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10010 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10011 int indx = (int) val->floatval;
10012
10013 if (val->floatval == (float) indx) {
10014 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
10015 first, NULL);
10016 return (total);
10017 }
10018 }
10019 }
10020 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10021 return (total);
10022 }
10023 case XPATH_OP_VALUE:
10024 valuePush(ctxt,
10025 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10026 return (0);
10027 case XPATH_OP_SORT:
10028 if (op->ch1 != -1)
10029 total +=
10030 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10031 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010032 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 if ((ctxt->value != NULL)
10034 && (ctxt->value->type == XPATH_NODESET)
10035 && (ctxt->value->nodesetval != NULL))
10036 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10037 return (total);
10038 default:
10039 return (xmlXPathCompOpEval(ctxt, op));
10040 }
10041}
10042
10043/**
10044 * xmlXPathCompOpEvalLast:
10045 * @ctxt: the XPath parser context with the compiled expression
10046 * @op: an XPath compiled operation
10047 * @last: the last elem found so far
10048 *
10049 * Evaluate the Precompiled XPath operation searching only the last
10050 * element in document order
10051 *
William M. Brack08171912003-12-29 02:52:11 +000010052 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010053 */
10054static int
10055xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10056 xmlNodePtr * last)
10057{
10058 int total = 0, cur;
10059 xmlXPathCompExprPtr comp;
10060 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010061 xmlNodePtr bak;
10062 xmlDocPtr bakd;
10063 int pp;
10064 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010065
Daniel Veillard556c6682001-10-06 09:59:51 +000010066 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010067 comp = ctxt->comp;
10068 switch (op->op) {
10069 case XPATH_OP_END:
10070 return (0);
10071 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010072 bakd = ctxt->context->doc;
10073 bak = ctxt->context->node;
10074 pp = ctxt->context->proximityPosition;
10075 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010076 total =
10077 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010078 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 if ((ctxt->value != NULL)
10080 && (ctxt->value->type == XPATH_NODESET)
10081 && (ctxt->value->nodesetval != NULL)
10082 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10083 /*
10084 * limit tree traversing to first node in the result
10085 */
10086 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10087 *last =
10088 ctxt->value->nodesetval->nodeTab[ctxt->value->
10089 nodesetval->nodeNr -
10090 1];
10091 }
William M. Brackce4fc562004-01-22 02:47:18 +000010092 ctxt->context->doc = bakd;
10093 ctxt->context->node = bak;
10094 ctxt->context->proximityPosition = pp;
10095 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 cur =
10097 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010098 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010099 if ((ctxt->value != NULL)
10100 && (ctxt->value->type == XPATH_NODESET)
10101 && (ctxt->value->nodesetval != NULL)
10102 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10103 }
10104 CHECK_TYPE0(XPATH_NODESET);
10105 arg2 = valuePop(ctxt);
10106
10107 CHECK_TYPE0(XPATH_NODESET);
10108 arg1 = valuePop(ctxt);
10109
10110 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10111 arg2->nodesetval);
10112 valuePush(ctxt, arg1);
10113 xmlXPathFreeObject(arg2);
10114 /* optimizer */
10115 if (total > cur)
10116 xmlXPathCompSwap(op);
10117 return (total + cur);
10118 case XPATH_OP_ROOT:
10119 xmlXPathRoot(ctxt);
10120 return (0);
10121 case XPATH_OP_NODE:
10122 if (op->ch1 != -1)
10123 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010124 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125 if (op->ch2 != -1)
10126 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010127 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010128 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10129 return (total);
10130 case XPATH_OP_RESET:
10131 if (op->ch1 != -1)
10132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010133 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010134 if (op->ch2 != -1)
10135 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010136 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 ctxt->context->node = NULL;
10138 return (total);
10139 case XPATH_OP_COLLECT:{
10140 if (op->ch1 == -1)
10141 return (0);
10142
10143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010144 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010145
10146 /*
10147 * Optimization for [n] selection where n is a number
10148 */
10149 if ((op->ch2 != -1) &&
10150 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10151 (comp->steps[op->ch2].ch1 == -1) &&
10152 (comp->steps[op->ch2].ch2 != -1) &&
10153 (comp->steps[comp->steps[op->ch2].ch2].op ==
10154 XPATH_OP_VALUE)) {
10155 xmlXPathObjectPtr val;
10156
10157 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10158 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10159 int indx = (int) val->floatval;
10160
10161 if (val->floatval == (float) indx) {
10162 total +=
10163 xmlXPathNodeCollectAndTestNth(ctxt, op,
10164 indx, NULL,
10165 last);
10166 return (total);
10167 }
10168 }
10169 }
10170 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10171 return (total);
10172 }
10173 case XPATH_OP_VALUE:
10174 valuePush(ctxt,
10175 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10176 return (0);
10177 case XPATH_OP_SORT:
10178 if (op->ch1 != -1)
10179 total +=
10180 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10181 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010182 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 if ((ctxt->value != NULL)
10184 && (ctxt->value->type == XPATH_NODESET)
10185 && (ctxt->value->nodesetval != NULL))
10186 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10187 return (total);
10188 default:
10189 return (xmlXPathCompOpEval(ctxt, op));
10190 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010191}
10192
Owen Taylor3473f882001-02-23 17:55:21 +000010193/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010194 * xmlXPathCompOpEval:
10195 * @ctxt: the XPath parser context with the compiled expression
10196 * @op: an XPath compiled operation
10197 *
10198 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010199 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010200 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010201static int
10202xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10203{
10204 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010205 int equal, ret;
10206 xmlXPathCompExprPtr comp;
10207 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010208 xmlNodePtr bak;
10209 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010210 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010211 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010212
Daniel Veillard556c6682001-10-06 09:59:51 +000010213 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010214 comp = ctxt->comp;
10215 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010216 case XPATH_OP_END:
10217 return (0);
10218 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010219 bakd = ctxt->context->doc;
10220 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010221 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010222 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010223 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010224 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010225 xmlXPathBooleanFunction(ctxt, 1);
10226 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10227 return (total);
10228 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010229 ctxt->context->doc = bakd;
10230 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010231 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010232 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010233 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010234 if (ctxt->error) {
10235 xmlXPathFreeObject(arg2);
10236 return(0);
10237 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 xmlXPathBooleanFunction(ctxt, 1);
10239 arg1 = valuePop(ctxt);
10240 arg1->boolval &= arg2->boolval;
10241 valuePush(ctxt, arg1);
10242 xmlXPathFreeObject(arg2);
10243 return (total);
10244 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010245 bakd = ctxt->context->doc;
10246 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010247 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010248 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010249 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010250 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010251 xmlXPathBooleanFunction(ctxt, 1);
10252 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10253 return (total);
10254 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010255 ctxt->context->doc = bakd;
10256 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010257 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010258 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010259 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010260 if (ctxt->error) {
10261 xmlXPathFreeObject(arg2);
10262 return(0);
10263 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 xmlXPathBooleanFunction(ctxt, 1);
10265 arg1 = valuePop(ctxt);
10266 arg1->boolval |= arg2->boolval;
10267 valuePush(ctxt, arg1);
10268 xmlXPathFreeObject(arg2);
10269 return (total);
10270 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010271 bakd = ctxt->context->doc;
10272 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010273 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010274 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010276 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010277 ctxt->context->doc = bakd;
10278 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010279 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010280 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010281 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010282 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010283 if (op->value)
10284 equal = xmlXPathEqualValues(ctxt);
10285 else
10286 equal = xmlXPathNotEqualValues(ctxt);
10287 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010288 return (total);
10289 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010290 bakd = ctxt->context->doc;
10291 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010292 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010293 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010295 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010296 ctxt->context->doc = bakd;
10297 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010298 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010299 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010301 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010302 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10303 valuePush(ctxt, xmlXPathNewBoolean(ret));
10304 return (total);
10305 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010306 bakd = ctxt->context->doc;
10307 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010308 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010309 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010311 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010312 if (op->ch2 != -1) {
10313 ctxt->context->doc = bakd;
10314 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010315 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010316 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010318 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010319 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010320 if (op->value == 0)
10321 xmlXPathSubValues(ctxt);
10322 else if (op->value == 1)
10323 xmlXPathAddValues(ctxt);
10324 else if (op->value == 2)
10325 xmlXPathValueFlipSign(ctxt);
10326 else if (op->value == 3) {
10327 CAST_TO_NUMBER;
10328 CHECK_TYPE0(XPATH_NUMBER);
10329 }
10330 return (total);
10331 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010332 bakd = ctxt->context->doc;
10333 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010334 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010335 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010337 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010338 ctxt->context->doc = bakd;
10339 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010340 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010341 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010343 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010344 if (op->value == 0)
10345 xmlXPathMultValues(ctxt);
10346 else if (op->value == 1)
10347 xmlXPathDivValues(ctxt);
10348 else if (op->value == 2)
10349 xmlXPathModValues(ctxt);
10350 return (total);
10351 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010352 bakd = ctxt->context->doc;
10353 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010354 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010355 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010357 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010358 ctxt->context->doc = bakd;
10359 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010360 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010361 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010362 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
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);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010366
Daniel Veillardf06307e2001-07-03 10:35:50 +000010367 CHECK_TYPE0(XPATH_NODESET);
10368 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010369
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10371 arg2->nodesetval);
10372 valuePush(ctxt, arg1);
10373 xmlXPathFreeObject(arg2);
10374 return (total);
10375 case XPATH_OP_ROOT:
10376 xmlXPathRoot(ctxt);
10377 return (total);
10378 case XPATH_OP_NODE:
10379 if (op->ch1 != -1)
10380 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010381 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010382 if (op->ch2 != -1)
10383 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010384 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010385 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10386 return (total);
10387 case XPATH_OP_RESET:
10388 if (op->ch1 != -1)
10389 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010390 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010391 if (op->ch2 != -1)
10392 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010393 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 ctxt->context->node = NULL;
10395 return (total);
10396 case XPATH_OP_COLLECT:{
10397 if (op->ch1 == -1)
10398 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010399
Daniel Veillardf06307e2001-07-03 10:35:50 +000010400 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010401 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010402
Daniel Veillardf06307e2001-07-03 10:35:50 +000010403 /*
10404 * Optimization for [n] selection where n is a number
10405 */
10406 if ((op->ch2 != -1) &&
10407 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10408 (comp->steps[op->ch2].ch1 == -1) &&
10409 (comp->steps[op->ch2].ch2 != -1) &&
10410 (comp->steps[comp->steps[op->ch2].ch2].op ==
10411 XPATH_OP_VALUE)) {
10412 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010413
Daniel Veillardf06307e2001-07-03 10:35:50 +000010414 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10415 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10416 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010417
Daniel Veillardf06307e2001-07-03 10:35:50 +000010418 if (val->floatval == (float) indx) {
10419 total +=
10420 xmlXPathNodeCollectAndTestNth(ctxt, op,
10421 indx, NULL,
10422 NULL);
10423 return (total);
10424 }
10425 }
10426 }
10427 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10428 return (total);
10429 }
10430 case XPATH_OP_VALUE:
10431 valuePush(ctxt,
10432 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10433 return (total);
10434 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010435 xmlXPathObjectPtr val;
10436
Daniel Veillardf06307e2001-07-03 10:35:50 +000010437 if (op->ch1 != -1)
10438 total +=
10439 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010440 if (op->value5 == NULL) {
10441 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10442 if (val == NULL) {
10443 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10444 return(0);
10445 }
10446 valuePush(ctxt, val);
10447 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010448 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010449
Daniel Veillardf06307e2001-07-03 10:35:50 +000010450 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10451 if (URI == NULL) {
10452 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010453 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010454 op->value4, op->value5);
10455 return (total);
10456 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010457 val = xmlXPathVariableLookupNS(ctxt->context,
10458 op->value4, URI);
10459 if (val == NULL) {
10460 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10461 return(0);
10462 }
10463 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010464 }
10465 return (total);
10466 }
10467 case XPATH_OP_FUNCTION:{
10468 xmlXPathFunction func;
10469 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010470 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010471
10472 if (op->ch1 != -1)
10473 total +=
10474 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010475 if (ctxt->valueNr < op->value) {
10476 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010477 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010478 ctxt->error = XPATH_INVALID_OPERAND;
10479 return (total);
10480 }
10481 for (i = 0; i < op->value; i++)
10482 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10483 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010484 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010485 ctxt->error = XPATH_INVALID_OPERAND;
10486 return (total);
10487 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010488 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010489 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010490 else {
10491 const xmlChar *URI = NULL;
10492
10493 if (op->value5 == NULL)
10494 func =
10495 xmlXPathFunctionLookup(ctxt->context,
10496 op->value4);
10497 else {
10498 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10499 if (URI == NULL) {
10500 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010501 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010502 op->value4, op->value5);
10503 return (total);
10504 }
10505 func = xmlXPathFunctionLookupNS(ctxt->context,
10506 op->value4, URI);
10507 }
10508 if (func == NULL) {
10509 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010510 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 op->value4);
10512 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010513 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010514 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010515 op->cacheURI = (void *) URI;
10516 }
10517 oldFunc = ctxt->context->function;
10518 oldFuncURI = ctxt->context->functionURI;
10519 ctxt->context->function = op->value4;
10520 ctxt->context->functionURI = op->cacheURI;
10521 func(ctxt, op->value);
10522 ctxt->context->function = oldFunc;
10523 ctxt->context->functionURI = oldFuncURI;
10524 return (total);
10525 }
10526 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010527 bakd = ctxt->context->doc;
10528 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010529 pp = ctxt->context->proximityPosition;
10530 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010531 if (op->ch1 != -1)
10532 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010533 ctxt->context->contextSize = cs;
10534 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010535 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010536 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010537 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010538 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010539 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010540 ctxt->context->doc = bakd;
10541 ctxt->context->node = bak;
10542 CHECK_ERROR0;
10543 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010544 return (total);
10545 case XPATH_OP_PREDICATE:
10546 case XPATH_OP_FILTER:{
10547 xmlXPathObjectPtr res;
10548 xmlXPathObjectPtr obj, tmp;
10549 xmlNodeSetPtr newset = NULL;
10550 xmlNodeSetPtr oldset;
10551 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010552 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010553 int i;
10554
10555 /*
10556 * Optimization for ()[1] selection i.e. the first elem
10557 */
10558 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10559 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10560 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10561 xmlXPathObjectPtr val;
10562
10563 val = comp->steps[op->ch2].value4;
10564 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10565 (val->floatval == 1.0)) {
10566 xmlNodePtr first = NULL;
10567
10568 total +=
10569 xmlXPathCompOpEvalFirst(ctxt,
10570 &comp->steps[op->ch1],
10571 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010572 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010573 /*
10574 * The nodeset should be in document order,
10575 * Keep only the first value
10576 */
10577 if ((ctxt->value != NULL) &&
10578 (ctxt->value->type == XPATH_NODESET) &&
10579 (ctxt->value->nodesetval != NULL) &&
10580 (ctxt->value->nodesetval->nodeNr > 1))
10581 ctxt->value->nodesetval->nodeNr = 1;
10582 return (total);
10583 }
10584 }
10585 /*
10586 * Optimization for ()[last()] selection i.e. the last elem
10587 */
10588 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10589 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10590 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10591 int f = comp->steps[op->ch2].ch1;
10592
10593 if ((f != -1) &&
10594 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10595 (comp->steps[f].value5 == NULL) &&
10596 (comp->steps[f].value == 0) &&
10597 (comp->steps[f].value4 != NULL) &&
10598 (xmlStrEqual
10599 (comp->steps[f].value4, BAD_CAST "last"))) {
10600 xmlNodePtr last = NULL;
10601
10602 total +=
10603 xmlXPathCompOpEvalLast(ctxt,
10604 &comp->steps[op->ch1],
10605 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010606 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010607 /*
10608 * The nodeset should be in document order,
10609 * Keep only the last value
10610 */
10611 if ((ctxt->value != NULL) &&
10612 (ctxt->value->type == XPATH_NODESET) &&
10613 (ctxt->value->nodesetval != NULL) &&
10614 (ctxt->value->nodesetval->nodeTab != NULL) &&
10615 (ctxt->value->nodesetval->nodeNr > 1)) {
10616 ctxt->value->nodesetval->nodeTab[0] =
10617 ctxt->value->nodesetval->nodeTab[ctxt->
10618 value->
10619 nodesetval->
10620 nodeNr -
10621 1];
10622 ctxt->value->nodesetval->nodeNr = 1;
10623 }
10624 return (total);
10625 }
10626 }
10627
10628 if (op->ch1 != -1)
10629 total +=
10630 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010631 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010632 if (op->ch2 == -1)
10633 return (total);
10634 if (ctxt->value == NULL)
10635 return (total);
10636
10637 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010638
10639#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010640 /*
10641 * Hum are we filtering the result of an XPointer expression
10642 */
10643 if (ctxt->value->type == XPATH_LOCATIONSET) {
10644 xmlLocationSetPtr newlocset = NULL;
10645 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010646
Daniel Veillardf06307e2001-07-03 10:35:50 +000010647 /*
10648 * Extract the old locset, and then evaluate the result of the
10649 * expression for all the element in the locset. use it to grow
10650 * up a new locset.
10651 */
10652 CHECK_TYPE0(XPATH_LOCATIONSET);
10653 obj = valuePop(ctxt);
10654 oldlocset = obj->user;
10655 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010656
Daniel Veillardf06307e2001-07-03 10:35:50 +000010657 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10658 ctxt->context->contextSize = 0;
10659 ctxt->context->proximityPosition = 0;
10660 if (op->ch2 != -1)
10661 total +=
10662 xmlXPathCompOpEval(ctxt,
10663 &comp->steps[op->ch2]);
10664 res = valuePop(ctxt);
10665 if (res != NULL)
10666 xmlXPathFreeObject(res);
10667 valuePush(ctxt, obj);
10668 CHECK_ERROR0;
10669 return (total);
10670 }
10671 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010672
Daniel Veillardf06307e2001-07-03 10:35:50 +000010673 for (i = 0; i < oldlocset->locNr; i++) {
10674 /*
10675 * Run the evaluation with a node list made of a
10676 * single item in the nodelocset.
10677 */
10678 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010679 ctxt->context->contextSize = oldlocset->locNr;
10680 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010681 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10682 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 if (op->ch2 != -1)
10685 total +=
10686 xmlXPathCompOpEval(ctxt,
10687 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010688 if (ctxt->error != XPATH_EXPRESSION_OK) {
10689 xmlXPathFreeObject(obj);
10690 return(0);
10691 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010692
Daniel Veillardf06307e2001-07-03 10:35:50 +000010693 /*
10694 * The result of the evaluation need to be tested to
10695 * decided whether the filter succeeded or not
10696 */
10697 res = valuePop(ctxt);
10698 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10699 xmlXPtrLocationSetAdd(newlocset,
10700 xmlXPathObjectCopy
10701 (oldlocset->locTab[i]));
10702 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010703
Daniel Veillardf06307e2001-07-03 10:35:50 +000010704 /*
10705 * Cleanup
10706 */
10707 if (res != NULL)
10708 xmlXPathFreeObject(res);
10709 if (ctxt->value == tmp) {
10710 res = valuePop(ctxt);
10711 xmlXPathFreeObject(res);
10712 }
10713
10714 ctxt->context->node = NULL;
10715 }
10716
10717 /*
10718 * The result is used as the new evaluation locset.
10719 */
10720 xmlXPathFreeObject(obj);
10721 ctxt->context->node = NULL;
10722 ctxt->context->contextSize = -1;
10723 ctxt->context->proximityPosition = -1;
10724 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10725 ctxt->context->node = oldnode;
10726 return (total);
10727 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010728#endif /* LIBXML_XPTR_ENABLED */
10729
Daniel Veillardf06307e2001-07-03 10:35:50 +000010730 /*
10731 * Extract the old set, and then evaluate the result of the
10732 * expression for all the element in the set. use it to grow
10733 * up a new set.
10734 */
10735 CHECK_TYPE0(XPATH_NODESET);
10736 obj = valuePop(ctxt);
10737 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010738
Daniel Veillardf06307e2001-07-03 10:35:50 +000010739 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010740 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010741 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010742
Daniel Veillardf06307e2001-07-03 10:35:50 +000010743 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10744 ctxt->context->contextSize = 0;
10745 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010746/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 if (op->ch2 != -1)
10748 total +=
10749 xmlXPathCompOpEval(ctxt,
10750 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010751 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010752 res = valuePop(ctxt);
10753 if (res != NULL)
10754 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010755*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010756 valuePush(ctxt, obj);
10757 ctxt->context->node = oldnode;
10758 CHECK_ERROR0;
10759 } else {
10760 /*
10761 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010762 * Also set the xpath document in case things like
10763 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010764 */
10765 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010766
Daniel Veillardf06307e2001-07-03 10:35:50 +000010767 for (i = 0; i < oldset->nodeNr; i++) {
10768 /*
10769 * Run the evaluation with a node list made of
10770 * a single item in the nodeset.
10771 */
10772 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010773 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10774 (oldset->nodeTab[i]->doc != NULL))
10775 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010776 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10777 valuePush(ctxt, tmp);
10778 ctxt->context->contextSize = oldset->nodeNr;
10779 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010780
Daniel Veillardf06307e2001-07-03 10:35:50 +000010781 if (op->ch2 != -1)
10782 total +=
10783 xmlXPathCompOpEval(ctxt,
10784 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010785 if (ctxt->error != XPATH_EXPRESSION_OK) {
10786 xmlXPathFreeNodeSet(newset);
10787 xmlXPathFreeObject(obj);
10788 return(0);
10789 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010790
Daniel Veillardf06307e2001-07-03 10:35:50 +000010791 /*
William M. Brack08171912003-12-29 02:52:11 +000010792 * The result of the evaluation needs to be tested to
10793 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010794 */
10795 res = valuePop(ctxt);
10796 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10797 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10798 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010799
Daniel Veillardf06307e2001-07-03 10:35:50 +000010800 /*
10801 * Cleanup
10802 */
10803 if (res != NULL)
10804 xmlXPathFreeObject(res);
10805 if (ctxt->value == tmp) {
10806 res = valuePop(ctxt);
10807 xmlXPathFreeObject(res);
10808 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010809
Daniel Veillardf06307e2001-07-03 10:35:50 +000010810 ctxt->context->node = NULL;
10811 }
10812
10813 /*
10814 * The result is used as the new evaluation set.
10815 */
10816 xmlXPathFreeObject(obj);
10817 ctxt->context->node = NULL;
10818 ctxt->context->contextSize = -1;
10819 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010820 /* may want to move this past the '}' later */
10821 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010822 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10823 }
10824 ctxt->context->node = oldnode;
10825 return (total);
10826 }
10827 case XPATH_OP_SORT:
10828 if (op->ch1 != -1)
10829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010830 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010831 if ((ctxt->value != NULL) &&
10832 (ctxt->value->type == XPATH_NODESET) &&
10833 (ctxt->value->nodesetval != NULL))
10834 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10835 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010836#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010837 case XPATH_OP_RANGETO:{
10838 xmlXPathObjectPtr range;
10839 xmlXPathObjectPtr res, obj;
10840 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010841 xmlLocationSetPtr newlocset = NULL;
10842 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010843 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010844 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010845
Daniel Veillardf06307e2001-07-03 10:35:50 +000010846 if (op->ch1 != -1)
10847 total +=
10848 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10849 if (op->ch2 == -1)
10850 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010851
William M. Brack08171912003-12-29 02:52:11 +000010852 if (ctxt->value->type == XPATH_LOCATIONSET) {
10853 /*
10854 * Extract the old locset, and then evaluate the result of the
10855 * expression for all the element in the locset. use it to grow
10856 * up a new locset.
10857 */
10858 CHECK_TYPE0(XPATH_LOCATIONSET);
10859 obj = valuePop(ctxt);
10860 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010861
William M. Brack08171912003-12-29 02:52:11 +000010862 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010863 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010864 ctxt->context->contextSize = 0;
10865 ctxt->context->proximityPosition = 0;
10866 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10867 res = valuePop(ctxt);
10868 if (res != NULL)
10869 xmlXPathFreeObject(res);
10870 valuePush(ctxt, obj);
10871 CHECK_ERROR0;
10872 return (total);
10873 }
10874 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010875
William M. Brack08171912003-12-29 02:52:11 +000010876 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010877 /*
William M. Brack08171912003-12-29 02:52:11 +000010878 * Run the evaluation with a node list made of a
10879 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010880 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010881 ctxt->context->node = oldlocset->locTab[i]->user;
10882 ctxt->context->contextSize = oldlocset->locNr;
10883 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010884 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10885 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010886
Daniel Veillardf06307e2001-07-03 10:35:50 +000010887 if (op->ch2 != -1)
10888 total +=
10889 xmlXPathCompOpEval(ctxt,
10890 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010891 if (ctxt->error != XPATH_EXPRESSION_OK) {
10892 xmlXPathFreeObject(obj);
10893 return(0);
10894 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010895
Daniel Veillardf06307e2001-07-03 10:35:50 +000010896 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010897 if (res->type == XPATH_LOCATIONSET) {
10898 xmlLocationSetPtr rloc =
10899 (xmlLocationSetPtr)res->user;
10900 for (j=0; j<rloc->locNr; j++) {
10901 range = xmlXPtrNewRange(
10902 oldlocset->locTab[i]->user,
10903 oldlocset->locTab[i]->index,
10904 rloc->locTab[j]->user2,
10905 rloc->locTab[j]->index2);
10906 if (range != NULL) {
10907 xmlXPtrLocationSetAdd(newlocset, range);
10908 }
10909 }
10910 } else {
10911 range = xmlXPtrNewRangeNodeObject(
10912 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10913 if (range != NULL) {
10914 xmlXPtrLocationSetAdd(newlocset,range);
10915 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010916 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010917
Daniel Veillardf06307e2001-07-03 10:35:50 +000010918 /*
10919 * Cleanup
10920 */
10921 if (res != NULL)
10922 xmlXPathFreeObject(res);
10923 if (ctxt->value == tmp) {
10924 res = valuePop(ctxt);
10925 xmlXPathFreeObject(res);
10926 }
10927
10928 ctxt->context->node = NULL;
10929 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010930 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010931 CHECK_TYPE0(XPATH_NODESET);
10932 obj = valuePop(ctxt);
10933 oldset = obj->nodesetval;
10934 ctxt->context->node = NULL;
10935
10936 newlocset = xmlXPtrLocationSetCreate(NULL);
10937
10938 if (oldset != NULL) {
10939 for (i = 0; i < oldset->nodeNr; i++) {
10940 /*
10941 * Run the evaluation with a node list made of a single item
10942 * in the nodeset.
10943 */
10944 ctxt->context->node = oldset->nodeTab[i];
10945 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10946 valuePush(ctxt, tmp);
10947
10948 if (op->ch2 != -1)
10949 total +=
10950 xmlXPathCompOpEval(ctxt,
10951 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010952 if (ctxt->error != XPATH_EXPRESSION_OK) {
10953 xmlXPathFreeObject(obj);
10954 return(0);
10955 }
William M. Brack08171912003-12-29 02:52:11 +000010956
William M. Brack08171912003-12-29 02:52:11 +000010957 res = valuePop(ctxt);
10958 range =
10959 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10960 res);
10961 if (range != NULL) {
10962 xmlXPtrLocationSetAdd(newlocset, range);
10963 }
10964
10965 /*
10966 * Cleanup
10967 */
10968 if (res != NULL)
10969 xmlXPathFreeObject(res);
10970 if (ctxt->value == tmp) {
10971 res = valuePop(ctxt);
10972 xmlXPathFreeObject(res);
10973 }
10974
10975 ctxt->context->node = NULL;
10976 }
10977 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010978 }
10979
10980 /*
10981 * The result is used as the new evaluation set.
10982 */
10983 xmlXPathFreeObject(obj);
10984 ctxt->context->node = NULL;
10985 ctxt->context->contextSize = -1;
10986 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010987 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010988 return (total);
10989 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010990#endif /* LIBXML_XPTR_ENABLED */
10991 }
10992 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010993 "XPath: unknown precompiled operation %d\n", op->op);
10994 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010995}
10996
Daniel Veillard56de87e2005-02-16 00:22:29 +000010997#ifdef XPATH_STREAMING
10998/**
10999 * xmlXPathRunStreamEval:
11000 * @ctxt: the XPath parser context with the compiled expression
11001 *
11002 * Evaluate the Precompiled Streamable XPath expression in the given context.
11003 */
11004static xmlXPathObjectPtr
11005xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
11006 int max_depth;
11007 int from_root;
11008 int ret, depth;
William M. Brack12d37ab2005-02-21 13:54:07 +000011009 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011010 xmlXPathObjectPtr retval;
11011 xmlStreamCtxtPtr patstream;
11012
11013 int nb_nodes = 0;
11014
11015 if ((ctxt == NULL) || (comp == NULL))
11016 return(NULL);
11017 max_depth = xmlPatternMaxDepth(comp);
11018 if (max_depth == -1)
11019 return(NULL);
11020 if (max_depth == -2)
11021 max_depth = 10000;
11022 from_root = xmlPatternFromRoot(comp);
11023 if (from_root < 0)
11024 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011025#if 0
11026 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11027#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011028
11029 retval = xmlXPathNewNodeSet(NULL);
11030 if (retval == NULL)
11031 return(NULL);
11032
Daniel Veillard56de87e2005-02-16 00:22:29 +000011033 if ((from_root) && (max_depth == 0)) {
11034 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11035 return(retval);
11036 } else if (max_depth == 0) {
11037 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11038 return(retval);
11039 }
11040 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011041 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011042 } else if (ctxt->node != NULL) {
11043 switch (ctxt->node->type) {
11044 case XML_ELEMENT_NODE:
11045 case XML_DOCUMENT_NODE:
11046 case XML_DOCUMENT_FRAG_NODE:
11047 case XML_HTML_DOCUMENT_NODE:
11048#ifdef LIBXML_DOCB_ENABLED
11049 case XML_DOCB_DOCUMENT_NODE:
11050#endif
11051 cur = ctxt->node;
11052 break;
11053 case XML_ATTRIBUTE_NODE:
11054 case XML_TEXT_NODE:
11055 case XML_CDATA_SECTION_NODE:
11056 case XML_ENTITY_REF_NODE:
11057 case XML_ENTITY_NODE:
11058 case XML_PI_NODE:
11059 case XML_COMMENT_NODE:
11060 case XML_NOTATION_NODE:
11061 case XML_DTD_NODE:
11062 case XML_DOCUMENT_TYPE_NODE:
11063 case XML_ELEMENT_DECL:
11064 case XML_ATTRIBUTE_DECL:
11065 case XML_ENTITY_DECL:
11066 case XML_NAMESPACE_DECL:
11067 case XML_XINCLUDE_START:
11068 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011069 break;
11070 }
11071 limit = cur;
11072 }
11073 if (cur == NULL)
11074 return(retval);
11075
11076 patstream = xmlPatternGetStreamCtxt(comp);
11077 if (patstream == NULL) {
11078 return(retval);
11079 }
11080
11081 if (from_root) {
11082 ret = xmlStreamPush(patstream, NULL, NULL);
11083 if (ret < 0) {
11084 } else if (ret == 1) {
11085 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11086 }
11087 }
11088
11089 depth = 0;
11090 goto scan_children;
11091 do {
11092next_node:
11093 nb_nodes++;
11094 if (cur->type == XML_ELEMENT_NODE) {
11095 ret = xmlStreamPush(patstream, cur->name,
11096 (cur->ns ? cur->ns->href : NULL));
11097 if (ret < 0) {
11098 } else if (ret == 1) {
11099 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11100 }
11101 if ((cur->children == NULL) || (depth >= max_depth)) {
11102 ret = xmlStreamPop(patstream);
William M. Brackfbb619f2005-06-06 13:49:18 +000011103 while (cur->next != NULL) {
11104 cur = cur->next;
11105 if ((cur->type != XML_ENTITY_DECL) &&
11106 (cur->type != XML_DTD_NODE))
11107 goto next_node;
11108 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011109 }
11110 }
11111
11112scan_children:
11113 if ((cur->children != NULL) && (depth < max_depth)) {
11114 /*
11115 * Do not descend on entities declarations
11116 */
11117 if (cur->children->type != XML_ENTITY_DECL) {
11118 cur = cur->children;
11119 depth++;
11120 /*
11121 * Skip DTDs
11122 */
11123 if (cur->type != XML_DTD_NODE)
11124 continue;
11125 }
11126 }
11127
11128 if (cur == limit)
11129 break;
11130
11131 while (cur->next != NULL) {
11132 cur = cur->next;
11133 if ((cur->type != XML_ENTITY_DECL) &&
11134 (cur->type != XML_DTD_NODE))
11135 goto next_node;
11136 }
11137
11138 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011139 cur = cur->parent;
11140 depth--;
11141 if ((cur == NULL) || (cur == limit))
11142 goto done;
William M. Brackfbb619f2005-06-06 13:49:18 +000011143 if (cur->type == XML_ELEMENT_NODE)
11144 ret = xmlStreamPop(patstream);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011145 if (cur->next != NULL) {
11146 cur = cur->next;
11147 break;
11148 }
11149 } while (cur != NULL);
11150
11151 } while ((cur != NULL) && (depth >= 0));
11152done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011153#if 0
11154 printf("stream eval: checked %d nodes selected %d\n",
11155 nb_nodes, retval->nodesetval->nodeNr);
11156#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011157 xmlFreeStreamCtxt(patstream);
11158 return(retval);
11159}
11160#endif /* XPATH_STREAMING */
11161
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011162/**
11163 * xmlXPathRunEval:
11164 * @ctxt: the XPath parser context with the compiled expression
11165 *
11166 * Evaluate the Precompiled XPath expression in the given context.
11167 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011168static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011169xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11170 xmlXPathCompExprPtr comp;
11171
11172 if ((ctxt == NULL) || (ctxt->comp == NULL))
11173 return;
11174
11175 if (ctxt->valueTab == NULL) {
11176 /* Allocate the value stack */
11177 ctxt->valueTab = (xmlXPathObjectPtr *)
11178 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11179 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011180 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011181 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011182 }
11183 ctxt->valueNr = 0;
11184 ctxt->valueMax = 10;
11185 ctxt->value = NULL;
11186 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011187#ifdef XPATH_STREAMING
11188 if (ctxt->comp->stream) {
11189 xmlXPathObjectPtr ret;
11190 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11191 if (ret != NULL) {
11192 valuePush(ctxt, ret);
11193 return;
11194 }
11195 }
11196#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011197 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011198 if(comp->last < 0) {
11199 xmlGenericError(xmlGenericErrorContext,
11200 "xmlXPathRunEval: last is less than zero\n");
11201 return;
11202 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011203 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11204}
11205
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011206/************************************************************************
11207 * *
11208 * Public interfaces *
11209 * *
11210 ************************************************************************/
11211
11212/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011213 * xmlXPathEvalPredicate:
11214 * @ctxt: the XPath context
11215 * @res: the Predicate Expression evaluation result
11216 *
11217 * Evaluate a predicate result for the current node.
11218 * A PredicateExpr is evaluated by evaluating the Expr and converting
11219 * the result to a boolean. If the result is a number, the result will
11220 * be converted to true if the number is equal to the position of the
11221 * context node in the context node list (as returned by the position
11222 * function) and will be converted to false otherwise; if the result
11223 * is not a number, then the result will be converted as if by a call
11224 * to the boolean function.
11225 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011226 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011227 */
11228int
11229xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011230 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011231 switch (res->type) {
11232 case XPATH_BOOLEAN:
11233 return(res->boolval);
11234 case XPATH_NUMBER:
11235 return(res->floatval == ctxt->proximityPosition);
11236 case XPATH_NODESET:
11237 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011238 if (res->nodesetval == NULL)
11239 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011240 return(res->nodesetval->nodeNr != 0);
11241 case XPATH_STRING:
11242 return((res->stringval != NULL) &&
11243 (xmlStrlen(res->stringval) != 0));
11244 default:
11245 STRANGE
11246 }
11247 return(0);
11248}
11249
11250/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011251 * xmlXPathEvaluatePredicateResult:
11252 * @ctxt: the XPath Parser context
11253 * @res: the Predicate Expression evaluation result
11254 *
11255 * Evaluate a predicate result for the current node.
11256 * A PredicateExpr is evaluated by evaluating the Expr and converting
11257 * the result to a boolean. If the result is a number, the result will
11258 * be converted to true if the number is equal to the position of the
11259 * context node in the context node list (as returned by the position
11260 * function) and will be converted to false otherwise; if the result
11261 * is not a number, then the result will be converted as if by a call
11262 * to the boolean function.
11263 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011264 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011265 */
11266int
11267xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11268 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011269 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011270 switch (res->type) {
11271 case XPATH_BOOLEAN:
11272 return(res->boolval);
11273 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011274#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011275 return((res->floatval == ctxt->context->proximityPosition) &&
11276 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011277#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011278 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011279#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011280 case XPATH_NODESET:
11281 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011282 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011283 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011284 return(res->nodesetval->nodeNr != 0);
11285 case XPATH_STRING:
11286 return((res->stringval != NULL) &&
11287 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011288#ifdef LIBXML_XPTR_ENABLED
11289 case XPATH_LOCATIONSET:{
11290 xmlLocationSetPtr ptr = res->user;
11291 if (ptr == NULL)
11292 return(0);
11293 return (ptr->locNr != 0);
11294 }
11295#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011296 default:
11297 STRANGE
11298 }
11299 return(0);
11300}
11301
Daniel Veillard56de87e2005-02-16 00:22:29 +000011302#ifdef XPATH_STREAMING
11303/**
11304 * xmlXPathTryStreamCompile:
11305 * @ctxt: an XPath context
11306 * @str: the XPath expression
11307 *
11308 * Try to compile the XPath expression as a streamable subset.
11309 *
11310 * Returns the compiled expression or NULL if failed to compile.
11311 */
11312static xmlXPathCompExprPtr
11313xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11314 /*
11315 * Optimization: use streaming patterns when the XPath expression can
11316 * be compiled to a stream lookup
11317 */
11318 xmlPatternPtr stream;
11319 xmlXPathCompExprPtr comp;
11320 xmlDictPtr dict = NULL;
11321 const xmlChar **namespaces = NULL;
11322 xmlNsPtr ns;
11323 int i, j;
11324
11325 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11326 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011327 const xmlChar *tmp;
11328
11329 /*
11330 * We don't try to handle :: constructs, just the simplied form at
11331 * this point
11332 */
11333 tmp = xmlStrchr(str, ':');
11334 if ((tmp != NULL) && (tmp[1] == ':'))
11335 return(NULL);
11336
Daniel Veillard56de87e2005-02-16 00:22:29 +000011337 if (ctxt != NULL) {
11338 dict = ctxt->dict;
11339 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000011340 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000011341 if (namespaces == NULL) {
11342 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11343 return(NULL);
11344 }
11345 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11346 ns = ctxt->namespaces[j];
11347 namespaces[i++] = ns->href;
11348 namespaces[i++] = ns->prefix;
11349 }
11350 namespaces[i++] = NULL;
11351 namespaces[i++] = NULL;
11352 }
11353 }
11354
William M. Brackea152c02005-06-09 18:12:28 +000011355 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
11356 &namespaces[0]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011357 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11358 comp = xmlXPathNewCompExpr();
11359 if (comp == NULL) {
11360 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11361 return(NULL);
11362 }
11363 comp->stream = stream;
11364 comp->dict = dict;
11365 if (comp->dict)
11366 xmlDictReference(comp->dict);
11367 return(comp);
11368 }
11369 xmlFreePattern(stream);
11370 }
11371 return(NULL);
11372}
11373#endif /* XPATH_STREAMING */
11374
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011375/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011376 * xmlXPathCtxtCompile:
11377 * @ctxt: an XPath context
11378 * @str: the XPath expression
11379 *
11380 * Compile an XPath expression
11381 *
11382 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11383 * the caller has to free the object.
11384 */
11385xmlXPathCompExprPtr
11386xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11387 xmlXPathParserContextPtr pctxt;
11388 xmlXPathCompExprPtr comp;
11389
Daniel Veillard56de87e2005-02-16 00:22:29 +000011390#ifdef XPATH_STREAMING
11391 comp = xmlXPathTryStreamCompile(ctxt, str);
11392 if (comp != NULL)
11393 return(comp);
11394#endif
11395
Daniel Veillard4773df22004-01-23 13:15:13 +000011396 xmlXPathInit();
11397
11398 pctxt = xmlXPathNewParserContext(str, ctxt);
11399 xmlXPathCompileExpr(pctxt);
11400
11401 if( pctxt->error != XPATH_EXPRESSION_OK )
11402 {
11403 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011404 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000011405 }
11406
11407 if (*pctxt->cur != 0) {
11408 /*
11409 * aleksey: in some cases this line prints *second* error message
11410 * (see bug #78858) and probably this should be fixed.
11411 * However, we are not sure that all error messages are printed
11412 * out in other places. It's not critical so we leave it as-is for now
11413 */
11414 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11415 comp = NULL;
11416 } else {
11417 comp = pctxt->comp;
11418 pctxt->comp = NULL;
11419 }
11420 xmlXPathFreeParserContext(pctxt);
11421 if (comp != NULL) {
11422 comp->expr = xmlStrdup(str);
11423#ifdef DEBUG_EVAL_COUNTS
11424 comp->string = xmlStrdup(str);
11425 comp->nb = 0;
11426#endif
11427 }
11428 return(comp);
11429}
11430
11431/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011432 * xmlXPathCompile:
11433 * @str: the XPath expression
11434 *
11435 * Compile an XPath expression
11436 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011437 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011438 * the caller has to free the object.
11439 */
11440xmlXPathCompExprPtr
11441xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011442 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011443}
11444
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011445/**
11446 * xmlXPathCompiledEval:
11447 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011448 * @ctx: the XPath context
11449 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011450 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011451 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011452 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011453 * the caller has to free the object.
11454 */
11455xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011456xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011457 xmlXPathParserContextPtr ctxt;
11458 xmlXPathObjectPtr res, tmp, init = NULL;
11459 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011460#ifndef LIBXML_THREAD_ENABLED
11461 static int reentance = 0;
11462#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011463
William M. Brackf13f77f2004-11-12 16:03:48 +000011464 CHECK_CTXT(ctx)
11465
11466 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011467 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011468 xmlXPathInit();
11469
Daniel Veillard81463942001-10-16 12:34:39 +000011470#ifndef LIBXML_THREAD_ENABLED
11471 reentance++;
11472 if (reentance > 1)
11473 xmlXPathDisableOptimizer = 1;
11474#endif
11475
Daniel Veillardf06307e2001-07-03 10:35:50 +000011476#ifdef DEBUG_EVAL_COUNTS
11477 comp->nb++;
11478 if ((comp->string != NULL) && (comp->nb > 100)) {
11479 fprintf(stderr, "100 x %s\n", comp->string);
11480 comp->nb = 0;
11481 }
11482#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011483 ctxt = xmlXPathCompParserContext(comp, ctx);
11484 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011485
11486 if (ctxt->value == NULL) {
11487 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011488 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011489 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011490 } else {
11491 res = valuePop(ctxt);
11492 }
11493
Daniel Veillardf06307e2001-07-03 10:35:50 +000011494
Owen Taylor3473f882001-02-23 17:55:21 +000011495 do {
11496 tmp = valuePop(ctxt);
11497 if (tmp != NULL) {
11498 if (tmp != init)
11499 stack++;
11500 xmlXPathFreeObject(tmp);
11501 }
11502 } while (tmp != NULL);
11503 if ((stack != 0) && (res != NULL)) {
11504 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011505 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011506 stack);
11507 }
11508 if (ctxt->error != XPATH_EXPRESSION_OK) {
11509 xmlXPathFreeObject(res);
11510 res = NULL;
11511 }
11512
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011513
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011514 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011515 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011516#ifndef LIBXML_THREAD_ENABLED
11517 reentance--;
11518#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011519 return(res);
11520}
11521
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011522/**
11523 * xmlXPathEvalExpr:
11524 * @ctxt: the XPath Parser context
11525 *
11526 * Parse and evaluate an XPath expression in the given context,
11527 * then push the result on the context stack
11528 */
11529void
11530xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011531#ifdef XPATH_STREAMING
11532 xmlXPathCompExprPtr comp;
11533#endif
11534
Daniel Veillarda82b1822004-11-08 16:24:57 +000011535 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011536
11537#ifdef XPATH_STREAMING
11538 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11539 if (comp != NULL) {
11540 if (ctxt->comp != NULL)
11541 xmlXPathFreeCompExpr(ctxt->comp);
11542 ctxt->comp = comp;
11543 if (ctxt->cur != NULL)
11544 while (*ctxt->cur != 0) ctxt->cur++;
11545 } else
11546#endif
11547 {
11548 xmlXPathCompileExpr(ctxt);
11549 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011550 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011551 xmlXPathRunEval(ctxt);
11552}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011553
11554/**
11555 * xmlXPathEval:
11556 * @str: the XPath expression
11557 * @ctx: the XPath context
11558 *
11559 * Evaluate the XPath Location Path in the given context.
11560 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011561 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011562 * the caller has to free the object.
11563 */
11564xmlXPathObjectPtr
11565xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11566 xmlXPathParserContextPtr ctxt;
11567 xmlXPathObjectPtr res, tmp, init = NULL;
11568 int stack = 0;
11569
William M. Brackf13f77f2004-11-12 16:03:48 +000011570 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011571
William M. Brackf13f77f2004-11-12 16:03:48 +000011572 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011573
11574 ctxt = xmlXPathNewParserContext(str, ctx);
11575 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011576
11577 if (ctxt->value == NULL) {
11578 xmlGenericError(xmlGenericErrorContext,
11579 "xmlXPathEval: evaluation failed\n");
11580 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011581 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11582#ifdef XPATH_STREAMING
11583 && (ctxt->comp->stream == NULL)
11584#endif
11585 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011586 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11587 res = NULL;
11588 } else {
11589 res = valuePop(ctxt);
11590 }
11591
11592 do {
11593 tmp = valuePop(ctxt);
11594 if (tmp != NULL) {
11595 if (tmp != init)
11596 stack++;
11597 xmlXPathFreeObject(tmp);
11598 }
11599 } while (tmp != NULL);
11600 if ((stack != 0) && (res != NULL)) {
11601 xmlGenericError(xmlGenericErrorContext,
11602 "xmlXPathEval: %d object left on the stack\n",
11603 stack);
11604 }
11605 if (ctxt->error != XPATH_EXPRESSION_OK) {
11606 xmlXPathFreeObject(res);
11607 res = NULL;
11608 }
11609
Owen Taylor3473f882001-02-23 17:55:21 +000011610 xmlXPathFreeParserContext(ctxt);
11611 return(res);
11612}
11613
11614/**
11615 * xmlXPathEvalExpression:
11616 * @str: the XPath expression
11617 * @ctxt: the XPath context
11618 *
11619 * Evaluate the XPath expression in the given context.
11620 *
11621 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11622 * the caller has to free the object.
11623 */
11624xmlXPathObjectPtr
11625xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11626 xmlXPathParserContextPtr pctxt;
11627 xmlXPathObjectPtr res, tmp;
11628 int stack = 0;
11629
William M. Brackf13f77f2004-11-12 16:03:48 +000011630 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011631
William M. Brackf13f77f2004-11-12 16:03:48 +000011632 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011633
11634 pctxt = xmlXPathNewParserContext(str, ctxt);
11635 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011636
11637 if (*pctxt->cur != 0) {
11638 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11639 res = NULL;
11640 } else {
11641 res = valuePop(pctxt);
11642 }
11643 do {
11644 tmp = valuePop(pctxt);
11645 if (tmp != NULL) {
11646 xmlXPathFreeObject(tmp);
11647 stack++;
11648 }
11649 } while (tmp != NULL);
11650 if ((stack != 0) && (res != NULL)) {
11651 xmlGenericError(xmlGenericErrorContext,
11652 "xmlXPathEvalExpression: %d object left on the stack\n",
11653 stack);
11654 }
11655 xmlXPathFreeParserContext(pctxt);
11656 return(res);
11657}
11658
Daniel Veillard42766c02002-08-22 20:52:17 +000011659/************************************************************************
11660 * *
11661 * Extra functions not pertaining to the XPath spec *
11662 * *
11663 ************************************************************************/
11664/**
11665 * xmlXPathEscapeUriFunction:
11666 * @ctxt: the XPath Parser context
11667 * @nargs: the number of arguments
11668 *
11669 * Implement the escape-uri() XPath function
11670 * string escape-uri(string $str, bool $escape-reserved)
11671 *
11672 * This function applies the URI escaping rules defined in section 2 of [RFC
11673 * 2396] to the string supplied as $uri-part, which typically represents all
11674 * or part of a URI. The effect of the function is to replace any special
11675 * character in the string by an escape sequence of the form %xx%yy...,
11676 * where xxyy... is the hexadecimal representation of the octets used to
11677 * represent the character in UTF-8.
11678 *
11679 * The set of characters that are escaped depends on the setting of the
11680 * boolean argument $escape-reserved.
11681 *
11682 * If $escape-reserved is true, all characters are escaped other than lower
11683 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11684 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11685 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11686 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11687 * A-F).
11688 *
11689 * If $escape-reserved is false, the behavior differs in that characters
11690 * referred to in [RFC 2396] as reserved characters are not escaped. These
11691 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11692 *
11693 * [RFC 2396] does not define whether escaped URIs should use lower case or
11694 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11695 * compared using string comparison functions, this function must always use
11696 * the upper-case letters A-F.
11697 *
11698 * Generally, $escape-reserved should be set to true when escaping a string
11699 * that is to form a single part of a URI, and to false when escaping an
11700 * entire URI or URI reference.
11701 *
11702 * In the case of non-ascii characters, the string is encoded according to
11703 * utf-8 and then converted according to RFC 2396.
11704 *
11705 * Examples
11706 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11707 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11708 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11709 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11710 *
11711 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011712static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011713xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11714 xmlXPathObjectPtr str;
11715 int escape_reserved;
11716 xmlBufferPtr target;
11717 xmlChar *cptr;
11718 xmlChar escape[4];
11719
11720 CHECK_ARITY(2);
11721
11722 escape_reserved = xmlXPathPopBoolean(ctxt);
11723
11724 CAST_TO_STRING;
11725 str = valuePop(ctxt);
11726
11727 target = xmlBufferCreate();
11728
11729 escape[0] = '%';
11730 escape[3] = 0;
11731
11732 if (target) {
11733 for (cptr = str->stringval; *cptr; cptr++) {
11734 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11735 (*cptr >= 'a' && *cptr <= 'z') ||
11736 (*cptr >= '0' && *cptr <= '9') ||
11737 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11738 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11739 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11740 (*cptr == '%' &&
11741 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11742 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11743 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11744 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11745 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11746 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11747 (!escape_reserved &&
11748 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11749 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11750 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11751 *cptr == ','))) {
11752 xmlBufferAdd(target, cptr, 1);
11753 } else {
11754 if ((*cptr >> 4) < 10)
11755 escape[1] = '0' + (*cptr >> 4);
11756 else
11757 escape[1] = 'A' - 10 + (*cptr >> 4);
11758 if ((*cptr & 0xF) < 10)
11759 escape[2] = '0' + (*cptr & 0xF);
11760 else
11761 escape[2] = 'A' - 10 + (*cptr & 0xF);
11762
11763 xmlBufferAdd(target, &escape[0], 3);
11764 }
11765 }
11766 }
11767 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11768 xmlBufferFree(target);
11769 xmlXPathFreeObject(str);
11770}
11771
Owen Taylor3473f882001-02-23 17:55:21 +000011772/**
11773 * xmlXPathRegisterAllFunctions:
11774 * @ctxt: the XPath context
11775 *
11776 * Registers all default XPath functions in this context
11777 */
11778void
11779xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11780{
11781 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11782 xmlXPathBooleanFunction);
11783 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11784 xmlXPathCeilingFunction);
11785 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11786 xmlXPathCountFunction);
11787 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11788 xmlXPathConcatFunction);
11789 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11790 xmlXPathContainsFunction);
11791 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11792 xmlXPathIdFunction);
11793 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11794 xmlXPathFalseFunction);
11795 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11796 xmlXPathFloorFunction);
11797 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11798 xmlXPathLastFunction);
11799 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11800 xmlXPathLangFunction);
11801 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11802 xmlXPathLocalNameFunction);
11803 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11804 xmlXPathNotFunction);
11805 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11806 xmlXPathNameFunction);
11807 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11808 xmlXPathNamespaceURIFunction);
11809 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11810 xmlXPathNormalizeFunction);
11811 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11812 xmlXPathNumberFunction);
11813 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11814 xmlXPathPositionFunction);
11815 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11816 xmlXPathRoundFunction);
11817 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11818 xmlXPathStringFunction);
11819 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11820 xmlXPathStringLengthFunction);
11821 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11822 xmlXPathStartsWithFunction);
11823 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11824 xmlXPathSubstringFunction);
11825 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11826 xmlXPathSubstringBeforeFunction);
11827 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11828 xmlXPathSubstringAfterFunction);
11829 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11830 xmlXPathSumFunction);
11831 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11832 xmlXPathTrueFunction);
11833 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11834 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011835
11836 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11837 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11838 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011839}
11840
11841#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000011842#define bottom_xpath
11843#include "elfgcchack.h"