blob: f57ba8c8eac648715fa6cd050db9773e4e095e27 [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;
Daniel Veillardb3d14912005-09-04 20:47:39 +00001403 int value = (int) number;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001404
1405 ptr = &buffer[0];
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001406 if (value == 0) {
1407 *ptr++ = '0';
1408 } else {
Daniel Veillardb3d14912005-09-04 20:47:39 +00001409 snprintf(work, 29, "%d", value);
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001410 cur = &work[0];
Daniel Veillardb3d14912005-09-04 20:47:39 +00001411 while ((*cur) && (ptr - buffer < buffersize)) {
1412 *ptr++ = *cur++;
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001413 }
1414 }
1415 if (ptr - buffer < buffersize) {
1416 *ptr = 0;
1417 } else if (buffersize > 0) {
1418 ptr--;
1419 *ptr = 0;
1420 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001421 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001422 /* 3 is sign, decimal point, and terminating zero */
1423 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1424 int integer_place, fraction_place;
1425 char *ptr;
1426 char *after_fraction;
1427 double absolute_value;
1428 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001429
Bjorn Reese70a9da52001-04-21 16:57:29 +00001430 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001431
Bjorn Reese70a9da52001-04-21 16:57:29 +00001432 /*
1433 * First choose format - scientific or regular floating point.
1434 * In either case, result is in work, and after_fraction points
1435 * just past the fractional part.
1436 */
1437 if ( ((absolute_value > UPPER_DOUBLE) ||
1438 (absolute_value < LOWER_DOUBLE)) &&
1439 (absolute_value != 0.0) ) {
1440 /* Use scientific notation */
1441 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1442 fraction_place = DBL_DIG - 1;
1443 snprintf(work, sizeof(work),"%*.*e",
1444 integer_place, fraction_place, number);
1445 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001446 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001447 else {
1448 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001449 if (absolute_value > 0.0)
1450 integer_place = 1 + (int)log10(absolute_value);
1451 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001452 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001453 fraction_place = (integer_place > 0)
1454 ? DBL_DIG - integer_place
1455 : DBL_DIG;
1456 size = snprintf(work, sizeof(work), "%0.*f",
1457 fraction_place, number);
1458 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001459 }
1460
Bjorn Reese70a9da52001-04-21 16:57:29 +00001461 /* Remove fractional trailing zeroes */
1462 ptr = after_fraction;
1463 while (*(--ptr) == '0')
1464 ;
1465 if (*ptr != '.')
1466 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001467 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001468
1469 /* Finally copy result back to caller */
1470 size = strlen(work) + 1;
1471 if (size > buffersize) {
1472 work[buffersize - 1] = 0;
1473 size = buffersize;
1474 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001475 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001476 }
1477 break;
1478 }
1479}
1480
Owen Taylor3473f882001-02-23 17:55:21 +00001481
1482/************************************************************************
1483 * *
1484 * Routines to handle NodeSets *
1485 * *
1486 ************************************************************************/
1487
1488/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001489 * xmlXPathOrderDocElems:
1490 * @doc: an input document
1491 *
1492 * Call this routine to speed up XPath computation on static documents.
1493 * This stamps all the element nodes with the document order
1494 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001495 * field, the value stored is actually - the node number (starting at -1)
1496 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001497 *
William M. Brack08171912003-12-29 02:52:11 +00001498 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001499 * of error.
1500 */
1501long
1502xmlXPathOrderDocElems(xmlDocPtr doc) {
1503 long count = 0;
1504 xmlNodePtr cur;
1505
1506 if (doc == NULL)
1507 return(-1);
1508 cur = doc->children;
1509 while (cur != NULL) {
1510 if (cur->type == XML_ELEMENT_NODE) {
1511 cur->content = (void *) (-(++count));
1512 if (cur->children != NULL) {
1513 cur = cur->children;
1514 continue;
1515 }
1516 }
1517 if (cur->next != NULL) {
1518 cur = cur->next;
1519 continue;
1520 }
1521 do {
1522 cur = cur->parent;
1523 if (cur == NULL)
1524 break;
1525 if (cur == (xmlNodePtr) doc) {
1526 cur = NULL;
1527 break;
1528 }
1529 if (cur->next != NULL) {
1530 cur = cur->next;
1531 break;
1532 }
1533 } while (cur != NULL);
1534 }
1535 return(count);
1536}
1537
1538/**
Owen Taylor3473f882001-02-23 17:55:21 +00001539 * xmlXPathCmpNodes:
1540 * @node1: the first node
1541 * @node2: the second node
1542 *
1543 * Compare two nodes w.r.t document order
1544 *
1545 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001546 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001547 */
1548int
1549xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1550 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001551 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001552 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001553 xmlNodePtr cur, root;
1554
1555 if ((node1 == NULL) || (node2 == NULL))
1556 return(-2);
1557 /*
1558 * a couple of optimizations which will avoid computations in most cases
1559 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001560 if (node1->type == XML_ATTRIBUTE_NODE) {
1561 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001562 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001563 node1 = node1->parent;
1564 }
1565 if (node2->type == XML_ATTRIBUTE_NODE) {
1566 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001567 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001568 node2 = node2->parent;
1569 }
1570 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001571 if (attr1 == attr2) {
1572 /* not required, but we keep attributes in order */
1573 if (attr1 != 0) {
1574 cur = attrNode2->prev;
1575 while (cur != NULL) {
1576 if (cur == attrNode1)
1577 return (1);
1578 cur = cur->prev;
1579 }
1580 return (-1);
1581 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001582 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001583 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001584 if (attr2 == 1)
1585 return(1);
1586 return(-1);
1587 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001588 if ((node1->type == XML_NAMESPACE_DECL) ||
1589 (node2->type == XML_NAMESPACE_DECL))
1590 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001591 if (node1 == node2->prev)
1592 return(1);
1593 if (node1 == node2->next)
1594 return(-1);
1595
1596 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001597 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001598 */
1599 if ((node1->type == XML_ELEMENT_NODE) &&
1600 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001601 (0 > (long) node1->content) &&
1602 (0 > (long) node2->content) &&
1603 (node1->doc == node2->doc)) {
1604 long l1, l2;
1605
1606 l1 = -((long) node1->content);
1607 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001608 if (l1 < l2)
1609 return(1);
1610 if (l1 > l2)
1611 return(-1);
1612 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001613
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001614 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001615 * compute depth to root
1616 */
1617 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1618 if (cur == node1)
1619 return(1);
1620 depth2++;
1621 }
1622 root = cur;
1623 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1624 if (cur == node2)
1625 return(-1);
1626 depth1++;
1627 }
1628 /*
1629 * Distinct document (or distinct entities :-( ) case.
1630 */
1631 if (root != cur) {
1632 return(-2);
1633 }
1634 /*
1635 * get the nearest common ancestor.
1636 */
1637 while (depth1 > depth2) {
1638 depth1--;
1639 node1 = node1->parent;
1640 }
1641 while (depth2 > depth1) {
1642 depth2--;
1643 node2 = node2->parent;
1644 }
1645 while (node1->parent != node2->parent) {
1646 node1 = node1->parent;
1647 node2 = node2->parent;
1648 /* should not happen but just in case ... */
1649 if ((node1 == NULL) || (node2 == NULL))
1650 return(-2);
1651 }
1652 /*
1653 * Find who's first.
1654 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001655 if (node1 == node2->prev)
1656 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001657 if (node1 == node2->next)
1658 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001659 /*
1660 * Speedup using document order if availble.
1661 */
1662 if ((node1->type == XML_ELEMENT_NODE) &&
1663 (node2->type == XML_ELEMENT_NODE) &&
1664 (0 > (long) node1->content) &&
1665 (0 > (long) node2->content) &&
1666 (node1->doc == node2->doc)) {
1667 long l1, l2;
1668
1669 l1 = -((long) node1->content);
1670 l2 = -((long) node2->content);
1671 if (l1 < l2)
1672 return(1);
1673 if (l1 > l2)
1674 return(-1);
1675 }
1676
Owen Taylor3473f882001-02-23 17:55:21 +00001677 for (cur = node1->next;cur != NULL;cur = cur->next)
1678 if (cur == node2)
1679 return(1);
1680 return(-1); /* assume there is no sibling list corruption */
1681}
1682
1683/**
1684 * xmlXPathNodeSetSort:
1685 * @set: the node set
1686 *
1687 * Sort the node set in document order
1688 */
1689void
1690xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001691 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001692 xmlNodePtr tmp;
1693
1694 if (set == NULL)
1695 return;
1696
1697 /* Use Shell's sort to sort the node-set */
1698 len = set->nodeNr;
1699 for (incr = len / 2; incr > 0; incr /= 2) {
1700 for (i = incr; i < len; i++) {
1701 j = i - incr;
1702 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001703 if (xmlXPathCmpNodes(set->nodeTab[j],
1704 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001705 tmp = set->nodeTab[j];
1706 set->nodeTab[j] = set->nodeTab[j + incr];
1707 set->nodeTab[j + incr] = tmp;
1708 j -= incr;
1709 } else
1710 break;
1711 }
1712 }
1713 }
1714}
1715
1716#define XML_NODESET_DEFAULT 10
1717/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001718 * xmlXPathNodeSetDupNs:
1719 * @node: the parent node of the namespace XPath node
1720 * @ns: the libxml namespace declaration node.
1721 *
1722 * Namespace node in libxml don't match the XPath semantic. In a node set
1723 * the namespace nodes are duplicated and the next pointer is set to the
1724 * parent node in the XPath semantic.
1725 *
1726 * Returns the newly created object.
1727 */
1728static xmlNodePtr
1729xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1730 xmlNsPtr cur;
1731
1732 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1733 return(NULL);
1734 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1735 return((xmlNodePtr) ns);
1736
1737 /*
1738 * Allocate a new Namespace and fill the fields.
1739 */
1740 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1741 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001742 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001743 return(NULL);
1744 }
1745 memset(cur, 0, sizeof(xmlNs));
1746 cur->type = XML_NAMESPACE_DECL;
1747 if (ns->href != NULL)
1748 cur->href = xmlStrdup(ns->href);
1749 if (ns->prefix != NULL)
1750 cur->prefix = xmlStrdup(ns->prefix);
1751 cur->next = (xmlNsPtr) node;
1752 return((xmlNodePtr) cur);
1753}
1754
1755/**
1756 * xmlXPathNodeSetFreeNs:
1757 * @ns: the XPath namespace node found in a nodeset.
1758 *
William M. Brack08171912003-12-29 02:52:11 +00001759 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001760 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001761 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001762 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001763void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001764xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1765 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1766 return;
1767
1768 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1769 if (ns->href != NULL)
1770 xmlFree((xmlChar *)ns->href);
1771 if (ns->prefix != NULL)
1772 xmlFree((xmlChar *)ns->prefix);
1773 xmlFree(ns);
1774 }
1775}
1776
1777/**
Owen Taylor3473f882001-02-23 17:55:21 +00001778 * xmlXPathNodeSetCreate:
1779 * @val: an initial xmlNodePtr, or NULL
1780 *
1781 * Create a new xmlNodeSetPtr of type double and of value @val
1782 *
1783 * Returns the newly created object.
1784 */
1785xmlNodeSetPtr
1786xmlXPathNodeSetCreate(xmlNodePtr val) {
1787 xmlNodeSetPtr ret;
1788
1789 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1790 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001791 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001792 return(NULL);
1793 }
1794 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1795 if (val != NULL) {
1796 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1797 sizeof(xmlNodePtr));
1798 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001799 xmlXPathErrMemory(NULL, "creating nodeset\n");
1800 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001801 return(NULL);
1802 }
1803 memset(ret->nodeTab, 0 ,
1804 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1805 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001806 if (val->type == XML_NAMESPACE_DECL) {
1807 xmlNsPtr ns = (xmlNsPtr) val;
1808
1809 ret->nodeTab[ret->nodeNr++] =
1810 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1811 } else
1812 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001813 }
1814 return(ret);
1815}
1816
1817/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001818 * xmlXPathNodeSetContains:
1819 * @cur: the node-set
1820 * @val: the node
1821 *
1822 * checks whether @cur contains @val
1823 *
1824 * Returns true (1) if @cur contains @val, false (0) otherwise
1825 */
1826int
1827xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1828 int i;
1829
Daniel Veillarda82b1822004-11-08 16:24:57 +00001830 if ((cur == NULL) || (val == NULL)) return(0);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001831 if (val->type == XML_NAMESPACE_DECL) {
1832 for (i = 0; i < cur->nodeNr; i++) {
1833 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1834 xmlNsPtr ns1, ns2;
1835
1836 ns1 = (xmlNsPtr) val;
1837 ns2 = (xmlNsPtr) cur->nodeTab[i];
1838 if (ns1 == ns2)
1839 return(1);
1840 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1841 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1842 return(1);
1843 }
1844 }
1845 } else {
1846 for (i = 0; i < cur->nodeNr; i++) {
1847 if (cur->nodeTab[i] == val)
1848 return(1);
1849 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001850 }
1851 return(0);
1852}
1853
1854/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001855 * xmlXPathNodeSetAddNs:
1856 * @cur: the initial node set
1857 * @node: the hosting node
1858 * @ns: a the namespace node
1859 *
1860 * add a new namespace node to an existing NodeSet
1861 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001862void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001863xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1864 int i;
1865
Daniel Veillarda82b1822004-11-08 16:24:57 +00001866
1867 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
1868 (ns->type != XML_NAMESPACE_DECL) ||
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001869 (node->type != XML_ELEMENT_NODE))
1870 return;
1871
William M. Brack08171912003-12-29 02:52:11 +00001872 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001873 /*
William M. Brack08171912003-12-29 02:52:11 +00001874 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001875 */
1876 for (i = 0;i < cur->nodeNr;i++) {
1877 if ((cur->nodeTab[i] != NULL) &&
1878 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001879 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001880 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1881 return;
1882 }
1883
1884 /*
1885 * grow the nodeTab if needed
1886 */
1887 if (cur->nodeMax == 0) {
1888 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1889 sizeof(xmlNodePtr));
1890 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001891 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001892 return;
1893 }
1894 memset(cur->nodeTab, 0 ,
1895 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1896 cur->nodeMax = XML_NODESET_DEFAULT;
1897 } else if (cur->nodeNr == cur->nodeMax) {
1898 xmlNodePtr *temp;
1899
1900 cur->nodeMax *= 2;
1901 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1902 sizeof(xmlNodePtr));
1903 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001904 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001905 return;
1906 }
1907 cur->nodeTab = temp;
1908 }
1909 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1910}
1911
1912/**
Owen Taylor3473f882001-02-23 17:55:21 +00001913 * xmlXPathNodeSetAdd:
1914 * @cur: the initial node set
1915 * @val: a new xmlNodePtr
1916 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001917 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001918 */
1919void
1920xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1921 int i;
1922
Daniel Veillarda82b1822004-11-08 16:24:57 +00001923 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001924
Daniel Veillardef0b4502003-03-24 13:57:34 +00001925#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001926 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1927 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001928#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001929
William M. Brack08171912003-12-29 02:52:11 +00001930 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001931 /*
William M. Brack08171912003-12-29 02:52:11 +00001932 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001933 */
1934 for (i = 0;i < cur->nodeNr;i++)
1935 if (cur->nodeTab[i] == val) return;
1936
1937 /*
1938 * grow the nodeTab if needed
1939 */
1940 if (cur->nodeMax == 0) {
1941 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1942 sizeof(xmlNodePtr));
1943 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001944 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001945 return;
1946 }
1947 memset(cur->nodeTab, 0 ,
1948 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1949 cur->nodeMax = XML_NODESET_DEFAULT;
1950 } else if (cur->nodeNr == cur->nodeMax) {
1951 xmlNodePtr *temp;
1952
1953 cur->nodeMax *= 2;
1954 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1955 sizeof(xmlNodePtr));
1956 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001957 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001958 return;
1959 }
1960 cur->nodeTab = temp;
1961 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001962 if (val->type == XML_NAMESPACE_DECL) {
1963 xmlNsPtr ns = (xmlNsPtr) val;
1964
1965 cur->nodeTab[cur->nodeNr++] =
1966 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1967 } else
1968 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001969}
1970
1971/**
1972 * xmlXPathNodeSetAddUnique:
1973 * @cur: the initial node set
1974 * @val: a new xmlNodePtr
1975 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001976 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001977 * when we are sure the node is not already in the set.
1978 */
1979void
1980xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00001981 if ((cur == NULL) || (val == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001982
Daniel Veillardef0b4502003-03-24 13:57:34 +00001983#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001984 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1985 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001986#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001987
William M. Brack08171912003-12-29 02:52:11 +00001988 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001989 /*
1990 * grow the nodeTab if needed
1991 */
1992 if (cur->nodeMax == 0) {
1993 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1994 sizeof(xmlNodePtr));
1995 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001996 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001997 return;
1998 }
1999 memset(cur->nodeTab, 0 ,
2000 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2001 cur->nodeMax = XML_NODESET_DEFAULT;
2002 } else if (cur->nodeNr == cur->nodeMax) {
2003 xmlNodePtr *temp;
2004
2005 cur->nodeMax *= 2;
2006 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
2007 sizeof(xmlNodePtr));
2008 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002009 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002010 return;
2011 }
2012 cur->nodeTab = temp;
2013 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002014 if (val->type == XML_NAMESPACE_DECL) {
2015 xmlNsPtr ns = (xmlNsPtr) val;
2016
2017 cur->nodeTab[cur->nodeNr++] =
2018 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2019 } else
2020 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00002021}
2022
2023/**
2024 * xmlXPathNodeSetMerge:
2025 * @val1: the first NodeSet or NULL
2026 * @val2: the second NodeSet
2027 *
2028 * Merges two nodesets, all nodes from @val2 are added to @val1
2029 * if @val1 is NULL, a new set is created and copied from @val2
2030 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002031 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002032 */
2033xmlNodeSetPtr
2034xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002035 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002036
2037 if (val2 == NULL) return(val1);
2038 if (val1 == NULL) {
2039 val1 = xmlXPathNodeSetCreate(NULL);
2040 }
2041
William M. Brack08171912003-12-29 02:52:11 +00002042 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002043 initNr = val1->nodeNr;
2044
2045 for (i = 0;i < val2->nodeNr;i++) {
2046 /*
William M. Brack08171912003-12-29 02:52:11 +00002047 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002048 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002049 skip = 0;
2050 for (j = 0; j < initNr; j++) {
2051 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2052 skip = 1;
2053 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002054 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2055 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2056 xmlNsPtr ns1, ns2;
2057 ns1 = (xmlNsPtr) val1->nodeTab[j];
2058 ns2 = (xmlNsPtr) val2->nodeTab[i];
2059 if ((ns1->next == ns2->next) &&
2060 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2061 skip = 1;
2062 break;
2063 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002064 }
2065 }
2066 if (skip)
2067 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002068
2069 /*
2070 * grow the nodeTab if needed
2071 */
2072 if (val1->nodeMax == 0) {
2073 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2074 sizeof(xmlNodePtr));
2075 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002076 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002077 return(NULL);
2078 }
2079 memset(val1->nodeTab, 0 ,
2080 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2081 val1->nodeMax = XML_NODESET_DEFAULT;
2082 } else if (val1->nodeNr == val1->nodeMax) {
2083 xmlNodePtr *temp;
2084
2085 val1->nodeMax *= 2;
2086 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2087 sizeof(xmlNodePtr));
2088 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002089 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002090 return(NULL);
2091 }
2092 val1->nodeTab = temp;
2093 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002094 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2095 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2096
2097 val1->nodeTab[val1->nodeNr++] =
2098 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2099 } else
2100 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002101 }
2102
2103 return(val1);
2104}
2105
2106/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002107 * xmlXPathNodeSetMergeUnique:
2108 * @val1: the first NodeSet or NULL
2109 * @val2: the second NodeSet
2110 *
2111 * Merges two nodesets, all nodes from @val2 are added to @val1
2112 * if @val1 is NULL, a new set is created and copied from @val2
2113 *
2114 * Returns @val1 once extended or NULL in case of error.
2115 */
2116static xmlNodeSetPtr
2117xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002118 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002119
2120 if (val2 == NULL) return(val1);
2121 if (val1 == NULL) {
2122 val1 = xmlXPathNodeSetCreate(NULL);
2123 }
2124
William M. Brack08171912003-12-29 02:52:11 +00002125 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002126
2127 for (i = 0;i < val2->nodeNr;i++) {
2128 /*
2129 * grow the nodeTab if needed
2130 */
2131 if (val1->nodeMax == 0) {
2132 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2133 sizeof(xmlNodePtr));
2134 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002135 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002136 return(NULL);
2137 }
2138 memset(val1->nodeTab, 0 ,
2139 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2140 val1->nodeMax = XML_NODESET_DEFAULT;
2141 } else if (val1->nodeNr == val1->nodeMax) {
2142 xmlNodePtr *temp;
2143
2144 val1->nodeMax *= 2;
2145 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2146 sizeof(xmlNodePtr));
2147 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002148 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002149 return(NULL);
2150 }
2151 val1->nodeTab = temp;
2152 }
2153 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2154 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2155
2156 val1->nodeTab[val1->nodeNr++] =
2157 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2158 } else
2159 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2160 }
2161
2162 return(val1);
2163}
2164
2165/**
Owen Taylor3473f882001-02-23 17:55:21 +00002166 * xmlXPathNodeSetDel:
2167 * @cur: the initial node set
2168 * @val: an xmlNodePtr
2169 *
2170 * Removes an xmlNodePtr from an existing NodeSet
2171 */
2172void
2173xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2174 int i;
2175
2176 if (cur == NULL) return;
2177 if (val == NULL) return;
2178
2179 /*
William M. Brack08171912003-12-29 02:52:11 +00002180 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002181 */
2182 for (i = 0;i < cur->nodeNr;i++)
2183 if (cur->nodeTab[i] == val) break;
2184
William M. Brack08171912003-12-29 02:52:11 +00002185 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002186#ifdef DEBUG
2187 xmlGenericError(xmlGenericErrorContext,
2188 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2189 val->name);
2190#endif
2191 return;
2192 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002193 if ((cur->nodeTab[i] != NULL) &&
2194 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2195 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002196 cur->nodeNr--;
2197 for (;i < cur->nodeNr;i++)
2198 cur->nodeTab[i] = cur->nodeTab[i + 1];
2199 cur->nodeTab[cur->nodeNr] = NULL;
2200}
2201
2202/**
2203 * xmlXPathNodeSetRemove:
2204 * @cur: the initial node set
2205 * @val: the index to remove
2206 *
2207 * Removes an entry from an existing NodeSet list.
2208 */
2209void
2210xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2211 if (cur == NULL) return;
2212 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002213 if ((cur->nodeTab[val] != NULL) &&
2214 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2215 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002216 cur->nodeNr--;
2217 for (;val < cur->nodeNr;val++)
2218 cur->nodeTab[val] = cur->nodeTab[val + 1];
2219 cur->nodeTab[cur->nodeNr] = NULL;
2220}
2221
2222/**
2223 * xmlXPathFreeNodeSet:
2224 * @obj: the xmlNodeSetPtr to free
2225 *
2226 * Free the NodeSet compound (not the actual nodes !).
2227 */
2228void
2229xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2230 if (obj == NULL) return;
2231 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002232 int i;
2233
William M. Brack08171912003-12-29 02:52:11 +00002234 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002235 for (i = 0;i < obj->nodeNr;i++)
2236 if ((obj->nodeTab[i] != NULL) &&
2237 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2238 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlFree(obj->nodeTab);
2240 }
Owen Taylor3473f882001-02-23 17:55:21 +00002241 xmlFree(obj);
2242}
2243
2244/**
2245 * xmlXPathFreeValueTree:
2246 * @obj: the xmlNodeSetPtr to free
2247 *
2248 * Free the NodeSet compound and the actual tree, this is different
2249 * from xmlXPathFreeNodeSet()
2250 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002251static void
Owen Taylor3473f882001-02-23 17:55:21 +00002252xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2253 int i;
2254
2255 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002256
2257 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002258 for (i = 0;i < obj->nodeNr;i++) {
2259 if (obj->nodeTab[i] != NULL) {
2260 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2261 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2262 } else {
2263 xmlFreeNodeList(obj->nodeTab[i]);
2264 }
2265 }
2266 }
Owen Taylor3473f882001-02-23 17:55:21 +00002267 xmlFree(obj->nodeTab);
2268 }
Owen Taylor3473f882001-02-23 17:55:21 +00002269 xmlFree(obj);
2270}
2271
2272#if defined(DEBUG) || defined(DEBUG_STEP)
2273/**
2274 * xmlGenericErrorContextNodeSet:
2275 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002276 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002277 *
2278 * Quick display of a NodeSet
2279 */
2280void
2281xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2282 int i;
2283
2284 if (output == NULL) output = xmlGenericErrorContext;
2285 if (obj == NULL) {
2286 fprintf(output, "NodeSet == NULL !\n");
2287 return;
2288 }
2289 if (obj->nodeNr == 0) {
2290 fprintf(output, "NodeSet is empty\n");
2291 return;
2292 }
2293 if (obj->nodeTab == NULL) {
2294 fprintf(output, " nodeTab == NULL !\n");
2295 return;
2296 }
2297 for (i = 0; i < obj->nodeNr; i++) {
2298 if (obj->nodeTab[i] == NULL) {
2299 fprintf(output, " NULL !\n");
2300 return;
2301 }
2302 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2303 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2304 fprintf(output, " /");
2305 else if (obj->nodeTab[i]->name == NULL)
2306 fprintf(output, " noname!");
2307 else fprintf(output, " %s", obj->nodeTab[i]->name);
2308 }
2309 fprintf(output, "\n");
2310}
2311#endif
2312
2313/**
2314 * xmlXPathNewNodeSet:
2315 * @val: the NodePtr value
2316 *
2317 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2318 * it with the single Node @val
2319 *
2320 * Returns the newly created object.
2321 */
2322xmlXPathObjectPtr
2323xmlXPathNewNodeSet(xmlNodePtr val) {
2324 xmlXPathObjectPtr ret;
2325
2326 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2327 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002328 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002329 return(NULL);
2330 }
2331 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2332 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002333 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002334 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002335 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002336 return(ret);
2337}
2338
2339/**
2340 * xmlXPathNewValueTree:
2341 * @val: the NodePtr value
2342 *
2343 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2344 * it with the tree root @val
2345 *
2346 * Returns the newly created object.
2347 */
2348xmlXPathObjectPtr
2349xmlXPathNewValueTree(xmlNodePtr val) {
2350 xmlXPathObjectPtr ret;
2351
2352 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2353 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002354 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002355 return(NULL);
2356 }
2357 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2358 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002359 ret->boolval = 1;
2360 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002361 ret->nodesetval = xmlXPathNodeSetCreate(val);
2362 return(ret);
2363}
2364
2365/**
2366 * xmlXPathNewNodeSetList:
2367 * @val: an existing NodeSet
2368 *
2369 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2370 * it with the Nodeset @val
2371 *
2372 * Returns the newly created object.
2373 */
2374xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002375xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2376{
Owen Taylor3473f882001-02-23 17:55:21 +00002377 xmlXPathObjectPtr ret;
2378 int i;
2379
2380 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002381 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002382 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002383 ret = xmlXPathNewNodeSet(NULL);
2384 else {
2385 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2386 for (i = 1; i < val->nodeNr; ++i)
2387 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2388 }
Owen Taylor3473f882001-02-23 17:55:21 +00002389
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002390 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002391}
2392
2393/**
2394 * xmlXPathWrapNodeSet:
2395 * @val: the NodePtr value
2396 *
2397 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2398 *
2399 * Returns the newly created object.
2400 */
2401xmlXPathObjectPtr
2402xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2403 xmlXPathObjectPtr ret;
2404
2405 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2406 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002407 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002408 return(NULL);
2409 }
2410 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2411 ret->type = XPATH_NODESET;
2412 ret->nodesetval = val;
2413 return(ret);
2414}
2415
2416/**
2417 * xmlXPathFreeNodeSetList:
2418 * @obj: an existing NodeSetList object
2419 *
2420 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2421 * the list contrary to xmlXPathFreeObject().
2422 */
2423void
2424xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2425 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002426 xmlFree(obj);
2427}
2428
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002429/**
2430 * xmlXPathDifference:
2431 * @nodes1: a node-set
2432 * @nodes2: a node-set
2433 *
2434 * Implements the EXSLT - Sets difference() function:
2435 * node-set set:difference (node-set, node-set)
2436 *
2437 * Returns the difference between the two node sets, or nodes1 if
2438 * nodes2 is empty
2439 */
2440xmlNodeSetPtr
2441xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2442 xmlNodeSetPtr ret;
2443 int i, l1;
2444 xmlNodePtr cur;
2445
2446 if (xmlXPathNodeSetIsEmpty(nodes2))
2447 return(nodes1);
2448
2449 ret = xmlXPathNodeSetCreate(NULL);
2450 if (xmlXPathNodeSetIsEmpty(nodes1))
2451 return(ret);
2452
2453 l1 = xmlXPathNodeSetGetLength(nodes1);
2454
2455 for (i = 0; i < l1; i++) {
2456 cur = xmlXPathNodeSetItem(nodes1, i);
2457 if (!xmlXPathNodeSetContains(nodes2, cur))
2458 xmlXPathNodeSetAddUnique(ret, cur);
2459 }
2460 return(ret);
2461}
2462
2463/**
2464 * xmlXPathIntersection:
2465 * @nodes1: a node-set
2466 * @nodes2: a node-set
2467 *
2468 * Implements the EXSLT - Sets intersection() function:
2469 * node-set set:intersection (node-set, node-set)
2470 *
2471 * Returns a node set comprising the nodes that are within both the
2472 * node sets passed as arguments
2473 */
2474xmlNodeSetPtr
2475xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2476 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2477 int i, l1;
2478 xmlNodePtr cur;
2479
2480 if (xmlXPathNodeSetIsEmpty(nodes1))
2481 return(ret);
2482 if (xmlXPathNodeSetIsEmpty(nodes2))
2483 return(ret);
2484
2485 l1 = xmlXPathNodeSetGetLength(nodes1);
2486
2487 for (i = 0; i < l1; i++) {
2488 cur = xmlXPathNodeSetItem(nodes1, i);
2489 if (xmlXPathNodeSetContains(nodes2, cur))
2490 xmlXPathNodeSetAddUnique(ret, cur);
2491 }
2492 return(ret);
2493}
2494
2495/**
2496 * xmlXPathDistinctSorted:
2497 * @nodes: a node-set, sorted by document order
2498 *
2499 * Implements the EXSLT - Sets distinct() function:
2500 * node-set set:distinct (node-set)
2501 *
2502 * Returns a subset of the nodes contained in @nodes, or @nodes if
2503 * it is empty
2504 */
2505xmlNodeSetPtr
2506xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2507 xmlNodeSetPtr ret;
2508 xmlHashTablePtr hash;
2509 int i, l;
2510 xmlChar * strval;
2511 xmlNodePtr cur;
2512
2513 if (xmlXPathNodeSetIsEmpty(nodes))
2514 return(nodes);
2515
2516 ret = xmlXPathNodeSetCreate(NULL);
2517 l = xmlXPathNodeSetGetLength(nodes);
2518 hash = xmlHashCreate (l);
2519 for (i = 0; i < l; i++) {
2520 cur = xmlXPathNodeSetItem(nodes, i);
2521 strval = xmlXPathCastNodeToString(cur);
2522 if (xmlHashLookup(hash, strval) == NULL) {
2523 xmlHashAddEntry(hash, strval, strval);
2524 xmlXPathNodeSetAddUnique(ret, cur);
2525 } else {
2526 xmlFree(strval);
2527 }
2528 }
2529 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2530 return(ret);
2531}
2532
2533/**
2534 * xmlXPathDistinct:
2535 * @nodes: a node-set
2536 *
2537 * Implements the EXSLT - Sets distinct() function:
2538 * node-set set:distinct (node-set)
2539 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2540 * is called with the sorted node-set
2541 *
2542 * Returns a subset of the nodes contained in @nodes, or @nodes if
2543 * it is empty
2544 */
2545xmlNodeSetPtr
2546xmlXPathDistinct (xmlNodeSetPtr nodes) {
2547 if (xmlXPathNodeSetIsEmpty(nodes))
2548 return(nodes);
2549
2550 xmlXPathNodeSetSort(nodes);
2551 return(xmlXPathDistinctSorted(nodes));
2552}
2553
2554/**
2555 * xmlXPathHasSameNodes:
2556 * @nodes1: a node-set
2557 * @nodes2: a node-set
2558 *
2559 * Implements the EXSLT - Sets has-same-nodes function:
2560 * boolean set:has-same-node(node-set, node-set)
2561 *
2562 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2563 * otherwise
2564 */
2565int
2566xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2567 int i, l;
2568 xmlNodePtr cur;
2569
2570 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2571 xmlXPathNodeSetIsEmpty(nodes2))
2572 return(0);
2573
2574 l = xmlXPathNodeSetGetLength(nodes1);
2575 for (i = 0; i < l; i++) {
2576 cur = xmlXPathNodeSetItem(nodes1, i);
2577 if (xmlXPathNodeSetContains(nodes2, cur))
2578 return(1);
2579 }
2580 return(0);
2581}
2582
2583/**
2584 * xmlXPathNodeLeadingSorted:
2585 * @nodes: a node-set, sorted by document order
2586 * @node: a node
2587 *
2588 * Implements the EXSLT - Sets leading() function:
2589 * node-set set:leading (node-set, node-set)
2590 *
2591 * Returns the nodes in @nodes that precede @node in document order,
2592 * @nodes if @node is NULL or an empty node-set if @nodes
2593 * doesn't contain @node
2594 */
2595xmlNodeSetPtr
2596xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2597 int i, l;
2598 xmlNodePtr cur;
2599 xmlNodeSetPtr ret;
2600
2601 if (node == NULL)
2602 return(nodes);
2603
2604 ret = xmlXPathNodeSetCreate(NULL);
2605 if (xmlXPathNodeSetIsEmpty(nodes) ||
2606 (!xmlXPathNodeSetContains(nodes, node)))
2607 return(ret);
2608
2609 l = xmlXPathNodeSetGetLength(nodes);
2610 for (i = 0; i < l; i++) {
2611 cur = xmlXPathNodeSetItem(nodes, i);
2612 if (cur == node)
2613 break;
2614 xmlXPathNodeSetAddUnique(ret, cur);
2615 }
2616 return(ret);
2617}
2618
2619/**
2620 * xmlXPathNodeLeading:
2621 * @nodes: a node-set
2622 * @node: a node
2623 *
2624 * Implements the EXSLT - Sets leading() function:
2625 * node-set set:leading (node-set, node-set)
2626 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2627 * is called.
2628 *
2629 * Returns the nodes in @nodes that precede @node in document order,
2630 * @nodes if @node is NULL or an empty node-set if @nodes
2631 * doesn't contain @node
2632 */
2633xmlNodeSetPtr
2634xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2635 xmlXPathNodeSetSort(nodes);
2636 return(xmlXPathNodeLeadingSorted(nodes, node));
2637}
2638
2639/**
2640 * xmlXPathLeadingSorted:
2641 * @nodes1: a node-set, sorted by document order
2642 * @nodes2: a node-set, sorted by document order
2643 *
2644 * Implements the EXSLT - Sets leading() function:
2645 * node-set set:leading (node-set, node-set)
2646 *
2647 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2648 * in document order, @nodes1 if @nodes2 is NULL or empty or
2649 * an empty node-set if @nodes1 doesn't contain @nodes2
2650 */
2651xmlNodeSetPtr
2652xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2653 if (xmlXPathNodeSetIsEmpty(nodes2))
2654 return(nodes1);
2655 return(xmlXPathNodeLeadingSorted(nodes1,
2656 xmlXPathNodeSetItem(nodes2, 1)));
2657}
2658
2659/**
2660 * xmlXPathLeading:
2661 * @nodes1: a node-set
2662 * @nodes2: a node-set
2663 *
2664 * Implements the EXSLT - Sets leading() function:
2665 * node-set set:leading (node-set, node-set)
2666 * @nodes1 and @nodes2 are sorted by document order, then
2667 * #exslSetsLeadingSorted is called.
2668 *
2669 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2670 * in document order, @nodes1 if @nodes2 is NULL or empty or
2671 * an empty node-set if @nodes1 doesn't contain @nodes2
2672 */
2673xmlNodeSetPtr
2674xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2675 if (xmlXPathNodeSetIsEmpty(nodes2))
2676 return(nodes1);
2677 if (xmlXPathNodeSetIsEmpty(nodes1))
2678 return(xmlXPathNodeSetCreate(NULL));
2679 xmlXPathNodeSetSort(nodes1);
2680 xmlXPathNodeSetSort(nodes2);
2681 return(xmlXPathNodeLeadingSorted(nodes1,
2682 xmlXPathNodeSetItem(nodes2, 1)));
2683}
2684
2685/**
2686 * xmlXPathNodeTrailingSorted:
2687 * @nodes: a node-set, sorted by document order
2688 * @node: a node
2689 *
2690 * Implements the EXSLT - Sets trailing() function:
2691 * node-set set:trailing (node-set, node-set)
2692 *
2693 * Returns the nodes in @nodes that follow @node in document order,
2694 * @nodes if @node is NULL or an empty node-set if @nodes
2695 * doesn't contain @node
2696 */
2697xmlNodeSetPtr
2698xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2699 int i, l;
2700 xmlNodePtr cur;
2701 xmlNodeSetPtr ret;
2702
2703 if (node == NULL)
2704 return(nodes);
2705
2706 ret = xmlXPathNodeSetCreate(NULL);
2707 if (xmlXPathNodeSetIsEmpty(nodes) ||
2708 (!xmlXPathNodeSetContains(nodes, node)))
2709 return(ret);
2710
2711 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002712 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002713 cur = xmlXPathNodeSetItem(nodes, i);
2714 if (cur == node)
2715 break;
2716 xmlXPathNodeSetAddUnique(ret, cur);
2717 }
2718 return(ret);
2719}
2720
2721/**
2722 * xmlXPathNodeTrailing:
2723 * @nodes: a node-set
2724 * @node: a node
2725 *
2726 * Implements the EXSLT - Sets trailing() function:
2727 * node-set set:trailing (node-set, node-set)
2728 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2729 * is called.
2730 *
2731 * Returns the nodes in @nodes that follow @node in document order,
2732 * @nodes if @node is NULL or an empty node-set if @nodes
2733 * doesn't contain @node
2734 */
2735xmlNodeSetPtr
2736xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2737 xmlXPathNodeSetSort(nodes);
2738 return(xmlXPathNodeTrailingSorted(nodes, node));
2739}
2740
2741/**
2742 * xmlXPathTrailingSorted:
2743 * @nodes1: a node-set, sorted by document order
2744 * @nodes2: a node-set, sorted by document order
2745 *
2746 * Implements the EXSLT - Sets trailing() function:
2747 * node-set set:trailing (node-set, node-set)
2748 *
2749 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2750 * in document order, @nodes1 if @nodes2 is NULL or empty or
2751 * an empty node-set if @nodes1 doesn't contain @nodes2
2752 */
2753xmlNodeSetPtr
2754xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2755 if (xmlXPathNodeSetIsEmpty(nodes2))
2756 return(nodes1);
2757 return(xmlXPathNodeTrailingSorted(nodes1,
2758 xmlXPathNodeSetItem(nodes2, 0)));
2759}
2760
2761/**
2762 * xmlXPathTrailing:
2763 * @nodes1: a node-set
2764 * @nodes2: a node-set
2765 *
2766 * Implements the EXSLT - Sets trailing() function:
2767 * node-set set:trailing (node-set, node-set)
2768 * @nodes1 and @nodes2 are sorted by document order, then
2769 * #xmlXPathTrailingSorted is called.
2770 *
2771 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2772 * in document order, @nodes1 if @nodes2 is NULL or empty or
2773 * an empty node-set if @nodes1 doesn't contain @nodes2
2774 */
2775xmlNodeSetPtr
2776xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2777 if (xmlXPathNodeSetIsEmpty(nodes2))
2778 return(nodes1);
2779 if (xmlXPathNodeSetIsEmpty(nodes1))
2780 return(xmlXPathNodeSetCreate(NULL));
2781 xmlXPathNodeSetSort(nodes1);
2782 xmlXPathNodeSetSort(nodes2);
2783 return(xmlXPathNodeTrailingSorted(nodes1,
2784 xmlXPathNodeSetItem(nodes2, 0)));
2785}
2786
Owen Taylor3473f882001-02-23 17:55:21 +00002787/************************************************************************
2788 * *
2789 * Routines to handle extra functions *
2790 * *
2791 ************************************************************************/
2792
2793/**
2794 * xmlXPathRegisterFunc:
2795 * @ctxt: the XPath context
2796 * @name: the function name
2797 * @f: the function implementation or NULL
2798 *
2799 * Register a new function. If @f is NULL it unregisters the function
2800 *
2801 * Returns 0 in case of success, -1 in case of error
2802 */
2803int
2804xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2805 xmlXPathFunction f) {
2806 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2807}
2808
2809/**
2810 * xmlXPathRegisterFuncNS:
2811 * @ctxt: the XPath context
2812 * @name: the function name
2813 * @ns_uri: the function namespace URI
2814 * @f: the function implementation or NULL
2815 *
2816 * Register a new function. If @f is NULL it unregisters the function
2817 *
2818 * Returns 0 in case of success, -1 in case of error
2819 */
2820int
2821xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2822 const xmlChar *ns_uri, xmlXPathFunction f) {
2823 if (ctxt == NULL)
2824 return(-1);
2825 if (name == NULL)
2826 return(-1);
2827
2828 if (ctxt->funcHash == NULL)
2829 ctxt->funcHash = xmlHashCreate(0);
2830 if (ctxt->funcHash == NULL)
2831 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002832 if (f == NULL)
2833 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
William M. Brackad0e67c2004-12-01 14:35:10 +00002834 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
Owen Taylor3473f882001-02-23 17:55:21 +00002835}
2836
2837/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002838 * xmlXPathRegisterFuncLookup:
2839 * @ctxt: the XPath context
2840 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002841 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002842 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002843 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002844 */
2845void
2846xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2847 xmlXPathFuncLookupFunc f,
2848 void *funcCtxt) {
2849 if (ctxt == NULL)
2850 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002851 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002852 ctxt->funcLookupData = funcCtxt;
2853}
2854
2855/**
Owen Taylor3473f882001-02-23 17:55:21 +00002856 * xmlXPathFunctionLookup:
2857 * @ctxt: the XPath context
2858 * @name: the function name
2859 *
2860 * Search in the Function array of the context for the given
2861 * function.
2862 *
2863 * Returns the xmlXPathFunction or NULL if not found
2864 */
2865xmlXPathFunction
2866xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002867 if (ctxt == NULL)
2868 return (NULL);
2869
2870 if (ctxt->funcLookupFunc != NULL) {
2871 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002872 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002873
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002874 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002875 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002876 if (ret != NULL)
2877 return(ret);
2878 }
Owen Taylor3473f882001-02-23 17:55:21 +00002879 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2880}
2881
2882/**
2883 * xmlXPathFunctionLookupNS:
2884 * @ctxt: the XPath context
2885 * @name: the function name
2886 * @ns_uri: the function namespace URI
2887 *
2888 * Search in the Function array of the context for the given
2889 * function.
2890 *
2891 * Returns the xmlXPathFunction or NULL if not found
2892 */
2893xmlXPathFunction
2894xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2895 const xmlChar *ns_uri) {
William M. Brackad0e67c2004-12-01 14:35:10 +00002896 xmlXPathFunction ret;
2897
Owen Taylor3473f882001-02-23 17:55:21 +00002898 if (ctxt == NULL)
2899 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002900 if (name == NULL)
2901 return(NULL);
2902
Thomas Broyerba4ad322001-07-26 16:55:21 +00002903 if (ctxt->funcLookupFunc != NULL) {
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002904 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002905
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002906 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002907 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002908 if (ret != NULL)
2909 return(ret);
2910 }
2911
2912 if (ctxt->funcHash == NULL)
2913 return(NULL);
2914
William M. Brackad0e67c2004-12-01 14:35:10 +00002915 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
2916 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002917}
2918
2919/**
2920 * xmlXPathRegisteredFuncsCleanup:
2921 * @ctxt: the XPath context
2922 *
2923 * Cleanup the XPath context data associated to registered functions
2924 */
2925void
2926xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2927 if (ctxt == NULL)
2928 return;
2929
2930 xmlHashFree(ctxt->funcHash, NULL);
2931 ctxt->funcHash = NULL;
2932}
2933
2934/************************************************************************
2935 * *
William M. Brack08171912003-12-29 02:52:11 +00002936 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002937 * *
2938 ************************************************************************/
2939
2940/**
2941 * xmlXPathRegisterVariable:
2942 * @ctxt: the XPath context
2943 * @name: the variable name
2944 * @value: the variable value or NULL
2945 *
2946 * Register a new variable value. If @value is NULL it unregisters
2947 * the variable
2948 *
2949 * Returns 0 in case of success, -1 in case of error
2950 */
2951int
2952xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2953 xmlXPathObjectPtr value) {
2954 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2955}
2956
2957/**
2958 * xmlXPathRegisterVariableNS:
2959 * @ctxt: the XPath context
2960 * @name: the variable name
2961 * @ns_uri: the variable namespace URI
2962 * @value: the variable value or NULL
2963 *
2964 * Register a new variable value. If @value is NULL it unregisters
2965 * the variable
2966 *
2967 * Returns 0 in case of success, -1 in case of error
2968 */
2969int
2970xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2971 const xmlChar *ns_uri,
2972 xmlXPathObjectPtr value) {
2973 if (ctxt == NULL)
2974 return(-1);
2975 if (name == NULL)
2976 return(-1);
2977
2978 if (ctxt->varHash == NULL)
2979 ctxt->varHash = xmlHashCreate(0);
2980 if (ctxt->varHash == NULL)
2981 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002982 if (value == NULL)
2983 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2984 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002985 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2986 (void *) value,
2987 (xmlHashDeallocator)xmlXPathFreeObject));
2988}
2989
2990/**
2991 * xmlXPathRegisterVariableLookup:
2992 * @ctxt: the XPath context
2993 * @f: the lookup function
2994 * @data: the lookup data
2995 *
2996 * register an external mechanism to do variable lookup
2997 */
2998void
2999xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3000 xmlXPathVariableLookupFunc f, void *data) {
3001 if (ctxt == NULL)
3002 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00003003 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00003004 ctxt->varLookupData = data;
3005}
3006
3007/**
3008 * xmlXPathVariableLookup:
3009 * @ctxt: the XPath context
3010 * @name: the variable name
3011 *
3012 * Search in the Variable array of the context for the given
3013 * variable value.
3014 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003015 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003016 */
3017xmlXPathObjectPtr
3018xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3019 if (ctxt == NULL)
3020 return(NULL);
3021
3022 if (ctxt->varLookupFunc != NULL) {
3023 xmlXPathObjectPtr ret;
3024
3025 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3026 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00003027 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003028 }
3029 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3030}
3031
3032/**
3033 * xmlXPathVariableLookupNS:
3034 * @ctxt: the XPath context
3035 * @name: the variable name
3036 * @ns_uri: the variable namespace URI
3037 *
3038 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003039 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003040 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003041 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003042 */
3043xmlXPathObjectPtr
3044xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3045 const xmlChar *ns_uri) {
3046 if (ctxt == NULL)
3047 return(NULL);
3048
3049 if (ctxt->varLookupFunc != NULL) {
3050 xmlXPathObjectPtr ret;
3051
3052 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3053 (ctxt->varLookupData, name, ns_uri);
3054 if (ret != NULL) return(ret);
3055 }
3056
3057 if (ctxt->varHash == NULL)
3058 return(NULL);
3059 if (name == NULL)
3060 return(NULL);
3061
Daniel Veillard8c357d52001-07-03 23:43:33 +00003062 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3063 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003064}
3065
3066/**
3067 * xmlXPathRegisteredVariablesCleanup:
3068 * @ctxt: the XPath context
3069 *
3070 * Cleanup the XPath context data associated to registered variables
3071 */
3072void
3073xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3074 if (ctxt == NULL)
3075 return;
3076
Daniel Veillard76d66f42001-05-16 21:05:17 +00003077 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003078 ctxt->varHash = NULL;
3079}
3080
3081/**
3082 * xmlXPathRegisterNs:
3083 * @ctxt: the XPath context
3084 * @prefix: the namespace prefix
3085 * @ns_uri: the namespace name
3086 *
3087 * Register a new namespace. If @ns_uri is NULL it unregisters
3088 * the namespace
3089 *
3090 * Returns 0 in case of success, -1 in case of error
3091 */
3092int
3093xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3094 const xmlChar *ns_uri) {
3095 if (ctxt == NULL)
3096 return(-1);
3097 if (prefix == NULL)
3098 return(-1);
3099
3100 if (ctxt->nsHash == NULL)
3101 ctxt->nsHash = xmlHashCreate(10);
3102 if (ctxt->nsHash == NULL)
3103 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003104 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003105 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003106 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003107 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003108 (xmlHashDeallocator)xmlFree));
3109}
3110
3111/**
3112 * xmlXPathNsLookup:
3113 * @ctxt: the XPath context
3114 * @prefix: the namespace prefix value
3115 *
3116 * Search in the namespace declaration array of the context for the given
3117 * namespace name associated to the given prefix
3118 *
3119 * Returns the value or NULL if not found
3120 */
3121const xmlChar *
3122xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3123 if (ctxt == NULL)
3124 return(NULL);
3125 if (prefix == NULL)
3126 return(NULL);
3127
3128#ifdef XML_XML_NAMESPACE
3129 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3130 return(XML_XML_NAMESPACE);
3131#endif
3132
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003133 if (ctxt->namespaces != NULL) {
3134 int i;
3135
3136 for (i = 0;i < ctxt->nsNr;i++) {
3137 if ((ctxt->namespaces[i] != NULL) &&
3138 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3139 return(ctxt->namespaces[i]->href);
3140 }
3141 }
Owen Taylor3473f882001-02-23 17:55:21 +00003142
3143 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3144}
3145
3146/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003147 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003148 * @ctxt: the XPath context
3149 *
3150 * Cleanup the XPath context data associated to registered variables
3151 */
3152void
3153xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3154 if (ctxt == NULL)
3155 return;
3156
Daniel Veillard42766c02002-08-22 20:52:17 +00003157 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003158 ctxt->nsHash = NULL;
3159}
3160
3161/************************************************************************
3162 * *
3163 * Routines to handle Values *
3164 * *
3165 ************************************************************************/
3166
William M. Brack08171912003-12-29 02:52:11 +00003167/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003168
3169/**
3170 * xmlXPathNewFloat:
3171 * @val: the double value
3172 *
3173 * Create a new xmlXPathObjectPtr of type double and of value @val
3174 *
3175 * Returns the newly created object.
3176 */
3177xmlXPathObjectPtr
3178xmlXPathNewFloat(double val) {
3179 xmlXPathObjectPtr ret;
3180
3181 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3182 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003183 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003184 return(NULL);
3185 }
3186 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3187 ret->type = XPATH_NUMBER;
3188 ret->floatval = val;
3189 return(ret);
3190}
3191
3192/**
3193 * xmlXPathNewBoolean:
3194 * @val: the boolean value
3195 *
3196 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3197 *
3198 * Returns the newly created object.
3199 */
3200xmlXPathObjectPtr
3201xmlXPathNewBoolean(int val) {
3202 xmlXPathObjectPtr ret;
3203
3204 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3205 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003206 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003207 return(NULL);
3208 }
3209 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3210 ret->type = XPATH_BOOLEAN;
3211 ret->boolval = (val != 0);
3212 return(ret);
3213}
3214
3215/**
3216 * xmlXPathNewString:
3217 * @val: the xmlChar * value
3218 *
3219 * Create a new xmlXPathObjectPtr of type string and of value @val
3220 *
3221 * Returns the newly created object.
3222 */
3223xmlXPathObjectPtr
3224xmlXPathNewString(const xmlChar *val) {
3225 xmlXPathObjectPtr ret;
3226
3227 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3228 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003229 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003230 return(NULL);
3231 }
3232 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3233 ret->type = XPATH_STRING;
3234 if (val != NULL)
3235 ret->stringval = xmlStrdup(val);
3236 else
3237 ret->stringval = xmlStrdup((const xmlChar *)"");
3238 return(ret);
3239}
3240
3241/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003242 * xmlXPathWrapString:
3243 * @val: the xmlChar * value
3244 *
3245 * Wraps the @val string into an XPath object.
3246 *
3247 * Returns the newly created object.
3248 */
3249xmlXPathObjectPtr
3250xmlXPathWrapString (xmlChar *val) {
3251 xmlXPathObjectPtr ret;
3252
3253 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3254 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003255 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003256 return(NULL);
3257 }
3258 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3259 ret->type = XPATH_STRING;
3260 ret->stringval = val;
3261 return(ret);
3262}
3263
3264/**
Owen Taylor3473f882001-02-23 17:55:21 +00003265 * xmlXPathNewCString:
3266 * @val: the char * value
3267 *
3268 * Create a new xmlXPathObjectPtr of type string and of value @val
3269 *
3270 * Returns the newly created object.
3271 */
3272xmlXPathObjectPtr
3273xmlXPathNewCString(const char *val) {
3274 xmlXPathObjectPtr ret;
3275
3276 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3277 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003278 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003279 return(NULL);
3280 }
3281 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3282 ret->type = XPATH_STRING;
3283 ret->stringval = xmlStrdup(BAD_CAST val);
3284 return(ret);
3285}
3286
3287/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003288 * xmlXPathWrapCString:
3289 * @val: the char * value
3290 *
3291 * Wraps a string into an XPath object.
3292 *
3293 * Returns the newly created object.
3294 */
3295xmlXPathObjectPtr
3296xmlXPathWrapCString (char * val) {
3297 return(xmlXPathWrapString((xmlChar *)(val)));
3298}
3299
3300/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003301 * xmlXPathWrapExternal:
3302 * @val: the user data
3303 *
3304 * Wraps the @val data into an XPath object.
3305 *
3306 * Returns the newly created object.
3307 */
3308xmlXPathObjectPtr
3309xmlXPathWrapExternal (void *val) {
3310 xmlXPathObjectPtr ret;
3311
3312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3313 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003314 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003315 return(NULL);
3316 }
3317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3318 ret->type = XPATH_USERS;
3319 ret->user = val;
3320 return(ret);
3321}
3322
3323/**
Owen Taylor3473f882001-02-23 17:55:21 +00003324 * xmlXPathObjectCopy:
3325 * @val: the original object
3326 *
3327 * allocate a new copy of a given object
3328 *
3329 * Returns the newly created object.
3330 */
3331xmlXPathObjectPtr
3332xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3333 xmlXPathObjectPtr ret;
3334
3335 if (val == NULL)
3336 return(NULL);
3337
3338 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3339 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003340 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003341 return(NULL);
3342 }
3343 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3344 switch (val->type) {
3345 case XPATH_BOOLEAN:
3346 case XPATH_NUMBER:
3347 case XPATH_POINT:
3348 case XPATH_RANGE:
3349 break;
3350 case XPATH_STRING:
3351 ret->stringval = xmlStrdup(val->stringval);
3352 break;
3353 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003354#if 0
3355/*
3356 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3357 this previous handling is no longer correct, and can cause some serious
3358 problems (ref. bug 145547)
3359*/
Owen Taylor3473f882001-02-23 17:55:21 +00003360 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003361 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003362 xmlNodePtr cur, tmp;
3363 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003364
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003365 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003366 top = xmlNewDoc(NULL);
3367 top->name = (char *)
3368 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003369 ret->user = top;
3370 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003371 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003372 cur = val->nodesetval->nodeTab[0]->children;
3373 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003374 tmp = xmlDocCopyNode(cur, top, 1);
3375 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003376 cur = cur->next;
3377 }
3378 }
William M. Bracke9449c52004-07-11 14:41:20 +00003379
Daniel Veillard9adc0462003-03-24 18:39:54 +00003380 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003381 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003382 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003383 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003384 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003385#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003386 case XPATH_NODESET:
3387 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003388 /* Do not deallocate the copied tree value */
3389 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003390 break;
3391 case XPATH_LOCATIONSET:
3392#ifdef LIBXML_XPTR_ENABLED
3393 {
3394 xmlLocationSetPtr loc = val->user;
3395 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3396 break;
3397 }
3398#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003399 case XPATH_USERS:
3400 ret->user = val->user;
3401 break;
3402 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003403 xmlGenericError(xmlGenericErrorContext,
3404 "xmlXPathObjectCopy: unsupported type %d\n",
3405 val->type);
3406 break;
3407 }
3408 return(ret);
3409}
3410
3411/**
3412 * xmlXPathFreeObject:
3413 * @obj: the object to free
3414 *
3415 * Free up an xmlXPathObjectPtr object.
3416 */
3417void
3418xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3419 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003420 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003421 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003422#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003423 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003424 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003425 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003426 } else
3427#endif
3428 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003429 xmlXPathFreeValueTree(obj->nodesetval);
3430 } else {
3431 if (obj->nodesetval != NULL)
3432 xmlXPathFreeNodeSet(obj->nodesetval);
3433 }
Owen Taylor3473f882001-02-23 17:55:21 +00003434#ifdef LIBXML_XPTR_ENABLED
3435 } else if (obj->type == XPATH_LOCATIONSET) {
3436 if (obj->user != NULL)
3437 xmlXPtrFreeLocationSet(obj->user);
3438#endif
3439 } else if (obj->type == XPATH_STRING) {
3440 if (obj->stringval != NULL)
3441 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003442 }
3443
Owen Taylor3473f882001-02-23 17:55:21 +00003444 xmlFree(obj);
3445}
3446
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003447
3448/************************************************************************
3449 * *
3450 * Type Casting Routines *
3451 * *
3452 ************************************************************************/
3453
3454/**
3455 * xmlXPathCastBooleanToString:
3456 * @val: a boolean
3457 *
3458 * Converts a boolean to its string value.
3459 *
3460 * Returns a newly allocated string.
3461 */
3462xmlChar *
3463xmlXPathCastBooleanToString (int val) {
3464 xmlChar *ret;
3465 if (val)
3466 ret = xmlStrdup((const xmlChar *) "true");
3467 else
3468 ret = xmlStrdup((const xmlChar *) "false");
3469 return(ret);
3470}
3471
3472/**
3473 * xmlXPathCastNumberToString:
3474 * @val: a number
3475 *
3476 * Converts a number to its string value.
3477 *
3478 * Returns a newly allocated string.
3479 */
3480xmlChar *
3481xmlXPathCastNumberToString (double val) {
3482 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003483 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003484 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003485 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003486 break;
3487 case -1:
3488 ret = xmlStrdup((const xmlChar *) "-Infinity");
3489 break;
3490 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003491 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003492 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003493 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3494 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003495 } else {
3496 /* could be improved */
3497 char buf[100];
3498 xmlXPathFormatNumber(val, buf, 100);
3499 ret = xmlStrdup((const xmlChar *) buf);
3500 }
3501 }
3502 return(ret);
3503}
3504
3505/**
3506 * xmlXPathCastNodeToString:
3507 * @node: a node
3508 *
3509 * Converts a node to its string value.
3510 *
3511 * Returns a newly allocated string.
3512 */
3513xmlChar *
3514xmlXPathCastNodeToString (xmlNodePtr node) {
3515 return(xmlNodeGetContent(node));
3516}
3517
3518/**
3519 * xmlXPathCastNodeSetToString:
3520 * @ns: a node-set
3521 *
3522 * Converts a node-set to its string value.
3523 *
3524 * Returns a newly allocated string.
3525 */
3526xmlChar *
3527xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3528 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3529 return(xmlStrdup((const xmlChar *) ""));
3530
3531 xmlXPathNodeSetSort(ns);
3532 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3533}
3534
3535/**
3536 * xmlXPathCastToString:
3537 * @val: an XPath object
3538 *
3539 * Converts an existing object to its string() equivalent
3540 *
3541 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003542 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003543 * string object).
3544 */
3545xmlChar *
3546xmlXPathCastToString(xmlXPathObjectPtr val) {
3547 xmlChar *ret = NULL;
3548
3549 if (val == NULL)
3550 return(xmlStrdup((const xmlChar *) ""));
3551 switch (val->type) {
3552 case XPATH_UNDEFINED:
3553#ifdef DEBUG_EXPR
3554 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3555#endif
3556 ret = xmlStrdup((const xmlChar *) "");
3557 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003558 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003559 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003560 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3561 break;
3562 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003563 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003564 case XPATH_BOOLEAN:
3565 ret = xmlXPathCastBooleanToString(val->boolval);
3566 break;
3567 case XPATH_NUMBER: {
3568 ret = xmlXPathCastNumberToString(val->floatval);
3569 break;
3570 }
3571 case XPATH_USERS:
3572 case XPATH_POINT:
3573 case XPATH_RANGE:
3574 case XPATH_LOCATIONSET:
3575 TODO
3576 ret = xmlStrdup((const xmlChar *) "");
3577 break;
3578 }
3579 return(ret);
3580}
3581
3582/**
3583 * xmlXPathConvertString:
3584 * @val: an XPath object
3585 *
3586 * Converts an existing object to its string() equivalent
3587 *
3588 * Returns the new object, the old one is freed (or the operation
3589 * is done directly on @val)
3590 */
3591xmlXPathObjectPtr
3592xmlXPathConvertString(xmlXPathObjectPtr val) {
3593 xmlChar *res = NULL;
3594
3595 if (val == NULL)
3596 return(xmlXPathNewCString(""));
3597
3598 switch (val->type) {
3599 case XPATH_UNDEFINED:
3600#ifdef DEBUG_EXPR
3601 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3602#endif
3603 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003604 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003605 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003606 res = xmlXPathCastNodeSetToString(val->nodesetval);
3607 break;
3608 case XPATH_STRING:
3609 return(val);
3610 case XPATH_BOOLEAN:
3611 res = xmlXPathCastBooleanToString(val->boolval);
3612 break;
3613 case XPATH_NUMBER:
3614 res = xmlXPathCastNumberToString(val->floatval);
3615 break;
3616 case XPATH_USERS:
3617 case XPATH_POINT:
3618 case XPATH_RANGE:
3619 case XPATH_LOCATIONSET:
3620 TODO;
3621 break;
3622 }
3623 xmlXPathFreeObject(val);
3624 if (res == NULL)
3625 return(xmlXPathNewCString(""));
3626 return(xmlXPathWrapString(res));
3627}
3628
3629/**
3630 * xmlXPathCastBooleanToNumber:
3631 * @val: a boolean
3632 *
3633 * Converts a boolean to its number value
3634 *
3635 * Returns the number value
3636 */
3637double
3638xmlXPathCastBooleanToNumber(int val) {
3639 if (val)
3640 return(1.0);
3641 return(0.0);
3642}
3643
3644/**
3645 * xmlXPathCastStringToNumber:
3646 * @val: a string
3647 *
3648 * Converts a string to its number value
3649 *
3650 * Returns the number value
3651 */
3652double
3653xmlXPathCastStringToNumber(const xmlChar * val) {
3654 return(xmlXPathStringEvalNumber(val));
3655}
3656
3657/**
3658 * xmlXPathCastNodeToNumber:
3659 * @node: a node
3660 *
3661 * Converts a node to its number value
3662 *
3663 * Returns the number value
3664 */
3665double
3666xmlXPathCastNodeToNumber (xmlNodePtr node) {
3667 xmlChar *strval;
3668 double ret;
3669
3670 if (node == NULL)
3671 return(xmlXPathNAN);
3672 strval = xmlXPathCastNodeToString(node);
3673 if (strval == NULL)
3674 return(xmlXPathNAN);
3675 ret = xmlXPathCastStringToNumber(strval);
3676 xmlFree(strval);
3677
3678 return(ret);
3679}
3680
3681/**
3682 * xmlXPathCastNodeSetToNumber:
3683 * @ns: a node-set
3684 *
3685 * Converts a node-set to its number value
3686 *
3687 * Returns the number value
3688 */
3689double
3690xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3691 xmlChar *str;
3692 double ret;
3693
3694 if (ns == NULL)
3695 return(xmlXPathNAN);
3696 str = xmlXPathCastNodeSetToString(ns);
3697 ret = xmlXPathCastStringToNumber(str);
3698 xmlFree(str);
3699 return(ret);
3700}
3701
3702/**
3703 * xmlXPathCastToNumber:
3704 * @val: an XPath object
3705 *
3706 * Converts an XPath object to its number value
3707 *
3708 * Returns the number value
3709 */
3710double
3711xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3712 double ret = 0.0;
3713
3714 if (val == NULL)
3715 return(xmlXPathNAN);
3716 switch (val->type) {
3717 case XPATH_UNDEFINED:
3718#ifdef DEGUB_EXPR
3719 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3720#endif
3721 ret = xmlXPathNAN;
3722 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003723 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003724 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003725 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3726 break;
3727 case XPATH_STRING:
3728 ret = xmlXPathCastStringToNumber(val->stringval);
3729 break;
3730 case XPATH_NUMBER:
3731 ret = val->floatval;
3732 break;
3733 case XPATH_BOOLEAN:
3734 ret = xmlXPathCastBooleanToNumber(val->boolval);
3735 break;
3736 case XPATH_USERS:
3737 case XPATH_POINT:
3738 case XPATH_RANGE:
3739 case XPATH_LOCATIONSET:
3740 TODO;
3741 ret = xmlXPathNAN;
3742 break;
3743 }
3744 return(ret);
3745}
3746
3747/**
3748 * xmlXPathConvertNumber:
3749 * @val: an XPath object
3750 *
3751 * Converts an existing object to its number() equivalent
3752 *
3753 * Returns the new object, the old one is freed (or the operation
3754 * is done directly on @val)
3755 */
3756xmlXPathObjectPtr
3757xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3758 xmlXPathObjectPtr ret;
3759
3760 if (val == NULL)
3761 return(xmlXPathNewFloat(0.0));
3762 if (val->type == XPATH_NUMBER)
3763 return(val);
3764 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3765 xmlXPathFreeObject(val);
3766 return(ret);
3767}
3768
3769/**
3770 * xmlXPathCastNumberToBoolean:
3771 * @val: a number
3772 *
3773 * Converts a number to its boolean value
3774 *
3775 * Returns the boolean value
3776 */
3777int
3778xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003779 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003780 return(0);
3781 return(1);
3782}
3783
3784/**
3785 * xmlXPathCastStringToBoolean:
3786 * @val: a string
3787 *
3788 * Converts a string to its boolean value
3789 *
3790 * Returns the boolean value
3791 */
3792int
3793xmlXPathCastStringToBoolean (const xmlChar *val) {
3794 if ((val == NULL) || (xmlStrlen(val) == 0))
3795 return(0);
3796 return(1);
3797}
3798
3799/**
3800 * xmlXPathCastNodeSetToBoolean:
3801 * @ns: a node-set
3802 *
3803 * Converts a node-set to its boolean value
3804 *
3805 * Returns the boolean value
3806 */
3807int
3808xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3809 if ((ns == NULL) || (ns->nodeNr == 0))
3810 return(0);
3811 return(1);
3812}
3813
3814/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003815 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003816 * @val: an XPath object
3817 *
3818 * Converts an XPath object to its boolean value
3819 *
3820 * Returns the boolean value
3821 */
3822int
3823xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3824 int ret = 0;
3825
3826 if (val == NULL)
3827 return(0);
3828 switch (val->type) {
3829 case XPATH_UNDEFINED:
3830#ifdef DEBUG_EXPR
3831 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3832#endif
3833 ret = 0;
3834 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003835 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003836 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003837 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3838 break;
3839 case XPATH_STRING:
3840 ret = xmlXPathCastStringToBoolean(val->stringval);
3841 break;
3842 case XPATH_NUMBER:
3843 ret = xmlXPathCastNumberToBoolean(val->floatval);
3844 break;
3845 case XPATH_BOOLEAN:
3846 ret = val->boolval;
3847 break;
3848 case XPATH_USERS:
3849 case XPATH_POINT:
3850 case XPATH_RANGE:
3851 case XPATH_LOCATIONSET:
3852 TODO;
3853 ret = 0;
3854 break;
3855 }
3856 return(ret);
3857}
3858
3859
3860/**
3861 * xmlXPathConvertBoolean:
3862 * @val: an XPath object
3863 *
3864 * Converts an existing object to its boolean() equivalent
3865 *
3866 * Returns the new object, the old one is freed (or the operation
3867 * is done directly on @val)
3868 */
3869xmlXPathObjectPtr
3870xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3871 xmlXPathObjectPtr ret;
3872
3873 if (val == NULL)
3874 return(xmlXPathNewBoolean(0));
3875 if (val->type == XPATH_BOOLEAN)
3876 return(val);
3877 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3878 xmlXPathFreeObject(val);
3879 return(ret);
3880}
3881
Owen Taylor3473f882001-02-23 17:55:21 +00003882/************************************************************************
3883 * *
3884 * Routines to handle XPath contexts *
3885 * *
3886 ************************************************************************/
3887
3888/**
3889 * xmlXPathNewContext:
3890 * @doc: the XML document
3891 *
3892 * Create a new xmlXPathContext
3893 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003894 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003895 */
3896xmlXPathContextPtr
3897xmlXPathNewContext(xmlDocPtr doc) {
3898 xmlXPathContextPtr ret;
3899
3900 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3901 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003902 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003903 return(NULL);
3904 }
3905 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3906 ret->doc = doc;
3907 ret->node = NULL;
3908
3909 ret->varHash = NULL;
3910
3911 ret->nb_types = 0;
3912 ret->max_types = 0;
3913 ret->types = NULL;
3914
3915 ret->funcHash = xmlHashCreate(0);
3916
3917 ret->nb_axis = 0;
3918 ret->max_axis = 0;
3919 ret->axis = NULL;
3920
3921 ret->nsHash = NULL;
3922 ret->user = NULL;
3923
3924 ret->contextSize = -1;
3925 ret->proximityPosition = -1;
3926
3927 xmlXPathRegisterAllFunctions(ret);
3928
3929 return(ret);
3930}
3931
3932/**
3933 * xmlXPathFreeContext:
3934 * @ctxt: the context to free
3935 *
3936 * Free up an xmlXPathContext
3937 */
3938void
3939xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003940 if (ctxt == NULL) return;
3941
Owen Taylor3473f882001-02-23 17:55:21 +00003942 xmlXPathRegisteredNsCleanup(ctxt);
3943 xmlXPathRegisteredFuncsCleanup(ctxt);
3944 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard7eca35f2004-11-29 13:08:03 +00003945 xmlResetError(&ctxt->lastError);
Owen Taylor3473f882001-02-23 17:55:21 +00003946 xmlFree(ctxt);
3947}
3948
3949/************************************************************************
3950 * *
3951 * Routines to handle XPath parser contexts *
3952 * *
3953 ************************************************************************/
3954
3955#define CHECK_CTXT(ctxt) \
3956 if (ctxt == NULL) { \
William M. Brackf13f77f2004-11-12 16:03:48 +00003957 __xmlRaiseError(NULL, NULL, NULL, \
3958 NULL, NULL, XML_FROM_XPATH, \
3959 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
3960 __FILE__, __LINE__, \
3961 NULL, NULL, NULL, 0, 0, \
3962 "NULL context pointer\n"); \
3963 return(NULL); \
Owen Taylor3473f882001-02-23 17:55:21 +00003964 } \
3965
3966
3967#define CHECK_CONTEXT(ctxt) \
Daniel Veillard57b25162004-11-06 14:50:18 +00003968 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
3969 (ctxt->doc->children == NULL)) { \
3970 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
Daniel Veillardce682bc2004-11-05 17:22:25 +00003971 return(NULL); \
Daniel Veillard57b25162004-11-06 14:50:18 +00003972 }
Owen Taylor3473f882001-02-23 17:55:21 +00003973
3974
3975/**
3976 * xmlXPathNewParserContext:
3977 * @str: the XPath expression
3978 * @ctxt: the XPath context
3979 *
3980 * Create a new xmlXPathParserContext
3981 *
3982 * Returns the xmlXPathParserContext just allocated.
3983 */
3984xmlXPathParserContextPtr
3985xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3986 xmlXPathParserContextPtr ret;
3987
3988 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3989 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003990 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003991 return(NULL);
3992 }
3993 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3994 ret->cur = ret->base = str;
3995 ret->context = ctxt;
3996
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003997 ret->comp = xmlXPathNewCompExpr();
3998 if (ret->comp == NULL) {
3999 xmlFree(ret->valueTab);
4000 xmlFree(ret);
4001 return(NULL);
4002 }
Daniel Veillard4773df22004-01-23 13:15:13 +00004003 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4004 ret->comp->dict = ctxt->dict;
4005 xmlDictReference(ret->comp->dict);
4006 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004007
4008 return(ret);
4009}
4010
4011/**
4012 * xmlXPathCompParserContext:
4013 * @comp: the XPath compiled expression
4014 * @ctxt: the XPath context
4015 *
4016 * Create a new xmlXPathParserContext when processing a compiled expression
4017 *
4018 * Returns the xmlXPathParserContext just allocated.
4019 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004020static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004021xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4022 xmlXPathParserContextPtr ret;
4023
4024 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4025 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004026 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004027 return(NULL);
4028 }
4029 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4030
Owen Taylor3473f882001-02-23 17:55:21 +00004031 /* Allocate the value stack */
4032 ret->valueTab = (xmlXPathObjectPtr *)
4033 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004034 if (ret->valueTab == NULL) {
4035 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004036 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004037 return(NULL);
4038 }
Owen Taylor3473f882001-02-23 17:55:21 +00004039 ret->valueNr = 0;
4040 ret->valueMax = 10;
4041 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004042
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004043 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004044 ret->comp = comp;
4045
Owen Taylor3473f882001-02-23 17:55:21 +00004046 return(ret);
4047}
4048
4049/**
4050 * xmlXPathFreeParserContext:
4051 * @ctxt: the context to free
4052 *
4053 * Free up an xmlXPathParserContext
4054 */
4055void
4056xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4057 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004058 xmlFree(ctxt->valueTab);
4059 }
Daniel Veillard56de87e2005-02-16 00:22:29 +00004060 if (ctxt->comp != NULL) {
4061#ifdef XPATH_STREAMING
4062 if (ctxt->comp->stream != NULL) {
4063 xmlFreePatternList(ctxt->comp->stream);
4064 ctxt->comp->stream = NULL;
4065 }
4066#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004067 xmlXPathFreeCompExpr(ctxt->comp);
Daniel Veillard56de87e2005-02-16 00:22:29 +00004068 }
Owen Taylor3473f882001-02-23 17:55:21 +00004069 xmlFree(ctxt);
4070}
4071
4072/************************************************************************
4073 * *
4074 * The implicit core function library *
4075 * *
4076 ************************************************************************/
4077
Owen Taylor3473f882001-02-23 17:55:21 +00004078/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004079 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004080 * @node: a node pointer
4081 *
4082 * Function computing the beginning of the string value of the node,
4083 * used to speed up comparisons
4084 *
4085 * Returns an int usable as a hash
4086 */
4087static unsigned int
4088xmlXPathNodeValHash(xmlNodePtr node) {
4089 int len = 2;
4090 const xmlChar * string = NULL;
4091 xmlNodePtr tmp = NULL;
4092 unsigned int ret = 0;
4093
4094 if (node == NULL)
4095 return(0);
4096
Daniel Veillard9adc0462003-03-24 18:39:54 +00004097 if (node->type == XML_DOCUMENT_NODE) {
4098 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4099 if (tmp == NULL)
4100 node = node->children;
4101 else
4102 node = tmp;
4103
4104 if (node == NULL)
4105 return(0);
4106 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004107
4108 switch (node->type) {
4109 case XML_COMMENT_NODE:
4110 case XML_PI_NODE:
4111 case XML_CDATA_SECTION_NODE:
4112 case XML_TEXT_NODE:
4113 string = node->content;
4114 if (string == NULL)
4115 return(0);
4116 if (string[0] == 0)
4117 return(0);
4118 return(((unsigned int) string[0]) +
4119 (((unsigned int) string[1]) << 8));
4120 case XML_NAMESPACE_DECL:
4121 string = ((xmlNsPtr)node)->href;
4122 if (string == NULL)
4123 return(0);
4124 if (string[0] == 0)
4125 return(0);
4126 return(((unsigned int) string[0]) +
4127 (((unsigned int) string[1]) << 8));
4128 case XML_ATTRIBUTE_NODE:
4129 tmp = ((xmlAttrPtr) node)->children;
4130 break;
4131 case XML_ELEMENT_NODE:
4132 tmp = node->children;
4133 break;
4134 default:
4135 return(0);
4136 }
4137 while (tmp != NULL) {
4138 switch (tmp->type) {
4139 case XML_COMMENT_NODE:
4140 case XML_PI_NODE:
4141 case XML_CDATA_SECTION_NODE:
4142 case XML_TEXT_NODE:
4143 string = tmp->content;
4144 break;
4145 case XML_NAMESPACE_DECL:
4146 string = ((xmlNsPtr)tmp)->href;
4147 break;
4148 default:
4149 break;
4150 }
4151 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004152 if (len == 1) {
4153 return(ret + (((unsigned int) string[0]) << 8));
4154 }
4155 if (string[1] == 0) {
4156 len = 1;
4157 ret = (unsigned int) string[0];
4158 } else {
4159 return(((unsigned int) string[0]) +
4160 (((unsigned int) string[1]) << 8));
4161 }
4162 }
4163 /*
4164 * Skip to next node
4165 */
4166 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4167 if (tmp->children->type != XML_ENTITY_DECL) {
4168 tmp = tmp->children;
4169 continue;
4170 }
4171 }
4172 if (tmp == node)
4173 break;
4174
4175 if (tmp->next != NULL) {
4176 tmp = tmp->next;
4177 continue;
4178 }
4179
4180 do {
4181 tmp = tmp->parent;
4182 if (tmp == NULL)
4183 break;
4184 if (tmp == node) {
4185 tmp = NULL;
4186 break;
4187 }
4188 if (tmp->next != NULL) {
4189 tmp = tmp->next;
4190 break;
4191 }
4192 } while (tmp != NULL);
4193 }
4194 return(ret);
4195}
4196
4197/**
4198 * xmlXPathStringHash:
4199 * @string: a string
4200 *
4201 * Function computing the beginning of the string value of the node,
4202 * used to speed up comparisons
4203 *
4204 * Returns an int usable as a hash
4205 */
4206static unsigned int
4207xmlXPathStringHash(const xmlChar * string) {
4208 if (string == NULL)
4209 return((unsigned int) 0);
4210 if (string[0] == 0)
4211 return(0);
4212 return(((unsigned int) string[0]) +
4213 (((unsigned int) string[1]) << 8));
4214}
4215
4216/**
Owen Taylor3473f882001-02-23 17:55:21 +00004217 * xmlXPathCompareNodeSetFloat:
4218 * @ctxt: the XPath Parser context
4219 * @inf: less than (1) or greater than (0)
4220 * @strict: is the comparison strict
4221 * @arg: the node set
4222 * @f: the value
4223 *
4224 * Implement the compare operation between a nodeset and a number
4225 * @ns < @val (1, 1, ...
4226 * @ns <= @val (1, 0, ...
4227 * @ns > @val (0, 1, ...
4228 * @ns >= @val (0, 0, ...
4229 *
4230 * If one object to be compared is a node-set and the other is a number,
4231 * then the comparison will be true if and only if there is a node in the
4232 * node-set such that the result of performing the comparison on the number
4233 * to be compared and on the result of converting the string-value of that
4234 * node to a number using the number function is true.
4235 *
4236 * Returns 0 or 1 depending on the results of the test.
4237 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004238static int
Owen Taylor3473f882001-02-23 17:55:21 +00004239xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4240 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4241 int i, ret = 0;
4242 xmlNodeSetPtr ns;
4243 xmlChar *str2;
4244
4245 if ((f == NULL) || (arg == NULL) ||
4246 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4247 xmlXPathFreeObject(arg);
4248 xmlXPathFreeObject(f);
4249 return(0);
4250 }
4251 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004252 if (ns != NULL) {
4253 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004254 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004255 if (str2 != NULL) {
4256 valuePush(ctxt,
4257 xmlXPathNewString(str2));
4258 xmlFree(str2);
4259 xmlXPathNumberFunction(ctxt, 1);
4260 valuePush(ctxt, xmlXPathObjectCopy(f));
4261 ret = xmlXPathCompareValues(ctxt, inf, strict);
4262 if (ret)
4263 break;
4264 }
4265 }
Owen Taylor3473f882001-02-23 17:55:21 +00004266 }
4267 xmlXPathFreeObject(arg);
4268 xmlXPathFreeObject(f);
4269 return(ret);
4270}
4271
4272/**
4273 * xmlXPathCompareNodeSetString:
4274 * @ctxt: the XPath Parser context
4275 * @inf: less than (1) or greater than (0)
4276 * @strict: is the comparison strict
4277 * @arg: the node set
4278 * @s: the value
4279 *
4280 * Implement the compare operation between a nodeset and a string
4281 * @ns < @val (1, 1, ...
4282 * @ns <= @val (1, 0, ...
4283 * @ns > @val (0, 1, ...
4284 * @ns >= @val (0, 0, ...
4285 *
4286 * If one object to be compared is a node-set and the other is a string,
4287 * then the comparison will be true if and only if there is a node in
4288 * the node-set such that the result of performing the comparison on the
4289 * string-value of the node and the other string is true.
4290 *
4291 * Returns 0 or 1 depending on the results of the test.
4292 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004293static int
Owen Taylor3473f882001-02-23 17:55:21 +00004294xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4295 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4296 int i, ret = 0;
4297 xmlNodeSetPtr ns;
4298 xmlChar *str2;
4299
4300 if ((s == NULL) || (arg == NULL) ||
4301 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4302 xmlXPathFreeObject(arg);
4303 xmlXPathFreeObject(s);
4304 return(0);
4305 }
4306 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004307 if (ns != NULL) {
4308 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004309 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004310 if (str2 != NULL) {
4311 valuePush(ctxt,
4312 xmlXPathNewString(str2));
4313 xmlFree(str2);
4314 valuePush(ctxt, xmlXPathObjectCopy(s));
4315 ret = xmlXPathCompareValues(ctxt, inf, strict);
4316 if (ret)
4317 break;
4318 }
4319 }
Owen Taylor3473f882001-02-23 17:55:21 +00004320 }
4321 xmlXPathFreeObject(arg);
4322 xmlXPathFreeObject(s);
4323 return(ret);
4324}
4325
4326/**
4327 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004328 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004329 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004330 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004331 * @arg2: the second node set object
4332 *
4333 * Implement the compare operation on nodesets:
4334 *
4335 * If both objects to be compared are node-sets, then the comparison
4336 * will be true if and only if there is a node in the first node-set
4337 * and a node in the second node-set such that the result of performing
4338 * the comparison on the string-values of the two nodes is true.
4339 * ....
4340 * When neither object to be compared is a node-set and the operator
4341 * is <=, <, >= or >, then the objects are compared by converting both
4342 * objects to numbers and comparing the numbers according to IEEE 754.
4343 * ....
4344 * The number function converts its argument to a number as follows:
4345 * - a string that consists of optional whitespace followed by an
4346 * optional minus sign followed by a Number followed by whitespace
4347 * is converted to the IEEE 754 number that is nearest (according
4348 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4349 * represented by the string; any other string is converted to NaN
4350 *
4351 * Conclusion all nodes need to be converted first to their string value
4352 * and then the comparison must be done when possible
4353 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004354static int
4355xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004356 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4357 int i, j, init = 0;
4358 double val1;
4359 double *values2;
4360 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004361 xmlNodeSetPtr ns1;
4362 xmlNodeSetPtr ns2;
4363
4364 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004365 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4366 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004367 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004368 }
Owen Taylor3473f882001-02-23 17:55:21 +00004369 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004370 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4371 xmlXPathFreeObject(arg1);
4372 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004373 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004374 }
Owen Taylor3473f882001-02-23 17:55:21 +00004375
4376 ns1 = arg1->nodesetval;
4377 ns2 = arg2->nodesetval;
4378
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004379 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004380 xmlXPathFreeObject(arg1);
4381 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004382 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004383 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004384 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004385 xmlXPathFreeObject(arg1);
4386 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004387 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004388 }
Owen Taylor3473f882001-02-23 17:55:21 +00004389
4390 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4391 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004392 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004393 xmlXPathFreeObject(arg1);
4394 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004395 return(0);
4396 }
4397 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004398 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004399 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004400 continue;
4401 for (j = 0;j < ns2->nodeNr;j++) {
4402 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004403 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004404 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004405 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004406 continue;
4407 if (inf && strict)
4408 ret = (val1 < values2[j]);
4409 else if (inf && !strict)
4410 ret = (val1 <= values2[j]);
4411 else if (!inf && strict)
4412 ret = (val1 > values2[j]);
4413 else if (!inf && !strict)
4414 ret = (val1 >= values2[j]);
4415 if (ret)
4416 break;
4417 }
4418 if (ret)
4419 break;
4420 init = 1;
4421 }
4422 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004423 xmlXPathFreeObject(arg1);
4424 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004425 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004426}
4427
4428/**
4429 * xmlXPathCompareNodeSetValue:
4430 * @ctxt: the XPath Parser context
4431 * @inf: less than (1) or greater than (0)
4432 * @strict: is the comparison strict
4433 * @arg: the node set
4434 * @val: the value
4435 *
4436 * Implement the compare operation between a nodeset and a value
4437 * @ns < @val (1, 1, ...
4438 * @ns <= @val (1, 0, ...
4439 * @ns > @val (0, 1, ...
4440 * @ns >= @val (0, 0, ...
4441 *
4442 * If one object to be compared is a node-set and the other is a boolean,
4443 * then the comparison will be true if and only if the result of performing
4444 * the comparison on the boolean and on the result of converting
4445 * the node-set to a boolean using the boolean function is true.
4446 *
4447 * Returns 0 or 1 depending on the results of the test.
4448 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004449static int
Owen Taylor3473f882001-02-23 17:55:21 +00004450xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4451 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4452 if ((val == NULL) || (arg == NULL) ||
4453 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4454 return(0);
4455
4456 switch(val->type) {
4457 case XPATH_NUMBER:
4458 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4459 case XPATH_NODESET:
4460 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004461 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004462 case XPATH_STRING:
4463 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4464 case XPATH_BOOLEAN:
4465 valuePush(ctxt, arg);
4466 xmlXPathBooleanFunction(ctxt, 1);
4467 valuePush(ctxt, val);
4468 return(xmlXPathCompareValues(ctxt, inf, strict));
4469 default:
4470 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004471 }
4472 return(0);
4473}
4474
4475/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004476 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004477 * @arg: the nodeset object argument
4478 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004479 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004480 *
4481 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4482 * If one object to be compared is a node-set and the other is a string,
4483 * then the comparison will be true if and only if there is a node in
4484 * the node-set such that the result of performing the comparison on the
4485 * string-value of the node and the other string is true.
4486 *
4487 * Returns 0 or 1 depending on the results of the test.
4488 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004489static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004490xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004491{
Owen Taylor3473f882001-02-23 17:55:21 +00004492 int i;
4493 xmlNodeSetPtr ns;
4494 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004495 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004496
4497 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004498 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4499 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004500 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004501 /*
4502 * A NULL nodeset compared with a string is always false
4503 * (since there is no node equal, and no node not equal)
4504 */
4505 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004506 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004507 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004508 for (i = 0; i < ns->nodeNr; i++) {
4509 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4510 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4511 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4512 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004513 if (neq)
4514 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004515 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004516 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4517 if (neq)
4518 continue;
4519 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004520 } else if (neq) {
4521 if (str2 != NULL)
4522 xmlFree(str2);
4523 return (1);
4524 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004525 if (str2 != NULL)
4526 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004527 } else if (neq)
4528 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004529 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004530 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004531}
4532
4533/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004534 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004535 * @arg: the nodeset object argument
4536 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004537 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004538 *
4539 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4540 * If one object to be compared is a node-set and the other is a number,
4541 * then the comparison will be true if and only if there is a node in
4542 * the node-set such that the result of performing the comparison on the
4543 * number to be compared and on the result of converting the string-value
4544 * of that node to a number using the number function is true.
4545 *
4546 * Returns 0 or 1 depending on the results of the test.
4547 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004548static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004549xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4550 xmlXPathObjectPtr arg, double f, int neq) {
4551 int i, ret=0;
4552 xmlNodeSetPtr ns;
4553 xmlChar *str2;
4554 xmlXPathObjectPtr val;
4555 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004556
4557 if ((arg == NULL) ||
4558 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4559 return(0);
4560
William M. Brack0c022ad2002-07-12 00:56:01 +00004561 ns = arg->nodesetval;
4562 if (ns != NULL) {
4563 for (i=0;i<ns->nodeNr;i++) {
4564 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4565 if (str2 != NULL) {
4566 valuePush(ctxt, xmlXPathNewString(str2));
4567 xmlFree(str2);
4568 xmlXPathNumberFunction(ctxt, 1);
4569 val = valuePop(ctxt);
4570 v = val->floatval;
4571 xmlXPathFreeObject(val);
4572 if (!xmlXPathIsNaN(v)) {
4573 if ((!neq) && (v==f)) {
4574 ret = 1;
4575 break;
4576 } else if ((neq) && (v!=f)) {
4577 ret = 1;
4578 break;
4579 }
William M. Brack32f0f712005-07-14 07:00:33 +00004580 } else { /* NaN is unequal to any value */
4581 if (neq)
4582 ret = 1;
William M. Brack0c022ad2002-07-12 00:56:01 +00004583 }
4584 }
4585 }
4586 }
4587
4588 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004589}
4590
4591
4592/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004593 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004594 * @arg1: first nodeset object argument
4595 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004596 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004597 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004598 * Implement the equal / not equal operation on XPath nodesets:
4599 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004600 * If both objects to be compared are node-sets, then the comparison
4601 * will be true if and only if there is a node in the first node-set and
4602 * a node in the second node-set such that the result of performing the
4603 * comparison on the string-values of the two nodes is true.
4604 *
4605 * (needless to say, this is a costly operation)
4606 *
4607 * Returns 0 or 1 depending on the results of the test.
4608 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004609static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004610xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004611 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004612 unsigned int *hashs1;
4613 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004614 xmlChar **values1;
4615 xmlChar **values2;
4616 int ret = 0;
4617 xmlNodeSetPtr ns1;
4618 xmlNodeSetPtr ns2;
4619
4620 if ((arg1 == NULL) ||
4621 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4622 return(0);
4623 if ((arg2 == NULL) ||
4624 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4625 return(0);
4626
4627 ns1 = arg1->nodesetval;
4628 ns2 = arg2->nodesetval;
4629
Daniel Veillard911f49a2001-04-07 15:39:35 +00004630 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004631 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004632 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004633 return(0);
4634
4635 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004636 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004637 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004638 if (neq == 0)
4639 for (i = 0;i < ns1->nodeNr;i++)
4640 for (j = 0;j < ns2->nodeNr;j++)
4641 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4642 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004643
4644 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004645 if (values1 == NULL) {
4646 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004647 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004648 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004649 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4650 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004651 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004652 xmlFree(values1);
4653 return(0);
4654 }
Owen Taylor3473f882001-02-23 17:55:21 +00004655 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4656 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4657 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004658 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004659 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004660 xmlFree(values1);
4661 return(0);
4662 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004663 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4664 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004665 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004666 xmlFree(hashs1);
4667 xmlFree(values1);
4668 xmlFree(values2);
4669 return(0);
4670 }
Owen Taylor3473f882001-02-23 17:55:21 +00004671 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4672 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004673 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004674 for (j = 0;j < ns2->nodeNr;j++) {
4675 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004676 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004677 if (hashs1[i] != hashs2[j]) {
4678 if (neq) {
4679 ret = 1;
4680 break;
4681 }
4682 }
4683 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004684 if (values1[i] == NULL)
4685 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4686 if (values2[j] == NULL)
4687 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004688 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004689 if (ret)
4690 break;
4691 }
Owen Taylor3473f882001-02-23 17:55:21 +00004692 }
4693 if (ret)
4694 break;
4695 }
4696 for (i = 0;i < ns1->nodeNr;i++)
4697 if (values1[i] != NULL)
4698 xmlFree(values1[i]);
4699 for (j = 0;j < ns2->nodeNr;j++)
4700 if (values2[j] != NULL)
4701 xmlFree(values2[j]);
4702 xmlFree(values1);
4703 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004704 xmlFree(hashs1);
4705 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004706 return(ret);
4707}
4708
William M. Brack0c022ad2002-07-12 00:56:01 +00004709static int
4710xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4711 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004712 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004713 /*
4714 *At this point we are assured neither arg1 nor arg2
4715 *is a nodeset, so we can just pick the appropriate routine.
4716 */
Owen Taylor3473f882001-02-23 17:55:21 +00004717 switch (arg1->type) {
4718 case XPATH_UNDEFINED:
4719#ifdef DEBUG_EXPR
4720 xmlGenericError(xmlGenericErrorContext,
4721 "Equal: undefined\n");
4722#endif
4723 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004724 case XPATH_BOOLEAN:
4725 switch (arg2->type) {
4726 case XPATH_UNDEFINED:
4727#ifdef DEBUG_EXPR
4728 xmlGenericError(xmlGenericErrorContext,
4729 "Equal: undefined\n");
4730#endif
4731 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004732 case XPATH_BOOLEAN:
4733#ifdef DEBUG_EXPR
4734 xmlGenericError(xmlGenericErrorContext,
4735 "Equal: %d boolean %d \n",
4736 arg1->boolval, arg2->boolval);
4737#endif
4738 ret = (arg1->boolval == arg2->boolval);
4739 break;
4740 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004741 ret = (arg1->boolval ==
4742 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004743 break;
4744 case XPATH_STRING:
4745 if ((arg2->stringval == NULL) ||
4746 (arg2->stringval[0] == 0)) ret = 0;
4747 else
4748 ret = 1;
4749 ret = (arg1->boolval == ret);
4750 break;
4751 case XPATH_USERS:
4752 case XPATH_POINT:
4753 case XPATH_RANGE:
4754 case XPATH_LOCATIONSET:
4755 TODO
4756 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004757 case XPATH_NODESET:
4758 case XPATH_XSLT_TREE:
4759 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004760 }
4761 break;
4762 case XPATH_NUMBER:
4763 switch (arg2->type) {
4764 case XPATH_UNDEFINED:
4765#ifdef DEBUG_EXPR
4766 xmlGenericError(xmlGenericErrorContext,
4767 "Equal: undefined\n");
4768#endif
4769 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004770 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004771 ret = (arg2->boolval==
4772 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004773 break;
4774 case XPATH_STRING:
4775 valuePush(ctxt, arg2);
4776 xmlXPathNumberFunction(ctxt, 1);
4777 arg2 = valuePop(ctxt);
4778 /* no break on purpose */
4779 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004780 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004781 if (xmlXPathIsNaN(arg1->floatval) ||
4782 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004783 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004784 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4785 if (xmlXPathIsInf(arg2->floatval) == 1)
4786 ret = 1;
4787 else
4788 ret = 0;
4789 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4790 if (xmlXPathIsInf(arg2->floatval) == -1)
4791 ret = 1;
4792 else
4793 ret = 0;
4794 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4795 if (xmlXPathIsInf(arg1->floatval) == 1)
4796 ret = 1;
4797 else
4798 ret = 0;
4799 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4800 if (xmlXPathIsInf(arg1->floatval) == -1)
4801 ret = 1;
4802 else
4803 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004804 } else {
4805 ret = (arg1->floatval == arg2->floatval);
4806 }
Owen Taylor3473f882001-02-23 17:55:21 +00004807 break;
4808 case XPATH_USERS:
4809 case XPATH_POINT:
4810 case XPATH_RANGE:
4811 case XPATH_LOCATIONSET:
4812 TODO
4813 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004814 case XPATH_NODESET:
4815 case XPATH_XSLT_TREE:
4816 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004817 }
4818 break;
4819 case XPATH_STRING:
4820 switch (arg2->type) {
4821 case XPATH_UNDEFINED:
4822#ifdef DEBUG_EXPR
4823 xmlGenericError(xmlGenericErrorContext,
4824 "Equal: undefined\n");
4825#endif
4826 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004827 case XPATH_BOOLEAN:
4828 if ((arg1->stringval == NULL) ||
4829 (arg1->stringval[0] == 0)) ret = 0;
4830 else
4831 ret = 1;
4832 ret = (arg2->boolval == ret);
4833 break;
4834 case XPATH_STRING:
4835 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4836 break;
4837 case XPATH_NUMBER:
4838 valuePush(ctxt, arg1);
4839 xmlXPathNumberFunction(ctxt, 1);
4840 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004841 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004842 if (xmlXPathIsNaN(arg1->floatval) ||
4843 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004844 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004845 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4846 if (xmlXPathIsInf(arg2->floatval) == 1)
4847 ret = 1;
4848 else
4849 ret = 0;
4850 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4851 if (xmlXPathIsInf(arg2->floatval) == -1)
4852 ret = 1;
4853 else
4854 ret = 0;
4855 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4856 if (xmlXPathIsInf(arg1->floatval) == 1)
4857 ret = 1;
4858 else
4859 ret = 0;
4860 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4861 if (xmlXPathIsInf(arg1->floatval) == -1)
4862 ret = 1;
4863 else
4864 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004865 } else {
4866 ret = (arg1->floatval == arg2->floatval);
4867 }
Owen Taylor3473f882001-02-23 17:55:21 +00004868 break;
4869 case XPATH_USERS:
4870 case XPATH_POINT:
4871 case XPATH_RANGE:
4872 case XPATH_LOCATIONSET:
4873 TODO
4874 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004875 case XPATH_NODESET:
4876 case XPATH_XSLT_TREE:
4877 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004878 }
4879 break;
4880 case XPATH_USERS:
4881 case XPATH_POINT:
4882 case XPATH_RANGE:
4883 case XPATH_LOCATIONSET:
4884 TODO
4885 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004886 case XPATH_NODESET:
4887 case XPATH_XSLT_TREE:
4888 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004889 }
4890 xmlXPathFreeObject(arg1);
4891 xmlXPathFreeObject(arg2);
4892 return(ret);
4893}
4894
William M. Brack0c022ad2002-07-12 00:56:01 +00004895/**
4896 * xmlXPathEqualValues:
4897 * @ctxt: the XPath Parser context
4898 *
4899 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4900 *
4901 * Returns 0 or 1 depending on the results of the test.
4902 */
4903int
4904xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4905 xmlXPathObjectPtr arg1, arg2, argtmp;
4906 int ret = 0;
4907
Daniel Veillard6128c012004-11-08 17:16:15 +00004908 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004909 arg2 = valuePop(ctxt);
4910 arg1 = valuePop(ctxt);
4911 if ((arg1 == NULL) || (arg2 == NULL)) {
4912 if (arg1 != NULL)
4913 xmlXPathFreeObject(arg1);
4914 else
4915 xmlXPathFreeObject(arg2);
4916 XP_ERROR0(XPATH_INVALID_OPERAND);
4917 }
4918
4919 if (arg1 == arg2) {
4920#ifdef DEBUG_EXPR
4921 xmlGenericError(xmlGenericErrorContext,
4922 "Equal: by pointer\n");
4923#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00004924 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004925 return(1);
4926 }
4927
4928 /*
4929 *If either argument is a nodeset, it's a 'special case'
4930 */
4931 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4932 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4933 /*
4934 *Hack it to assure arg1 is the nodeset
4935 */
4936 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4937 argtmp = arg2;
4938 arg2 = arg1;
4939 arg1 = argtmp;
4940 }
4941 switch (arg2->type) {
4942 case XPATH_UNDEFINED:
4943#ifdef DEBUG_EXPR
4944 xmlGenericError(xmlGenericErrorContext,
4945 "Equal: undefined\n");
4946#endif
4947 break;
4948 case XPATH_NODESET:
4949 case XPATH_XSLT_TREE:
4950 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4951 break;
4952 case XPATH_BOOLEAN:
4953 if ((arg1->nodesetval == NULL) ||
4954 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4955 else
4956 ret = 1;
4957 ret = (ret == arg2->boolval);
4958 break;
4959 case XPATH_NUMBER:
4960 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4961 break;
4962 case XPATH_STRING:
4963 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4964 break;
4965 case XPATH_USERS:
4966 case XPATH_POINT:
4967 case XPATH_RANGE:
4968 case XPATH_LOCATIONSET:
4969 TODO
4970 break;
4971 }
4972 xmlXPathFreeObject(arg1);
4973 xmlXPathFreeObject(arg2);
4974 return(ret);
4975 }
4976
4977 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4978}
4979
4980/**
4981 * xmlXPathNotEqualValues:
4982 * @ctxt: the XPath Parser context
4983 *
4984 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4985 *
4986 * Returns 0 or 1 depending on the results of the test.
4987 */
4988int
4989xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4990 xmlXPathObjectPtr arg1, arg2, argtmp;
4991 int ret = 0;
4992
Daniel Veillard6128c012004-11-08 17:16:15 +00004993 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004994 arg2 = valuePop(ctxt);
4995 arg1 = valuePop(ctxt);
4996 if ((arg1 == NULL) || (arg2 == NULL)) {
4997 if (arg1 != NULL)
4998 xmlXPathFreeObject(arg1);
4999 else
5000 xmlXPathFreeObject(arg2);
5001 XP_ERROR0(XPATH_INVALID_OPERAND);
5002 }
5003
5004 if (arg1 == arg2) {
5005#ifdef DEBUG_EXPR
5006 xmlGenericError(xmlGenericErrorContext,
5007 "NotEqual: by pointer\n");
5008#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005009 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005010 return(0);
5011 }
5012
5013 /*
5014 *If either argument is a nodeset, it's a 'special case'
5015 */
5016 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5017 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5018 /*
5019 *Hack it to assure arg1 is the nodeset
5020 */
5021 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5022 argtmp = arg2;
5023 arg2 = arg1;
5024 arg1 = argtmp;
5025 }
5026 switch (arg2->type) {
5027 case XPATH_UNDEFINED:
5028#ifdef DEBUG_EXPR
5029 xmlGenericError(xmlGenericErrorContext,
5030 "NotEqual: undefined\n");
5031#endif
5032 break;
5033 case XPATH_NODESET:
5034 case XPATH_XSLT_TREE:
5035 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5036 break;
5037 case XPATH_BOOLEAN:
5038 if ((arg1->nodesetval == NULL) ||
5039 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5040 else
5041 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005042 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005043 break;
5044 case XPATH_NUMBER:
5045 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5046 break;
5047 case XPATH_STRING:
5048 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5049 break;
5050 case XPATH_USERS:
5051 case XPATH_POINT:
5052 case XPATH_RANGE:
5053 case XPATH_LOCATIONSET:
5054 TODO
5055 break;
5056 }
5057 xmlXPathFreeObject(arg1);
5058 xmlXPathFreeObject(arg2);
5059 return(ret);
5060 }
5061
5062 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5063}
Owen Taylor3473f882001-02-23 17:55:21 +00005064
5065/**
5066 * xmlXPathCompareValues:
5067 * @ctxt: the XPath Parser context
5068 * @inf: less than (1) or greater than (0)
5069 * @strict: is the comparison strict
5070 *
5071 * Implement the compare operation on XPath objects:
5072 * @arg1 < @arg2 (1, 1, ...
5073 * @arg1 <= @arg2 (1, 0, ...
5074 * @arg1 > @arg2 (0, 1, ...
5075 * @arg1 >= @arg2 (0, 0, ...
5076 *
5077 * When neither object to be compared is a node-set and the operator is
5078 * <=, <, >=, >, then the objects are compared by converted both objects
5079 * to numbers and comparing the numbers according to IEEE 754. The <
5080 * comparison will be true if and only if the first number is less than the
5081 * second number. The <= comparison will be true if and only if the first
5082 * number is less than or equal to the second number. The > comparison
5083 * will be true if and only if the first number is greater than the second
5084 * number. The >= comparison will be true if and only if the first number
5085 * is greater than or equal to the second number.
5086 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005087 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005088 */
5089int
5090xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005091 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005092 xmlXPathObjectPtr arg1, arg2;
5093
Daniel Veillard6128c012004-11-08 17:16:15 +00005094 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005095 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005096 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005097 if ((arg1 == NULL) || (arg2 == NULL)) {
5098 if (arg1 != NULL)
5099 xmlXPathFreeObject(arg1);
5100 else
5101 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005102 XP_ERROR0(XPATH_INVALID_OPERAND);
5103 }
5104
William M. Brack0c022ad2002-07-12 00:56:01 +00005105 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5106 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00005107 /*
5108 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5109 * are not freed from within this routine; they will be freed from the
5110 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5111 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005112 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5113 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005114 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005115 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005116 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005117 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5118 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005119 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005120 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5121 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005122 }
5123 }
5124 return(ret);
5125 }
5126
5127 if (arg1->type != XPATH_NUMBER) {
5128 valuePush(ctxt, arg1);
5129 xmlXPathNumberFunction(ctxt, 1);
5130 arg1 = valuePop(ctxt);
5131 }
5132 if (arg1->type != XPATH_NUMBER) {
5133 xmlXPathFreeObject(arg1);
5134 xmlXPathFreeObject(arg2);
5135 XP_ERROR0(XPATH_INVALID_OPERAND);
5136 }
5137 if (arg2->type != XPATH_NUMBER) {
5138 valuePush(ctxt, arg2);
5139 xmlXPathNumberFunction(ctxt, 1);
5140 arg2 = valuePop(ctxt);
5141 }
5142 if (arg2->type != XPATH_NUMBER) {
5143 xmlXPathFreeObject(arg1);
5144 xmlXPathFreeObject(arg2);
5145 XP_ERROR0(XPATH_INVALID_OPERAND);
5146 }
5147 /*
5148 * Add tests for infinity and nan
5149 * => feedback on 3.4 for Inf and NaN
5150 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005151 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005152 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005153 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005154 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005155 arg1i=xmlXPathIsInf(arg1->floatval);
5156 arg2i=xmlXPathIsInf(arg2->floatval);
5157 if (inf && strict) {
5158 if ((arg1i == -1 && arg2i != -1) ||
5159 (arg2i == 1 && arg1i != 1)) {
5160 ret = 1;
5161 } else if (arg1i == 0 && arg2i == 0) {
5162 ret = (arg1->floatval < arg2->floatval);
5163 } else {
5164 ret = 0;
5165 }
5166 }
5167 else if (inf && !strict) {
5168 if (arg1i == -1 || arg2i == 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 (arg2i == -1 && arg1i != -1)) {
5179 ret = 1;
5180 } else if (arg1i == 0 && arg2i == 0) {
5181 ret = (arg1->floatval > arg2->floatval);
5182 } else {
5183 ret = 0;
5184 }
5185 }
5186 else if (!inf && !strict) {
5187 if (arg1i == 1 || arg2i == -1) {
5188 ret = 1;
5189 } else if (arg1i == 0 && arg2i == 0) {
5190 ret = (arg1->floatval >= arg2->floatval);
5191 } else {
5192 ret = 0;
5193 }
5194 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005195 }
Owen Taylor3473f882001-02-23 17:55:21 +00005196 xmlXPathFreeObject(arg1);
5197 xmlXPathFreeObject(arg2);
5198 return(ret);
5199}
5200
5201/**
5202 * xmlXPathValueFlipSign:
5203 * @ctxt: the XPath Parser context
5204 *
5205 * Implement the unary - operation on an XPath object
5206 * The numeric operators convert their operands to numbers as if
5207 * by calling the number function.
5208 */
5209void
5210xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005211 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005212 CAST_TO_NUMBER;
5213 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005214 if (xmlXPathIsNaN(ctxt->value->floatval))
5215 ctxt->value->floatval=xmlXPathNAN;
5216 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5217 ctxt->value->floatval=xmlXPathNINF;
5218 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5219 ctxt->value->floatval=xmlXPathPINF;
5220 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005221 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5222 ctxt->value->floatval = xmlXPathNZERO;
5223 else
5224 ctxt->value->floatval = 0;
5225 }
5226 else
5227 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005228}
5229
5230/**
5231 * xmlXPathAddValues:
5232 * @ctxt: the XPath Parser context
5233 *
5234 * Implement the add operation on XPath objects:
5235 * The numeric operators convert their operands to numbers as if
5236 * by calling the number function.
5237 */
5238void
5239xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5240 xmlXPathObjectPtr arg;
5241 double val;
5242
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005243 arg = valuePop(ctxt);
5244 if (arg == NULL)
5245 XP_ERROR(XPATH_INVALID_OPERAND);
5246 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005247 xmlXPathFreeObject(arg);
5248
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005249 CAST_TO_NUMBER;
5250 CHECK_TYPE(XPATH_NUMBER);
5251 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005252}
5253
5254/**
5255 * xmlXPathSubValues:
5256 * @ctxt: the XPath Parser context
5257 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005258 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005259 * The numeric operators convert their operands to numbers as if
5260 * by calling the number function.
5261 */
5262void
5263xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5264 xmlXPathObjectPtr arg;
5265 double val;
5266
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005267 arg = valuePop(ctxt);
5268 if (arg == NULL)
5269 XP_ERROR(XPATH_INVALID_OPERAND);
5270 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005271 xmlXPathFreeObject(arg);
5272
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005273 CAST_TO_NUMBER;
5274 CHECK_TYPE(XPATH_NUMBER);
5275 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005276}
5277
5278/**
5279 * xmlXPathMultValues:
5280 * @ctxt: the XPath Parser context
5281 *
5282 * Implement the multiply operation on XPath objects:
5283 * The numeric operators convert their operands to numbers as if
5284 * by calling the number function.
5285 */
5286void
5287xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5288 xmlXPathObjectPtr arg;
5289 double val;
5290
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005291 arg = valuePop(ctxt);
5292 if (arg == NULL)
5293 XP_ERROR(XPATH_INVALID_OPERAND);
5294 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005295 xmlXPathFreeObject(arg);
5296
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005297 CAST_TO_NUMBER;
5298 CHECK_TYPE(XPATH_NUMBER);
5299 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005300}
5301
5302/**
5303 * xmlXPathDivValues:
5304 * @ctxt: the XPath Parser context
5305 *
5306 * Implement the div operation on XPath objects @arg1 / @arg2:
5307 * The numeric operators convert their operands to numbers as if
5308 * by calling the number function.
5309 */
5310void
5311xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5312 xmlXPathObjectPtr arg;
5313 double val;
5314
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005315 arg = valuePop(ctxt);
5316 if (arg == NULL)
5317 XP_ERROR(XPATH_INVALID_OPERAND);
5318 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005319 xmlXPathFreeObject(arg);
5320
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005321 CAST_TO_NUMBER;
5322 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005323 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5324 ctxt->value->floatval = xmlXPathNAN;
5325 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005326 if (ctxt->value->floatval == 0)
5327 ctxt->value->floatval = xmlXPathNAN;
5328 else if (ctxt->value->floatval > 0)
5329 ctxt->value->floatval = xmlXPathNINF;
5330 else if (ctxt->value->floatval < 0)
5331 ctxt->value->floatval = xmlXPathPINF;
5332 }
5333 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005334 if (ctxt->value->floatval == 0)
5335 ctxt->value->floatval = xmlXPathNAN;
5336 else if (ctxt->value->floatval > 0)
5337 ctxt->value->floatval = xmlXPathPINF;
5338 else if (ctxt->value->floatval < 0)
5339 ctxt->value->floatval = xmlXPathNINF;
5340 } else
5341 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005342}
5343
5344/**
5345 * xmlXPathModValues:
5346 * @ctxt: the XPath Parser context
5347 *
5348 * Implement the mod operation on XPath objects: @arg1 / @arg2
5349 * The numeric operators convert their operands to numbers as if
5350 * by calling the number function.
5351 */
5352void
5353xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5354 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005355 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005356
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005357 arg = valuePop(ctxt);
5358 if (arg == NULL)
5359 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005360 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005361 xmlXPathFreeObject(arg);
5362
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005363 CAST_TO_NUMBER;
5364 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005365 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005366 if (arg2 == 0)
5367 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005368 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005369 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005370 }
Owen Taylor3473f882001-02-23 17:55:21 +00005371}
5372
5373/************************************************************************
5374 * *
5375 * The traversal functions *
5376 * *
5377 ************************************************************************/
5378
Owen Taylor3473f882001-02-23 17:55:21 +00005379/*
5380 * A traversal function enumerates nodes along an axis.
5381 * Initially it must be called with NULL, and it indicates
5382 * termination on the axis by returning NULL.
5383 */
5384typedef xmlNodePtr (*xmlXPathTraversalFunction)
5385 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5386
5387/**
5388 * xmlXPathNextSelf:
5389 * @ctxt: the XPath Parser context
5390 * @cur: the current node in the traversal
5391 *
5392 * Traversal function for the "self" direction
5393 * The self axis contains just the context node itself
5394 *
5395 * Returns the next element following that axis
5396 */
5397xmlNodePtr
5398xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005399 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005400 if (cur == NULL)
5401 return(ctxt->context->node);
5402 return(NULL);
5403}
5404
5405/**
5406 * xmlXPathNextChild:
5407 * @ctxt: the XPath Parser context
5408 * @cur: the current node in the traversal
5409 *
5410 * Traversal function for the "child" direction
5411 * The child axis contains the children of the context node in document order.
5412 *
5413 * Returns the next element following that axis
5414 */
5415xmlNodePtr
5416xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005417 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005418 if (cur == NULL) {
5419 if (ctxt->context->node == NULL) return(NULL);
5420 switch (ctxt->context->node->type) {
5421 case XML_ELEMENT_NODE:
5422 case XML_TEXT_NODE:
5423 case XML_CDATA_SECTION_NODE:
5424 case XML_ENTITY_REF_NODE:
5425 case XML_ENTITY_NODE:
5426 case XML_PI_NODE:
5427 case XML_COMMENT_NODE:
5428 case XML_NOTATION_NODE:
5429 case XML_DTD_NODE:
5430 return(ctxt->context->node->children);
5431 case XML_DOCUMENT_NODE:
5432 case XML_DOCUMENT_TYPE_NODE:
5433 case XML_DOCUMENT_FRAG_NODE:
5434 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005435#ifdef LIBXML_DOCB_ENABLED
5436 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005437#endif
5438 return(((xmlDocPtr) ctxt->context->node)->children);
5439 case XML_ELEMENT_DECL:
5440 case XML_ATTRIBUTE_DECL:
5441 case XML_ENTITY_DECL:
5442 case XML_ATTRIBUTE_NODE:
5443 case XML_NAMESPACE_DECL:
5444 case XML_XINCLUDE_START:
5445 case XML_XINCLUDE_END:
5446 return(NULL);
5447 }
5448 return(NULL);
5449 }
5450 if ((cur->type == XML_DOCUMENT_NODE) ||
5451 (cur->type == XML_HTML_DOCUMENT_NODE))
5452 return(NULL);
5453 return(cur->next);
5454}
5455
5456/**
5457 * xmlXPathNextDescendant:
5458 * @ctxt: the XPath Parser context
5459 * @cur: the current node in the traversal
5460 *
5461 * Traversal function for the "descendant" direction
5462 * the descendant axis contains the descendants of the context node in document
5463 * order; a descendant is a child or a child of a child and so on.
5464 *
5465 * Returns the next element following that axis
5466 */
5467xmlNodePtr
5468xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005469 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005470 if (cur == NULL) {
5471 if (ctxt->context->node == NULL)
5472 return(NULL);
5473 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5474 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5475 return(NULL);
5476
5477 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5478 return(ctxt->context->doc->children);
5479 return(ctxt->context->node->children);
5480 }
5481
Daniel Veillard567e1b42001-08-01 15:53:47 +00005482 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005483 /*
5484 * Do not descend on entities declarations
5485 */
5486 if (cur->children->type != XML_ENTITY_DECL) {
5487 cur = cur->children;
5488 /*
5489 * Skip DTDs
5490 */
5491 if (cur->type != XML_DTD_NODE)
5492 return(cur);
5493 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005494 }
5495
5496 if (cur == ctxt->context->node) return(NULL);
5497
Daniel Veillard68e9e742002-11-16 15:35:11 +00005498 while (cur->next != NULL) {
5499 cur = cur->next;
5500 if ((cur->type != XML_ENTITY_DECL) &&
5501 (cur->type != XML_DTD_NODE))
5502 return(cur);
5503 }
Owen Taylor3473f882001-02-23 17:55:21 +00005504
5505 do {
5506 cur = cur->parent;
5507 if (cur == NULL) return(NULL);
5508 if (cur == ctxt->context->node) return(NULL);
5509 if (cur->next != NULL) {
5510 cur = cur->next;
5511 return(cur);
5512 }
5513 } while (cur != NULL);
5514 return(cur);
5515}
5516
5517/**
5518 * xmlXPathNextDescendantOrSelf:
5519 * @ctxt: the XPath Parser context
5520 * @cur: the current node in the traversal
5521 *
5522 * Traversal function for the "descendant-or-self" direction
5523 * the descendant-or-self axis contains the context node and the descendants
5524 * of the context node in document order; thus the context node is the first
5525 * node on the axis, and the first child of the context node is the second node
5526 * on the axis
5527 *
5528 * Returns the next element following that axis
5529 */
5530xmlNodePtr
5531xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005532 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005533 if (cur == NULL) {
5534 if (ctxt->context->node == NULL)
5535 return(NULL);
5536 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5537 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5538 return(NULL);
5539 return(ctxt->context->node);
5540 }
5541
5542 return(xmlXPathNextDescendant(ctxt, cur));
5543}
5544
5545/**
5546 * xmlXPathNextParent:
5547 * @ctxt: the XPath Parser context
5548 * @cur: the current node in the traversal
5549 *
5550 * Traversal function for the "parent" direction
5551 * The parent axis contains the parent of the context node, if there is one.
5552 *
5553 * Returns the next element following that axis
5554 */
5555xmlNodePtr
5556xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005557 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005558 /*
5559 * the parent of an attribute or namespace node is the element
5560 * to which the attribute or namespace node is attached
5561 * Namespace handling !!!
5562 */
5563 if (cur == NULL) {
5564 if (ctxt->context->node == NULL) return(NULL);
5565 switch (ctxt->context->node->type) {
5566 case XML_ELEMENT_NODE:
5567 case XML_TEXT_NODE:
5568 case XML_CDATA_SECTION_NODE:
5569 case XML_ENTITY_REF_NODE:
5570 case XML_ENTITY_NODE:
5571 case XML_PI_NODE:
5572 case XML_COMMENT_NODE:
5573 case XML_NOTATION_NODE:
5574 case XML_DTD_NODE:
5575 case XML_ELEMENT_DECL:
5576 case XML_ATTRIBUTE_DECL:
5577 case XML_XINCLUDE_START:
5578 case XML_XINCLUDE_END:
5579 case XML_ENTITY_DECL:
5580 if (ctxt->context->node->parent == NULL)
5581 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005582 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005583 ((ctxt->context->node->parent->name[0] == ' ') ||
5584 (xmlStrEqual(ctxt->context->node->parent->name,
5585 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005586 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005587 return(ctxt->context->node->parent);
5588 case XML_ATTRIBUTE_NODE: {
5589 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5590
5591 return(att->parent);
5592 }
5593 case XML_DOCUMENT_NODE:
5594 case XML_DOCUMENT_TYPE_NODE:
5595 case XML_DOCUMENT_FRAG_NODE:
5596 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005597#ifdef LIBXML_DOCB_ENABLED
5598 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005599#endif
5600 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005601 case XML_NAMESPACE_DECL: {
5602 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5603
5604 if ((ns->next != NULL) &&
5605 (ns->next->type != XML_NAMESPACE_DECL))
5606 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005607 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005608 }
Owen Taylor3473f882001-02-23 17:55:21 +00005609 }
5610 }
5611 return(NULL);
5612}
5613
5614/**
5615 * xmlXPathNextAncestor:
5616 * @ctxt: the XPath Parser context
5617 * @cur: the current node in the traversal
5618 *
5619 * Traversal function for the "ancestor" direction
5620 * the ancestor axis contains the ancestors of the context node; the ancestors
5621 * of the context node consist of the parent of context node and the parent's
5622 * parent and so on; the nodes are ordered in reverse document order; thus the
5623 * parent is the first node on the axis, and the parent's parent is the second
5624 * node on the axis
5625 *
5626 * Returns the next element following that axis
5627 */
5628xmlNodePtr
5629xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005630 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005631 /*
5632 * the parent of an attribute or namespace node is the element
5633 * to which the attribute or namespace node is attached
5634 * !!!!!!!!!!!!!
5635 */
5636 if (cur == NULL) {
5637 if (ctxt->context->node == NULL) return(NULL);
5638 switch (ctxt->context->node->type) {
5639 case XML_ELEMENT_NODE:
5640 case XML_TEXT_NODE:
5641 case XML_CDATA_SECTION_NODE:
5642 case XML_ENTITY_REF_NODE:
5643 case XML_ENTITY_NODE:
5644 case XML_PI_NODE:
5645 case XML_COMMENT_NODE:
5646 case XML_DTD_NODE:
5647 case XML_ELEMENT_DECL:
5648 case XML_ATTRIBUTE_DECL:
5649 case XML_ENTITY_DECL:
5650 case XML_NOTATION_NODE:
5651 case XML_XINCLUDE_START:
5652 case XML_XINCLUDE_END:
5653 if (ctxt->context->node->parent == NULL)
5654 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005655 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005656 ((ctxt->context->node->parent->name[0] == ' ') ||
5657 (xmlStrEqual(ctxt->context->node->parent->name,
5658 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005659 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005660 return(ctxt->context->node->parent);
5661 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005662 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005663
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005664 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005665 }
5666 case XML_DOCUMENT_NODE:
5667 case XML_DOCUMENT_TYPE_NODE:
5668 case XML_DOCUMENT_FRAG_NODE:
5669 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005670#ifdef LIBXML_DOCB_ENABLED
5671 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005672#endif
5673 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005674 case XML_NAMESPACE_DECL: {
5675 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5676
5677 if ((ns->next != NULL) &&
5678 (ns->next->type != XML_NAMESPACE_DECL))
5679 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005680 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005681 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005682 }
Owen Taylor3473f882001-02-23 17:55:21 +00005683 }
5684 return(NULL);
5685 }
5686 if (cur == ctxt->context->doc->children)
5687 return((xmlNodePtr) ctxt->context->doc);
5688 if (cur == (xmlNodePtr) ctxt->context->doc)
5689 return(NULL);
5690 switch (cur->type) {
5691 case XML_ELEMENT_NODE:
5692 case XML_TEXT_NODE:
5693 case XML_CDATA_SECTION_NODE:
5694 case XML_ENTITY_REF_NODE:
5695 case XML_ENTITY_NODE:
5696 case XML_PI_NODE:
5697 case XML_COMMENT_NODE:
5698 case XML_NOTATION_NODE:
5699 case XML_DTD_NODE:
5700 case XML_ELEMENT_DECL:
5701 case XML_ATTRIBUTE_DECL:
5702 case XML_ENTITY_DECL:
5703 case XML_XINCLUDE_START:
5704 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005705 if (cur->parent == NULL)
5706 return(NULL);
5707 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005708 ((cur->parent->name[0] == ' ') ||
5709 (xmlStrEqual(cur->parent->name,
5710 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005711 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005712 return(cur->parent);
5713 case XML_ATTRIBUTE_NODE: {
5714 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5715
5716 return(att->parent);
5717 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005718 case XML_NAMESPACE_DECL: {
5719 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5720
5721 if ((ns->next != NULL) &&
5722 (ns->next->type != XML_NAMESPACE_DECL))
5723 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005724 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005725 return(NULL);
5726 }
Owen Taylor3473f882001-02-23 17:55:21 +00005727 case XML_DOCUMENT_NODE:
5728 case XML_DOCUMENT_TYPE_NODE:
5729 case XML_DOCUMENT_FRAG_NODE:
5730 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005731#ifdef LIBXML_DOCB_ENABLED
5732 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005733#endif
5734 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005735 }
5736 return(NULL);
5737}
5738
5739/**
5740 * xmlXPathNextAncestorOrSelf:
5741 * @ctxt: the XPath Parser context
5742 * @cur: the current node in the traversal
5743 *
5744 * Traversal function for the "ancestor-or-self" direction
5745 * he ancestor-or-self axis contains the context node and ancestors of
5746 * the context node in reverse document order; thus the context node is
5747 * the first node on the axis, and the context node's parent the second;
5748 * parent here is defined the same as with the parent axis.
5749 *
5750 * Returns the next element following that axis
5751 */
5752xmlNodePtr
5753xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005754 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005755 if (cur == NULL)
5756 return(ctxt->context->node);
5757 return(xmlXPathNextAncestor(ctxt, cur));
5758}
5759
5760/**
5761 * xmlXPathNextFollowingSibling:
5762 * @ctxt: the XPath Parser context
5763 * @cur: the current node in the traversal
5764 *
5765 * Traversal function for the "following-sibling" direction
5766 * The following-sibling axis contains the following siblings of the context
5767 * node in document order.
5768 *
5769 * Returns the next element following that axis
5770 */
5771xmlNodePtr
5772xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005773 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005774 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5775 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5776 return(NULL);
5777 if (cur == (xmlNodePtr) ctxt->context->doc)
5778 return(NULL);
5779 if (cur == NULL)
5780 return(ctxt->context->node->next);
5781 return(cur->next);
5782}
5783
5784/**
5785 * xmlXPathNextPrecedingSibling:
5786 * @ctxt: the XPath Parser context
5787 * @cur: the current node in the traversal
5788 *
5789 * Traversal function for the "preceding-sibling" direction
5790 * The preceding-sibling axis contains the preceding siblings of the context
5791 * node in reverse document order; the first preceding sibling is first on the
5792 * axis; the sibling preceding that node is the second on the axis and so on.
5793 *
5794 * Returns the next element following that axis
5795 */
5796xmlNodePtr
5797xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005798 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005799 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5800 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5801 return(NULL);
5802 if (cur == (xmlNodePtr) ctxt->context->doc)
5803 return(NULL);
5804 if (cur == NULL)
5805 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005806 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5807 cur = cur->prev;
5808 if (cur == NULL)
5809 return(ctxt->context->node->prev);
5810 }
Owen Taylor3473f882001-02-23 17:55:21 +00005811 return(cur->prev);
5812}
5813
5814/**
5815 * xmlXPathNextFollowing:
5816 * @ctxt: the XPath Parser context
5817 * @cur: the current node in the traversal
5818 *
5819 * Traversal function for the "following" direction
5820 * The following axis contains all nodes in the same document as the context
5821 * node that are after the context node in document order, excluding any
5822 * descendants and excluding attribute nodes and namespace nodes; the nodes
5823 * are ordered in document order
5824 *
5825 * Returns the next element following that axis
5826 */
5827xmlNodePtr
5828xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005829 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005830 if (cur != NULL && cur->children != NULL)
5831 return cur->children ;
5832 if (cur == NULL) cur = ctxt->context->node;
5833 if (cur == NULL) return(NULL) ; /* ERROR */
5834 if (cur->next != NULL) return(cur->next) ;
5835 do {
5836 cur = cur->parent;
5837 if (cur == NULL) return(NULL);
5838 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5839 if (cur->next != NULL) return(cur->next);
5840 } while (cur != NULL);
5841 return(cur);
5842}
5843
5844/*
5845 * xmlXPathIsAncestor:
5846 * @ancestor: the ancestor node
5847 * @node: the current node
5848 *
5849 * Check that @ancestor is a @node's ancestor
5850 *
5851 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5852 */
5853static int
5854xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5855 if ((ancestor == NULL) || (node == NULL)) return(0);
5856 /* nodes need to be in the same document */
5857 if (ancestor->doc != node->doc) return(0);
5858 /* avoid searching if ancestor or node is the root node */
5859 if (ancestor == (xmlNodePtr) node->doc) return(1);
5860 if (node == (xmlNodePtr) ancestor->doc) return(0);
5861 while (node->parent != NULL) {
5862 if (node->parent == ancestor)
5863 return(1);
5864 node = node->parent;
5865 }
5866 return(0);
5867}
5868
5869/**
5870 * xmlXPathNextPreceding:
5871 * @ctxt: the XPath Parser context
5872 * @cur: the current node in the traversal
5873 *
5874 * Traversal function for the "preceding" direction
5875 * the preceding axis contains all nodes in the same document as the context
5876 * node that are before the context node in document order, excluding any
5877 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5878 * ordered in reverse document order
5879 *
5880 * Returns the next element following that axis
5881 */
5882xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005883xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5884{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005885 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005886 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005887 cur = ctxt->context->node;
5888 if (cur == NULL)
5889 return (NULL);
5890 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5891 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005892 do {
5893 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005894 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5895 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005896 }
5897
5898 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005899 if (cur == NULL)
5900 return (NULL);
5901 if (cur == ctxt->context->doc->children)
5902 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005903 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005904 return (cur);
5905}
5906
5907/**
5908 * xmlXPathNextPrecedingInternal:
5909 * @ctxt: the XPath Parser context
5910 * @cur: the current node in the traversal
5911 *
5912 * Traversal function for the "preceding" direction
5913 * the preceding axis contains all nodes in the same document as the context
5914 * node that are before the context node in document order, excluding any
5915 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5916 * ordered in reverse document order
5917 * This is a faster implementation but internal only since it requires a
5918 * state kept in the parser context: ctxt->ancestor.
5919 *
5920 * Returns the next element following that axis
5921 */
5922static xmlNodePtr
5923xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5924 xmlNodePtr cur)
5925{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005926 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005927 if (cur == NULL) {
5928 cur = ctxt->context->node;
5929 if (cur == NULL)
5930 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005931 if (cur->type == XML_NAMESPACE_DECL)
5932 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005933 ctxt->ancestor = cur->parent;
5934 }
5935 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5936 cur = cur->prev;
5937 while (cur->prev == NULL) {
5938 cur = cur->parent;
5939 if (cur == NULL)
5940 return (NULL);
5941 if (cur == ctxt->context->doc->children)
5942 return (NULL);
5943 if (cur != ctxt->ancestor)
5944 return (cur);
5945 ctxt->ancestor = cur->parent;
5946 }
5947 cur = cur->prev;
5948 while (cur->last != NULL)
5949 cur = cur->last;
5950 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005951}
5952
5953/**
5954 * xmlXPathNextNamespace:
5955 * @ctxt: the XPath Parser context
5956 * @cur: the current attribute in the traversal
5957 *
5958 * Traversal function for the "namespace" direction
5959 * the namespace axis contains the namespace nodes of the context node;
5960 * the order of nodes on this axis is implementation-defined; the axis will
5961 * be empty unless the context node is an element
5962 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005963 * We keep the XML namespace node at the end of the list.
5964 *
Owen Taylor3473f882001-02-23 17:55:21 +00005965 * Returns the next element following that axis
5966 */
5967xmlNodePtr
5968xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005969 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005970 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005971 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005972 if (ctxt->context->tmpNsList != NULL)
5973 xmlFree(ctxt->context->tmpNsList);
5974 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005975 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005976 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005977 if (ctxt->context->tmpNsList != NULL) {
5978 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5979 ctxt->context->tmpNsNr++;
5980 }
5981 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005982 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005983 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005984 if (ctxt->context->tmpNsNr > 0) {
5985 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5986 } else {
5987 if (ctxt->context->tmpNsList != NULL)
5988 xmlFree(ctxt->context->tmpNsList);
5989 ctxt->context->tmpNsList = NULL;
5990 return(NULL);
5991 }
Owen Taylor3473f882001-02-23 17:55:21 +00005992}
5993
5994/**
5995 * xmlXPathNextAttribute:
5996 * @ctxt: the XPath Parser context
5997 * @cur: the current attribute in the traversal
5998 *
5999 * Traversal function for the "attribute" direction
6000 * TODO: support DTD inherited default attributes
6001 *
6002 * Returns the next element following that axis
6003 */
6004xmlNodePtr
6005xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006006 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006007 if (ctxt->context->node == NULL)
6008 return(NULL);
6009 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6010 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006011 if (cur == NULL) {
6012 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6013 return(NULL);
6014 return((xmlNodePtr)ctxt->context->node->properties);
6015 }
6016 return((xmlNodePtr)cur->next);
6017}
6018
6019/************************************************************************
6020 * *
6021 * NodeTest Functions *
6022 * *
6023 ************************************************************************/
6024
Owen Taylor3473f882001-02-23 17:55:21 +00006025#define IS_FUNCTION 200
6026
Owen Taylor3473f882001-02-23 17:55:21 +00006027
6028/************************************************************************
6029 * *
6030 * Implicit tree core function library *
6031 * *
6032 ************************************************************************/
6033
6034/**
6035 * xmlXPathRoot:
6036 * @ctxt: the XPath Parser context
6037 *
6038 * Initialize the context to the root of the document
6039 */
6040void
6041xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006042 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006043 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6044 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6045}
6046
6047/************************************************************************
6048 * *
6049 * The explicit core function library *
6050 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6051 * *
6052 ************************************************************************/
6053
6054
6055/**
6056 * xmlXPathLastFunction:
6057 * @ctxt: the XPath Parser context
6058 * @nargs: the number of arguments
6059 *
6060 * Implement the last() XPath function
6061 * number last()
6062 * The last function returns the number of nodes in the context node list.
6063 */
6064void
6065xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6066 CHECK_ARITY(0);
6067 if (ctxt->context->contextSize >= 0) {
6068 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6069#ifdef DEBUG_EXPR
6070 xmlGenericError(xmlGenericErrorContext,
6071 "last() : %d\n", ctxt->context->contextSize);
6072#endif
6073 } else {
6074 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6075 }
6076}
6077
6078/**
6079 * xmlXPathPositionFunction:
6080 * @ctxt: the XPath Parser context
6081 * @nargs: the number of arguments
6082 *
6083 * Implement the position() XPath function
6084 * number position()
6085 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006086 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006087 * will be equal to last().
6088 */
6089void
6090xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6091 CHECK_ARITY(0);
6092 if (ctxt->context->proximityPosition >= 0) {
6093 valuePush(ctxt,
6094 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6095#ifdef DEBUG_EXPR
6096 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6097 ctxt->context->proximityPosition);
6098#endif
6099 } else {
6100 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6101 }
6102}
6103
6104/**
6105 * xmlXPathCountFunction:
6106 * @ctxt: the XPath Parser context
6107 * @nargs: the number of arguments
6108 *
6109 * Implement the count() XPath function
6110 * number count(node-set)
6111 */
6112void
6113xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6114 xmlXPathObjectPtr cur;
6115
6116 CHECK_ARITY(1);
6117 if ((ctxt->value == NULL) ||
6118 ((ctxt->value->type != XPATH_NODESET) &&
6119 (ctxt->value->type != XPATH_XSLT_TREE)))
6120 XP_ERROR(XPATH_INVALID_TYPE);
6121 cur = valuePop(ctxt);
6122
Daniel Veillard911f49a2001-04-07 15:39:35 +00006123 if ((cur == NULL) || (cur->nodesetval == NULL))
6124 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006125 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006126 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006127 } else {
6128 if ((cur->nodesetval->nodeNr != 1) ||
6129 (cur->nodesetval->nodeTab == NULL)) {
6130 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6131 } else {
6132 xmlNodePtr tmp;
6133 int i = 0;
6134
6135 tmp = cur->nodesetval->nodeTab[0];
6136 if (tmp != NULL) {
6137 tmp = tmp->children;
6138 while (tmp != NULL) {
6139 tmp = tmp->next;
6140 i++;
6141 }
6142 }
6143 valuePush(ctxt, xmlXPathNewFloat((double) i));
6144 }
6145 }
Owen Taylor3473f882001-02-23 17:55:21 +00006146 xmlXPathFreeObject(cur);
6147}
6148
6149/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006150 * xmlXPathGetElementsByIds:
6151 * @doc: the document
6152 * @ids: a whitespace separated list of IDs
6153 *
6154 * Selects elements by their unique ID.
6155 *
6156 * Returns a node-set of selected elements.
6157 */
6158static xmlNodeSetPtr
6159xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6160 xmlNodeSetPtr ret;
6161 const xmlChar *cur = ids;
6162 xmlChar *ID;
6163 xmlAttrPtr attr;
6164 xmlNodePtr elem = NULL;
6165
Daniel Veillard7a985a12003-07-06 17:57:42 +00006166 if (ids == NULL) return(NULL);
6167
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006168 ret = xmlXPathNodeSetCreate(NULL);
6169
William M. Brack76e95df2003-10-18 16:20:14 +00006170 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006171 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006172 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006173 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006174
6175 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006176 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006177 /*
6178 * We used to check the fact that the value passed
6179 * was an NCName, but this generated much troubles for
6180 * me and Aleksey Sanin, people blatantly violated that
6181 * constaint, like Visa3D spec.
6182 * if (xmlValidateNCName(ID, 1) == 0)
6183 */
6184 attr = xmlGetID(doc, ID);
6185 if (attr != NULL) {
6186 if (attr->type == XML_ATTRIBUTE_NODE)
6187 elem = attr->parent;
6188 else if (attr->type == XML_ELEMENT_NODE)
6189 elem = (xmlNodePtr) attr;
6190 else
6191 elem = NULL;
6192 if (elem != NULL)
6193 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006194 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006195 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006196 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006197
William M. Brack76e95df2003-10-18 16:20:14 +00006198 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006199 ids = cur;
6200 }
6201 return(ret);
6202}
6203
6204/**
Owen Taylor3473f882001-02-23 17:55:21 +00006205 * xmlXPathIdFunction:
6206 * @ctxt: the XPath Parser context
6207 * @nargs: the number of arguments
6208 *
6209 * Implement the id() XPath function
6210 * node-set id(object)
6211 * The id function selects elements by their unique ID
6212 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6213 * then the result is the union of the result of applying id to the
6214 * string value of each of the nodes in the argument node-set. When the
6215 * argument to id is of any other type, the argument is converted to a
6216 * string as if by a call to the string function; the string is split
6217 * into a whitespace-separated list of tokens (whitespace is any sequence
6218 * of characters matching the production S); the result is a node-set
6219 * containing the elements in the same document as the context node that
6220 * have a unique ID equal to any of the tokens in the list.
6221 */
6222void
6223xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006224 xmlChar *tokens;
6225 xmlNodeSetPtr ret;
6226 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006227
6228 CHECK_ARITY(1);
6229 obj = valuePop(ctxt);
6230 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006231 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006232 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006233 int i;
6234
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006235 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006236
Daniel Veillard911f49a2001-04-07 15:39:35 +00006237 if (obj->nodesetval != NULL) {
6238 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006239 tokens =
6240 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6241 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6242 ret = xmlXPathNodeSetMerge(ret, ns);
6243 xmlXPathFreeNodeSet(ns);
6244 if (tokens != NULL)
6245 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006246 }
Owen Taylor3473f882001-02-23 17:55:21 +00006247 }
6248
6249 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006250 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006251 return;
6252 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006253 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006254
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006255 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6256 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006257
Owen Taylor3473f882001-02-23 17:55:21 +00006258 xmlXPathFreeObject(obj);
6259 return;
6260}
6261
6262/**
6263 * xmlXPathLocalNameFunction:
6264 * @ctxt: the XPath Parser context
6265 * @nargs: the number of arguments
6266 *
6267 * Implement the local-name() XPath function
6268 * string local-name(node-set?)
6269 * The local-name function returns a string containing the local part
6270 * of the name of the node in the argument node-set that is first in
6271 * document order. If the node-set is empty or the first node has no
6272 * name, an empty string is returned. If the argument is omitted it
6273 * defaults to the context node.
6274 */
6275void
6276xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6277 xmlXPathObjectPtr cur;
6278
Daniel Veillarda82b1822004-11-08 16:24:57 +00006279 if (ctxt == NULL) return;
6280
Owen Taylor3473f882001-02-23 17:55:21 +00006281 if (nargs == 0) {
6282 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6283 nargs = 1;
6284 }
6285
6286 CHECK_ARITY(1);
6287 if ((ctxt->value == NULL) ||
6288 ((ctxt->value->type != XPATH_NODESET) &&
6289 (ctxt->value->type != XPATH_XSLT_TREE)))
6290 XP_ERROR(XPATH_INVALID_TYPE);
6291 cur = valuePop(ctxt);
6292
Daniel Veillard911f49a2001-04-07 15:39:35 +00006293 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006294 valuePush(ctxt, xmlXPathNewCString(""));
6295 } else {
6296 int i = 0; /* Should be first in document order !!!!! */
6297 switch (cur->nodesetval->nodeTab[i]->type) {
6298 case XML_ELEMENT_NODE:
6299 case XML_ATTRIBUTE_NODE:
6300 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006301 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6302 valuePush(ctxt, xmlXPathNewCString(""));
6303 else
6304 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006305 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6306 break;
6307 case XML_NAMESPACE_DECL:
6308 valuePush(ctxt, xmlXPathNewString(
6309 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6310 break;
6311 default:
6312 valuePush(ctxt, xmlXPathNewCString(""));
6313 }
6314 }
6315 xmlXPathFreeObject(cur);
6316}
6317
6318/**
6319 * xmlXPathNamespaceURIFunction:
6320 * @ctxt: the XPath Parser context
6321 * @nargs: the number of arguments
6322 *
6323 * Implement the namespace-uri() XPath function
6324 * string namespace-uri(node-set?)
6325 * The namespace-uri function returns a string containing the
6326 * namespace URI of the expanded name of the node in the argument
6327 * node-set that is first in document order. If the node-set is empty,
6328 * the first node has no name, or the expanded name has no namespace
6329 * URI, an empty string is returned. If the argument is omitted it
6330 * defaults to the context node.
6331 */
6332void
6333xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6334 xmlXPathObjectPtr cur;
6335
Daniel Veillarda82b1822004-11-08 16:24:57 +00006336 if (ctxt == NULL) return;
6337
Owen Taylor3473f882001-02-23 17:55:21 +00006338 if (nargs == 0) {
6339 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6340 nargs = 1;
6341 }
6342 CHECK_ARITY(1);
6343 if ((ctxt->value == NULL) ||
6344 ((ctxt->value->type != XPATH_NODESET) &&
6345 (ctxt->value->type != XPATH_XSLT_TREE)))
6346 XP_ERROR(XPATH_INVALID_TYPE);
6347 cur = valuePop(ctxt);
6348
Daniel Veillard911f49a2001-04-07 15:39:35 +00006349 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006350 valuePush(ctxt, xmlXPathNewCString(""));
6351 } else {
6352 int i = 0; /* Should be first in document order !!!!! */
6353 switch (cur->nodesetval->nodeTab[i]->type) {
6354 case XML_ELEMENT_NODE:
6355 case XML_ATTRIBUTE_NODE:
6356 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6357 valuePush(ctxt, xmlXPathNewCString(""));
6358 else
6359 valuePush(ctxt, xmlXPathNewString(
6360 cur->nodesetval->nodeTab[i]->ns->href));
6361 break;
6362 default:
6363 valuePush(ctxt, xmlXPathNewCString(""));
6364 }
6365 }
6366 xmlXPathFreeObject(cur);
6367}
6368
6369/**
6370 * xmlXPathNameFunction:
6371 * @ctxt: the XPath Parser context
6372 * @nargs: the number of arguments
6373 *
6374 * Implement the name() XPath function
6375 * string name(node-set?)
6376 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006377 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006378 * order. The QName must represent the name with respect to the namespace
6379 * declarations in effect on the node whose name is being represented.
6380 * Typically, this will be the form in which the name occurred in the XML
6381 * source. This need not be the case if there are namespace declarations
6382 * in effect on the node that associate multiple prefixes with the same
6383 * namespace. However, an implementation may include information about
6384 * the original prefix in its representation of nodes; in this case, an
6385 * implementation can ensure that the returned string is always the same
6386 * as the QName used in the XML source. If the argument it omitted it
6387 * defaults to the context node.
6388 * Libxml keep the original prefix so the "real qualified name" used is
6389 * returned.
6390 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006391static void
Daniel Veillard04383752001-07-08 14:27:15 +00006392xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6393{
Owen Taylor3473f882001-02-23 17:55:21 +00006394 xmlXPathObjectPtr cur;
6395
6396 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006397 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6398 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006399 }
6400
6401 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006402 if ((ctxt->value == NULL) ||
6403 ((ctxt->value->type != XPATH_NODESET) &&
6404 (ctxt->value->type != XPATH_XSLT_TREE)))
6405 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006406 cur = valuePop(ctxt);
6407
Daniel Veillard911f49a2001-04-07 15:39:35 +00006408 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006409 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006410 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006411 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006412
Daniel Veillard04383752001-07-08 14:27:15 +00006413 switch (cur->nodesetval->nodeTab[i]->type) {
6414 case XML_ELEMENT_NODE:
6415 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006416 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6417 valuePush(ctxt, xmlXPathNewCString(""));
6418 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6419 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006420 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006421 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006422
Daniel Veillard652d8a92003-02-04 19:28:49 +00006423 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006424 xmlChar *fullname;
6425
6426 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6427 cur->nodesetval->nodeTab[i]->ns->prefix,
6428 NULL, 0);
6429 if (fullname == cur->nodesetval->nodeTab[i]->name)
6430 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6431 if (fullname == NULL) {
6432 XP_ERROR(XPATH_MEMORY_ERROR);
6433 }
6434 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006435 }
6436 break;
6437 default:
6438 valuePush(ctxt,
6439 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6440 xmlXPathLocalNameFunction(ctxt, 1);
6441 }
Owen Taylor3473f882001-02-23 17:55:21 +00006442 }
6443 xmlXPathFreeObject(cur);
6444}
6445
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006446
6447/**
Owen Taylor3473f882001-02-23 17:55:21 +00006448 * xmlXPathStringFunction:
6449 * @ctxt: the XPath Parser context
6450 * @nargs: the number of arguments
6451 *
6452 * Implement the string() XPath function
6453 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006454 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006455 * - A node-set is converted to a string by returning the value of
6456 * the node in the node-set that is first in document order.
6457 * If the node-set is empty, an empty string is returned.
6458 * - A number is converted to a string as follows
6459 * + NaN is converted to the string NaN
6460 * + positive zero is converted to the string 0
6461 * + negative zero is converted to the string 0
6462 * + positive infinity is converted to the string Infinity
6463 * + negative infinity is converted to the string -Infinity
6464 * + if the number is an integer, the number is represented in
6465 * decimal form as a Number with no decimal point and no leading
6466 * zeros, preceded by a minus sign (-) if the number is negative
6467 * + otherwise, the number is represented in decimal form as a
6468 * Number including a decimal point with at least one digit
6469 * before the decimal point and at least one digit after the
6470 * decimal point, preceded by a minus sign (-) if the number
6471 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006472 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006473 * before the decimal point; beyond the one required digit
6474 * after the decimal point there must be as many, but only as
6475 * many, more digits as are needed to uniquely distinguish the
6476 * number from all other IEEE 754 numeric values.
6477 * - The boolean false value is converted to the string false.
6478 * The boolean true value is converted to the string true.
6479 *
6480 * If the argument is omitted, it defaults to a node-set with the
6481 * context node as its only member.
6482 */
6483void
6484xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6485 xmlXPathObjectPtr cur;
6486
Daniel Veillarda82b1822004-11-08 16:24:57 +00006487 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006488 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006489 valuePush(ctxt,
6490 xmlXPathWrapString(
6491 xmlXPathCastNodeToString(ctxt->context->node)));
6492 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006493 }
6494
6495 CHECK_ARITY(1);
6496 cur = valuePop(ctxt);
6497 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006498 cur = xmlXPathConvertString(cur);
6499 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006500}
6501
6502/**
6503 * xmlXPathStringLengthFunction:
6504 * @ctxt: the XPath Parser context
6505 * @nargs: the number of arguments
6506 *
6507 * Implement the string-length() XPath function
6508 * number string-length(string?)
6509 * The string-length returns the number of characters in the string
6510 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6511 * the context node converted to a string, in other words the value
6512 * of the context node.
6513 */
6514void
6515xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6516 xmlXPathObjectPtr cur;
6517
6518 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006519 if ((ctxt == NULL) || (ctxt->context == NULL))
6520 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006521 if (ctxt->context->node == NULL) {
6522 valuePush(ctxt, xmlXPathNewFloat(0));
6523 } else {
6524 xmlChar *content;
6525
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006526 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006527 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006528 xmlFree(content);
6529 }
6530 return;
6531 }
6532 CHECK_ARITY(1);
6533 CAST_TO_STRING;
6534 CHECK_TYPE(XPATH_STRING);
6535 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006536 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006537 xmlXPathFreeObject(cur);
6538}
6539
6540/**
6541 * xmlXPathConcatFunction:
6542 * @ctxt: the XPath Parser context
6543 * @nargs: the number of arguments
6544 *
6545 * Implement the concat() XPath function
6546 * string concat(string, string, string*)
6547 * The concat function returns the concatenation of its arguments.
6548 */
6549void
6550xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6551 xmlXPathObjectPtr cur, newobj;
6552 xmlChar *tmp;
6553
Daniel Veillarda82b1822004-11-08 16:24:57 +00006554 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006555 if (nargs < 2) {
6556 CHECK_ARITY(2);
6557 }
6558
6559 CAST_TO_STRING;
6560 cur = valuePop(ctxt);
6561 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6562 xmlXPathFreeObject(cur);
6563 return;
6564 }
6565 nargs--;
6566
6567 while (nargs > 0) {
6568 CAST_TO_STRING;
6569 newobj = valuePop(ctxt);
6570 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6571 xmlXPathFreeObject(newobj);
6572 xmlXPathFreeObject(cur);
6573 XP_ERROR(XPATH_INVALID_TYPE);
6574 }
6575 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6576 newobj->stringval = cur->stringval;
6577 cur->stringval = tmp;
6578
6579 xmlXPathFreeObject(newobj);
6580 nargs--;
6581 }
6582 valuePush(ctxt, cur);
6583}
6584
6585/**
6586 * xmlXPathContainsFunction:
6587 * @ctxt: the XPath Parser context
6588 * @nargs: the number of arguments
6589 *
6590 * Implement the contains() XPath function
6591 * boolean contains(string, string)
6592 * The contains function returns true if the first argument string
6593 * contains the second argument string, and otherwise returns false.
6594 */
6595void
6596xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6597 xmlXPathObjectPtr hay, needle;
6598
6599 CHECK_ARITY(2);
6600 CAST_TO_STRING;
6601 CHECK_TYPE(XPATH_STRING);
6602 needle = valuePop(ctxt);
6603 CAST_TO_STRING;
6604 hay = valuePop(ctxt);
6605 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6606 xmlXPathFreeObject(hay);
6607 xmlXPathFreeObject(needle);
6608 XP_ERROR(XPATH_INVALID_TYPE);
6609 }
6610 if (xmlStrstr(hay->stringval, needle->stringval))
6611 valuePush(ctxt, xmlXPathNewBoolean(1));
6612 else
6613 valuePush(ctxt, xmlXPathNewBoolean(0));
6614 xmlXPathFreeObject(hay);
6615 xmlXPathFreeObject(needle);
6616}
6617
6618/**
6619 * xmlXPathStartsWithFunction:
6620 * @ctxt: the XPath Parser context
6621 * @nargs: the number of arguments
6622 *
6623 * Implement the starts-with() XPath function
6624 * boolean starts-with(string, string)
6625 * The starts-with function returns true if the first argument string
6626 * starts with the second argument string, and otherwise returns false.
6627 */
6628void
6629xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6630 xmlXPathObjectPtr hay, needle;
6631 int n;
6632
6633 CHECK_ARITY(2);
6634 CAST_TO_STRING;
6635 CHECK_TYPE(XPATH_STRING);
6636 needle = valuePop(ctxt);
6637 CAST_TO_STRING;
6638 hay = valuePop(ctxt);
6639 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6640 xmlXPathFreeObject(hay);
6641 xmlXPathFreeObject(needle);
6642 XP_ERROR(XPATH_INVALID_TYPE);
6643 }
6644 n = xmlStrlen(needle->stringval);
6645 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6646 valuePush(ctxt, xmlXPathNewBoolean(0));
6647 else
6648 valuePush(ctxt, xmlXPathNewBoolean(1));
6649 xmlXPathFreeObject(hay);
6650 xmlXPathFreeObject(needle);
6651}
6652
6653/**
6654 * xmlXPathSubstringFunction:
6655 * @ctxt: the XPath Parser context
6656 * @nargs: the number of arguments
6657 *
6658 * Implement the substring() XPath function
6659 * string substring(string, number, number?)
6660 * The substring function returns the substring of the first argument
6661 * starting at the position specified in the second argument with
6662 * length specified in the third argument. For example,
6663 * substring("12345",2,3) returns "234". If the third argument is not
6664 * specified, it returns the substring starting at the position specified
6665 * in the second argument and continuing to the end of the string. For
6666 * example, substring("12345",2) returns "2345". More precisely, each
6667 * character in the string (see [3.6 Strings]) is considered to have a
6668 * numeric position: the position of the first character is 1, the position
6669 * of the second character is 2 and so on. The returned substring contains
6670 * those characters for which the position of the character is greater than
6671 * or equal to the second argument and, if the third argument is specified,
6672 * less than the sum of the second and third arguments; the comparisons
6673 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6674 * - substring("12345", 1.5, 2.6) returns "234"
6675 * - substring("12345", 0, 3) returns "12"
6676 * - substring("12345", 0 div 0, 3) returns ""
6677 * - substring("12345", 1, 0 div 0) returns ""
6678 * - substring("12345", -42, 1 div 0) returns "12345"
6679 * - substring("12345", -1 div 0, 1 div 0) returns ""
6680 */
6681void
6682xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6683 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006684 double le=0, in;
6685 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006686 xmlChar *ret;
6687
Owen Taylor3473f882001-02-23 17:55:21 +00006688 if (nargs < 2) {
6689 CHECK_ARITY(2);
6690 }
6691 if (nargs > 3) {
6692 CHECK_ARITY(3);
6693 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006694 /*
6695 * take care of possible last (position) argument
6696 */
Owen Taylor3473f882001-02-23 17:55:21 +00006697 if (nargs == 3) {
6698 CAST_TO_NUMBER;
6699 CHECK_TYPE(XPATH_NUMBER);
6700 len = valuePop(ctxt);
6701 le = len->floatval;
6702 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006703 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006704
Owen Taylor3473f882001-02-23 17:55:21 +00006705 CAST_TO_NUMBER;
6706 CHECK_TYPE(XPATH_NUMBER);
6707 start = valuePop(ctxt);
6708 in = start->floatval;
6709 xmlXPathFreeObject(start);
6710 CAST_TO_STRING;
6711 CHECK_TYPE(XPATH_STRING);
6712 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006713 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006714
Daniel Veillard97ac1312001-05-30 19:14:17 +00006715 /*
6716 * If last pos not present, calculate last position
6717 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006718 if (nargs != 3) {
6719 le = (double)m;
6720 if (in < 1.0)
6721 in = 1.0;
6722 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006723
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006724 /* Need to check for the special cases where either
6725 * the index is NaN, the length is NaN, or both
6726 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006727 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006728 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006729 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006730 * To meet the requirements of the spec, the arguments
6731 * must be converted to integer format before
6732 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006733 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006734 * First we go to integer form, rounding up
6735 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006736 */
6737 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006738 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006739
Daniel Veillard9e412302002-06-10 15:59:44 +00006740 if (xmlXPathIsInf(le) == 1) {
6741 l = m;
6742 if (i < 1)
6743 i = 1;
6744 }
6745 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6746 l = 0;
6747 else {
6748 l = (int) le;
6749 if (((double)l)+0.5 <= le) l++;
6750 }
6751
6752 /* Now we normalize inidices */
6753 i -= 1;
6754 l += i;
6755 if (i < 0)
6756 i = 0;
6757 if (l > m)
6758 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006759
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006760 /* number of chars to copy */
6761 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006762
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006763 ret = xmlUTF8Strsub(str->stringval, i, l);
6764 }
6765 else {
6766 ret = NULL;
6767 }
6768
Owen Taylor3473f882001-02-23 17:55:21 +00006769 if (ret == NULL)
6770 valuePush(ctxt, xmlXPathNewCString(""));
6771 else {
6772 valuePush(ctxt, xmlXPathNewString(ret));
6773 xmlFree(ret);
6774 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006775
Owen Taylor3473f882001-02-23 17:55:21 +00006776 xmlXPathFreeObject(str);
6777}
6778
6779/**
6780 * xmlXPathSubstringBeforeFunction:
6781 * @ctxt: the XPath Parser context
6782 * @nargs: the number of arguments
6783 *
6784 * Implement the substring-before() XPath function
6785 * string substring-before(string, string)
6786 * The substring-before function returns the substring of the first
6787 * argument string that precedes the first occurrence of the second
6788 * argument string in the first argument string, or the empty string
6789 * if the first argument string does not contain the second argument
6790 * string. For example, substring-before("1999/04/01","/") returns 1999.
6791 */
6792void
6793xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6794 xmlXPathObjectPtr str;
6795 xmlXPathObjectPtr find;
6796 xmlBufferPtr target;
6797 const xmlChar *point;
6798 int offset;
6799
6800 CHECK_ARITY(2);
6801 CAST_TO_STRING;
6802 find = valuePop(ctxt);
6803 CAST_TO_STRING;
6804 str = valuePop(ctxt);
6805
6806 target = xmlBufferCreate();
6807 if (target) {
6808 point = xmlStrstr(str->stringval, find->stringval);
6809 if (point) {
6810 offset = (int)(point - str->stringval);
6811 xmlBufferAdd(target, str->stringval, offset);
6812 }
6813 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6814 xmlBufferFree(target);
6815 }
6816
6817 xmlXPathFreeObject(str);
6818 xmlXPathFreeObject(find);
6819}
6820
6821/**
6822 * xmlXPathSubstringAfterFunction:
6823 * @ctxt: the XPath Parser context
6824 * @nargs: the number of arguments
6825 *
6826 * Implement the substring-after() XPath function
6827 * string substring-after(string, string)
6828 * The substring-after function returns the substring of the first
6829 * argument string that follows the first occurrence of the second
6830 * argument string in the first argument string, or the empty stringi
6831 * if the first argument string does not contain the second argument
6832 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6833 * and substring-after("1999/04/01","19") returns 99/04/01.
6834 */
6835void
6836xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6837 xmlXPathObjectPtr str;
6838 xmlXPathObjectPtr find;
6839 xmlBufferPtr target;
6840 const xmlChar *point;
6841 int offset;
6842
6843 CHECK_ARITY(2);
6844 CAST_TO_STRING;
6845 find = valuePop(ctxt);
6846 CAST_TO_STRING;
6847 str = valuePop(ctxt);
6848
6849 target = xmlBufferCreate();
6850 if (target) {
6851 point = xmlStrstr(str->stringval, find->stringval);
6852 if (point) {
6853 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6854 xmlBufferAdd(target, &str->stringval[offset],
6855 xmlStrlen(str->stringval) - offset);
6856 }
6857 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6858 xmlBufferFree(target);
6859 }
6860
6861 xmlXPathFreeObject(str);
6862 xmlXPathFreeObject(find);
6863}
6864
6865/**
6866 * xmlXPathNormalizeFunction:
6867 * @ctxt: the XPath Parser context
6868 * @nargs: the number of arguments
6869 *
6870 * Implement the normalize-space() XPath function
6871 * string normalize-space(string?)
6872 * The normalize-space function returns the argument string with white
6873 * space normalized by stripping leading and trailing whitespace
6874 * and replacing sequences of whitespace characters by a single
6875 * space. Whitespace characters are the same allowed by the S production
6876 * in XML. If the argument is omitted, it defaults to the context
6877 * node converted to a string, in other words the value of the context node.
6878 */
6879void
6880xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6881 xmlXPathObjectPtr obj = NULL;
6882 xmlChar *source = NULL;
6883 xmlBufferPtr target;
6884 xmlChar blank;
6885
Daniel Veillarda82b1822004-11-08 16:24:57 +00006886 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006887 if (nargs == 0) {
6888 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006889 valuePush(ctxt,
6890 xmlXPathWrapString(
6891 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006892 nargs = 1;
6893 }
6894
6895 CHECK_ARITY(1);
6896 CAST_TO_STRING;
6897 CHECK_TYPE(XPATH_STRING);
6898 obj = valuePop(ctxt);
6899 source = obj->stringval;
6900
6901 target = xmlBufferCreate();
6902 if (target && source) {
6903
6904 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006905 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006906 source++;
6907
6908 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6909 blank = 0;
6910 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006911 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006912 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006913 } else {
6914 if (blank) {
6915 xmlBufferAdd(target, &blank, 1);
6916 blank = 0;
6917 }
6918 xmlBufferAdd(target, source, 1);
6919 }
6920 source++;
6921 }
6922
6923 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6924 xmlBufferFree(target);
6925 }
6926 xmlXPathFreeObject(obj);
6927}
6928
6929/**
6930 * xmlXPathTranslateFunction:
6931 * @ctxt: the XPath Parser context
6932 * @nargs: the number of arguments
6933 *
6934 * Implement the translate() XPath function
6935 * string translate(string, string, string)
6936 * The translate function returns the first argument string with
6937 * occurrences of characters in the second argument string replaced
6938 * by the character at the corresponding position in the third argument
6939 * string. For example, translate("bar","abc","ABC") returns the string
6940 * BAr. If there is a character in the second argument string with no
6941 * character at a corresponding position in the third argument string
6942 * (because the second argument string is longer than the third argument
6943 * string), then occurrences of that character in the first argument
6944 * string are removed. For example, translate("--aaa--","abc-","ABC")
6945 * returns "AAA". If a character occurs more than once in second
6946 * argument string, then the first occurrence determines the replacement
6947 * character. If the third argument string is longer than the second
6948 * argument string, then excess characters are ignored.
6949 */
6950void
6951xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006952 xmlXPathObjectPtr str;
6953 xmlXPathObjectPtr from;
6954 xmlXPathObjectPtr to;
6955 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006956 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006957 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006958 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006959 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006960
Daniel Veillarde043ee12001-04-16 14:08:07 +00006961 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006962
Daniel Veillarde043ee12001-04-16 14:08:07 +00006963 CAST_TO_STRING;
6964 to = valuePop(ctxt);
6965 CAST_TO_STRING;
6966 from = valuePop(ctxt);
6967 CAST_TO_STRING;
6968 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006969
Daniel Veillarde043ee12001-04-16 14:08:07 +00006970 target = xmlBufferCreate();
6971 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006972 max = xmlUTF8Strlen(to->stringval);
6973 for (cptr = str->stringval; (ch=*cptr); ) {
6974 offset = xmlUTF8Strloc(from->stringval, cptr);
6975 if (offset >= 0) {
6976 if (offset < max) {
6977 point = xmlUTF8Strpos(to->stringval, offset);
6978 if (point)
6979 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6980 }
6981 } else
6982 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6983
6984 /* Step to next character in input */
6985 cptr++;
6986 if ( ch & 0x80 ) {
6987 /* if not simple ascii, verify proper format */
6988 if ( (ch & 0xc0) != 0xc0 ) {
6989 xmlGenericError(xmlGenericErrorContext,
6990 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6991 break;
6992 }
6993 /* then skip over remaining bytes for this char */
6994 while ( (ch <<= 1) & 0x80 )
6995 if ( (*cptr++ & 0xc0) != 0x80 ) {
6996 xmlGenericError(xmlGenericErrorContext,
6997 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6998 break;
6999 }
7000 if (ch & 0x80) /* must have had error encountered */
7001 break;
7002 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007003 }
Owen Taylor3473f882001-02-23 17:55:21 +00007004 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007005 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7006 xmlBufferFree(target);
7007 xmlXPathFreeObject(str);
7008 xmlXPathFreeObject(from);
7009 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007010}
7011
7012/**
7013 * xmlXPathBooleanFunction:
7014 * @ctxt: the XPath Parser context
7015 * @nargs: the number of arguments
7016 *
7017 * Implement the boolean() XPath function
7018 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007019 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007020 * - a number is true if and only if it is neither positive or
7021 * negative zero nor NaN
7022 * - a node-set is true if and only if it is non-empty
7023 * - a string is true if and only if its length is non-zero
7024 */
7025void
7026xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7027 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007028
7029 CHECK_ARITY(1);
7030 cur = valuePop(ctxt);
7031 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007032 cur = xmlXPathConvertBoolean(cur);
7033 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007034}
7035
7036/**
7037 * xmlXPathNotFunction:
7038 * @ctxt: the XPath Parser context
7039 * @nargs: the number of arguments
7040 *
7041 * Implement the not() XPath function
7042 * boolean not(boolean)
7043 * The not function returns true if its argument is false,
7044 * and false otherwise.
7045 */
7046void
7047xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7048 CHECK_ARITY(1);
7049 CAST_TO_BOOLEAN;
7050 CHECK_TYPE(XPATH_BOOLEAN);
7051 ctxt->value->boolval = ! ctxt->value->boolval;
7052}
7053
7054/**
7055 * xmlXPathTrueFunction:
7056 * @ctxt: the XPath Parser context
7057 * @nargs: the number of arguments
7058 *
7059 * Implement the true() XPath function
7060 * boolean true()
7061 */
7062void
7063xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7064 CHECK_ARITY(0);
7065 valuePush(ctxt, xmlXPathNewBoolean(1));
7066}
7067
7068/**
7069 * xmlXPathFalseFunction:
7070 * @ctxt: the XPath Parser context
7071 * @nargs: the number of arguments
7072 *
7073 * Implement the false() XPath function
7074 * boolean false()
7075 */
7076void
7077xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7078 CHECK_ARITY(0);
7079 valuePush(ctxt, xmlXPathNewBoolean(0));
7080}
7081
7082/**
7083 * xmlXPathLangFunction:
7084 * @ctxt: the XPath Parser context
7085 * @nargs: the number of arguments
7086 *
7087 * Implement the lang() XPath function
7088 * boolean lang(string)
7089 * The lang function returns true or false depending on whether the
7090 * language of the context node as specified by xml:lang attributes
7091 * is the same as or is a sublanguage of the language specified by
7092 * the argument string. The language of the context node is determined
7093 * by the value of the xml:lang attribute on the context node, or, if
7094 * the context node has no xml:lang attribute, by the value of the
7095 * xml:lang attribute on the nearest ancestor of the context node that
7096 * has an xml:lang attribute. If there is no such attribute, then lang
7097 * returns false. If there is such an attribute, then lang returns
7098 * true if the attribute value is equal to the argument ignoring case,
7099 * or if there is some suffix starting with - such that the attribute
7100 * value is equal to the argument ignoring that suffix of the attribute
7101 * value and ignoring case.
7102 */
7103void
7104xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007105 xmlXPathObjectPtr val = NULL;
7106 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007107 const xmlChar *lang;
7108 int ret = 0;
7109 int i;
7110
7111 CHECK_ARITY(1);
7112 CAST_TO_STRING;
7113 CHECK_TYPE(XPATH_STRING);
7114 val = valuePop(ctxt);
7115 lang = val->stringval;
7116 theLang = xmlNodeGetLang(ctxt->context->node);
7117 if ((theLang != NULL) && (lang != NULL)) {
7118 for (i = 0;lang[i] != 0;i++)
7119 if (toupper(lang[i]) != toupper(theLang[i]))
7120 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007121 if ((theLang[i] == 0) || (theLang[i] == '-'))
7122 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007123 }
7124not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007125 if (theLang != NULL)
7126 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007127 xmlXPathFreeObject(val);
7128 valuePush(ctxt, xmlXPathNewBoolean(ret));
7129}
7130
7131/**
7132 * xmlXPathNumberFunction:
7133 * @ctxt: the XPath Parser context
7134 * @nargs: the number of arguments
7135 *
7136 * Implement the number() XPath function
7137 * number number(object?)
7138 */
7139void
7140xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7141 xmlXPathObjectPtr cur;
7142 double res;
7143
Daniel Veillarda82b1822004-11-08 16:24:57 +00007144 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007145 if (nargs == 0) {
7146 if (ctxt->context->node == NULL) {
7147 valuePush(ctxt, xmlXPathNewFloat(0.0));
7148 } else {
7149 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7150
7151 res = xmlXPathStringEvalNumber(content);
7152 valuePush(ctxt, xmlXPathNewFloat(res));
7153 xmlFree(content);
7154 }
7155 return;
7156 }
7157
7158 CHECK_ARITY(1);
7159 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007160 cur = xmlXPathConvertNumber(cur);
7161 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007162}
7163
7164/**
7165 * xmlXPathSumFunction:
7166 * @ctxt: the XPath Parser context
7167 * @nargs: the number of arguments
7168 *
7169 * Implement the sum() XPath function
7170 * number sum(node-set)
7171 * The sum function returns the sum of the values of the nodes in
7172 * the argument node-set.
7173 */
7174void
7175xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7176 xmlXPathObjectPtr cur;
7177 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007178 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007179
7180 CHECK_ARITY(1);
7181 if ((ctxt->value == NULL) ||
7182 ((ctxt->value->type != XPATH_NODESET) &&
7183 (ctxt->value->type != XPATH_XSLT_TREE)))
7184 XP_ERROR(XPATH_INVALID_TYPE);
7185 cur = valuePop(ctxt);
7186
William M. Brack08171912003-12-29 02:52:11 +00007187 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007188 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7189 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007190 }
7191 }
William M. Brack08171912003-12-29 02:52:11 +00007192 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007193 xmlXPathFreeObject(cur);
7194}
7195
William M. Brack3d426662005-04-19 14:40:28 +00007196/*
7197 * To assure working code on multiple platforms, we want to only depend
7198 * upon the characteristic truncation of converting a floating point value
7199 * to an integer. Unfortunately, because of the different storage sizes
7200 * of our internal floating point value (double) and integer (int), we
7201 * can't directly convert (see bug 301162). This macro is a messy
7202 * 'workaround'
7203 */
7204#define XTRUNC(f, v) \
7205 f = fmod((v), INT_MAX); \
7206 f = (v) - (f) + (double)((int)(f));
7207
Owen Taylor3473f882001-02-23 17:55:21 +00007208/**
7209 * xmlXPathFloorFunction:
7210 * @ctxt: the XPath Parser context
7211 * @nargs: the number of arguments
7212 *
7213 * Implement the floor() XPath function
7214 * number floor(number)
7215 * The floor function returns the largest (closest to positive infinity)
7216 * number that is not greater than the argument and that is an integer.
7217 */
7218void
7219xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007220 double f;
7221
Owen Taylor3473f882001-02-23 17:55:21 +00007222 CHECK_ARITY(1);
7223 CAST_TO_NUMBER;
7224 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007225
William M. Brack3d426662005-04-19 14:40:28 +00007226 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007227 if (f != ctxt->value->floatval) {
7228 if (ctxt->value->floatval > 0)
7229 ctxt->value->floatval = f;
7230 else
7231 ctxt->value->floatval = f - 1;
7232 }
Owen Taylor3473f882001-02-23 17:55:21 +00007233}
7234
7235/**
7236 * xmlXPathCeilingFunction:
7237 * @ctxt: the XPath Parser context
7238 * @nargs: the number of arguments
7239 *
7240 * Implement the ceiling() XPath function
7241 * number ceiling(number)
7242 * The ceiling function returns the smallest (closest to negative infinity)
7243 * number that is not less than the argument and that is an integer.
7244 */
7245void
7246xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7247 double f;
7248
7249 CHECK_ARITY(1);
7250 CAST_TO_NUMBER;
7251 CHECK_TYPE(XPATH_NUMBER);
7252
7253#if 0
7254 ctxt->value->floatval = ceil(ctxt->value->floatval);
7255#else
William M. Brack3d426662005-04-19 14:40:28 +00007256 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007257 if (f != ctxt->value->floatval) {
7258 if (ctxt->value->floatval > 0)
7259 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007260 else {
7261 if (ctxt->value->floatval < 0 && f == 0)
7262 ctxt->value->floatval = xmlXPathNZERO;
7263 else
7264 ctxt->value->floatval = f;
7265 }
7266
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007267 }
Owen Taylor3473f882001-02-23 17:55:21 +00007268#endif
7269}
7270
7271/**
7272 * xmlXPathRoundFunction:
7273 * @ctxt: the XPath Parser context
7274 * @nargs: the number of arguments
7275 *
7276 * Implement the round() XPath function
7277 * number round(number)
7278 * The round function returns the number that is closest to the
7279 * argument and that is an integer. If there are two such numbers,
7280 * then the one that is even is returned.
7281 */
7282void
7283xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7284 double f;
7285
7286 CHECK_ARITY(1);
7287 CAST_TO_NUMBER;
7288 CHECK_TYPE(XPATH_NUMBER);
7289
Daniel Veillardcda96922001-08-21 10:56:31 +00007290 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7291 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7292 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007293 (ctxt->value->floatval == 0.0))
7294 return;
7295
William M. Brack3d426662005-04-19 14:40:28 +00007296 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007297 if (ctxt->value->floatval < 0) {
7298 if (ctxt->value->floatval < f - 0.5)
7299 ctxt->value->floatval = f - 1;
7300 else
7301 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007302 if (ctxt->value->floatval == 0)
7303 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007304 } else {
7305 if (ctxt->value->floatval < f + 0.5)
7306 ctxt->value->floatval = f;
7307 else
7308 ctxt->value->floatval = f + 1;
7309 }
Owen Taylor3473f882001-02-23 17:55:21 +00007310}
7311
7312/************************************************************************
7313 * *
7314 * The Parser *
7315 * *
7316 ************************************************************************/
7317
7318/*
William M. Brack08171912003-12-29 02:52:11 +00007319 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007320 * implementation.
7321 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007322static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007323static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007324static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007325static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007326static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7327 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007328
7329/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007330 * xmlXPathCurrentChar:
7331 * @ctxt: the XPath parser context
7332 * @cur: pointer to the beginning of the char
7333 * @len: pointer to the length of the char read
7334 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007335 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007336 * bytes in the input buffer.
7337 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007338 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007339 */
7340
7341static int
7342xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7343 unsigned char c;
7344 unsigned int val;
7345 const xmlChar *cur;
7346
7347 if (ctxt == NULL)
7348 return(0);
7349 cur = ctxt->cur;
7350
7351 /*
7352 * We are supposed to handle UTF8, check it's valid
7353 * From rfc2044: encoding of the Unicode values on UTF-8:
7354 *
7355 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7356 * 0000 0000-0000 007F 0xxxxxxx
7357 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7358 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7359 *
7360 * Check for the 0x110000 limit too
7361 */
7362 c = *cur;
7363 if (c & 0x80) {
7364 if ((cur[1] & 0xc0) != 0x80)
7365 goto encoding_error;
7366 if ((c & 0xe0) == 0xe0) {
7367
7368 if ((cur[2] & 0xc0) != 0x80)
7369 goto encoding_error;
7370 if ((c & 0xf0) == 0xf0) {
7371 if (((c & 0xf8) != 0xf0) ||
7372 ((cur[3] & 0xc0) != 0x80))
7373 goto encoding_error;
7374 /* 4-byte code */
7375 *len = 4;
7376 val = (cur[0] & 0x7) << 18;
7377 val |= (cur[1] & 0x3f) << 12;
7378 val |= (cur[2] & 0x3f) << 6;
7379 val |= cur[3] & 0x3f;
7380 } else {
7381 /* 3-byte code */
7382 *len = 3;
7383 val = (cur[0] & 0xf) << 12;
7384 val |= (cur[1] & 0x3f) << 6;
7385 val |= cur[2] & 0x3f;
7386 }
7387 } else {
7388 /* 2-byte code */
7389 *len = 2;
7390 val = (cur[0] & 0x1f) << 6;
7391 val |= cur[1] & 0x3f;
7392 }
7393 if (!IS_CHAR(val)) {
7394 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7395 }
7396 return(val);
7397 } else {
7398 /* 1-byte code */
7399 *len = 1;
7400 return((int) *cur);
7401 }
7402encoding_error:
7403 /*
William M. Brack08171912003-12-29 02:52:11 +00007404 * If we detect an UTF8 error that probably means that the
7405 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007406 * declaration header. Report the error and switch the encoding
7407 * to ISO-Latin-1 (if you don't like this policy, just declare the
7408 * encoding !)
7409 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007410 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007411 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007412}
7413
7414/**
Owen Taylor3473f882001-02-23 17:55:21 +00007415 * xmlXPathParseNCName:
7416 * @ctxt: the XPath Parser context
7417 *
7418 * parse an XML namespace non qualified name.
7419 *
7420 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7421 *
7422 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7423 * CombiningChar | Extender
7424 *
7425 * Returns the namespace name or NULL
7426 */
7427
7428xmlChar *
7429xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007430 const xmlChar *in;
7431 xmlChar *ret;
7432 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007433
Daniel Veillarda82b1822004-11-08 16:24:57 +00007434 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007435 /*
7436 * Accelerator for simple ASCII names
7437 */
7438 in = ctxt->cur;
7439 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7440 ((*in >= 0x41) && (*in <= 0x5A)) ||
7441 (*in == '_')) {
7442 in++;
7443 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7444 ((*in >= 0x41) && (*in <= 0x5A)) ||
7445 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007446 (*in == '_') || (*in == '.') ||
7447 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007448 in++;
7449 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7450 (*in == '[') || (*in == ']') || (*in == ':') ||
7451 (*in == '@') || (*in == '*')) {
7452 count = in - ctxt->cur;
7453 if (count == 0)
7454 return(NULL);
7455 ret = xmlStrndup(ctxt->cur, count);
7456 ctxt->cur = in;
7457 return(ret);
7458 }
7459 }
7460 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007461}
7462
Daniel Veillard2156a562001-04-28 12:24:34 +00007463
Owen Taylor3473f882001-02-23 17:55:21 +00007464/**
7465 * xmlXPathParseQName:
7466 * @ctxt: the XPath Parser context
7467 * @prefix: a xmlChar **
7468 *
7469 * parse an XML qualified name
7470 *
7471 * [NS 5] QName ::= (Prefix ':')? LocalPart
7472 *
7473 * [NS 6] Prefix ::= NCName
7474 *
7475 * [NS 7] LocalPart ::= NCName
7476 *
7477 * Returns the function returns the local part, and prefix is updated
7478 * to get the Prefix if any.
7479 */
7480
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007481static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007482xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7483 xmlChar *ret = NULL;
7484
7485 *prefix = NULL;
7486 ret = xmlXPathParseNCName(ctxt);
7487 if (CUR == ':') {
7488 *prefix = ret;
7489 NEXT;
7490 ret = xmlXPathParseNCName(ctxt);
7491 }
7492 return(ret);
7493}
7494
7495/**
7496 * xmlXPathParseName:
7497 * @ctxt: the XPath Parser context
7498 *
7499 * parse an XML name
7500 *
7501 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7502 * CombiningChar | Extender
7503 *
7504 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7505 *
7506 * Returns the namespace name or NULL
7507 */
7508
7509xmlChar *
7510xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007511 const xmlChar *in;
7512 xmlChar *ret;
7513 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007514
Daniel Veillarda82b1822004-11-08 16:24:57 +00007515 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007516 /*
7517 * Accelerator for simple ASCII names
7518 */
7519 in = ctxt->cur;
7520 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7521 ((*in >= 0x41) && (*in <= 0x5A)) ||
7522 (*in == '_') || (*in == ':')) {
7523 in++;
7524 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7525 ((*in >= 0x41) && (*in <= 0x5A)) ||
7526 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007527 (*in == '_') || (*in == '-') ||
7528 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007529 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007530 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007531 count = in - ctxt->cur;
7532 ret = xmlStrndup(ctxt->cur, count);
7533 ctxt->cur = in;
7534 return(ret);
7535 }
7536 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007537 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007538}
7539
Daniel Veillard61d80a22001-04-27 17:13:01 +00007540static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007541xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007542 xmlChar buf[XML_MAX_NAMELEN + 5];
7543 int len = 0, l;
7544 int c;
7545
7546 /*
7547 * Handler for more complex cases
7548 */
7549 c = CUR_CHAR(l);
7550 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007551 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7552 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007553 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007554 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007555 return(NULL);
7556 }
7557
7558 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7559 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7560 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007561 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007562 (IS_COMBINING(c)) ||
7563 (IS_EXTENDER(c)))) {
7564 COPY_BUF(l,buf,len,c);
7565 NEXTL(l);
7566 c = CUR_CHAR(l);
7567 if (len >= XML_MAX_NAMELEN) {
7568 /*
7569 * Okay someone managed to make a huge name, so he's ready to pay
7570 * for the processing speed.
7571 */
7572 xmlChar *buffer;
7573 int max = len * 2;
7574
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007575 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007576 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007577 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007578 }
7579 memcpy(buffer, buf, len);
7580 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7581 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007582 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007583 (IS_COMBINING(c)) ||
7584 (IS_EXTENDER(c))) {
7585 if (len + 10 > max) {
7586 max *= 2;
7587 buffer = (xmlChar *) xmlRealloc(buffer,
7588 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007589 if (buffer == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007590 XP_ERRORNULL(XPATH_MEMORY_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007591 }
7592 }
7593 COPY_BUF(l,buffer,len,c);
7594 NEXTL(l);
7595 c = CUR_CHAR(l);
7596 }
7597 buffer[len] = 0;
7598 return(buffer);
7599 }
7600 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007601 if (len == 0)
7602 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007603 return(xmlStrndup(buf, len));
7604}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007605
7606#define MAX_FRAC 20
7607
William M. Brack372a4452004-02-17 13:09:23 +00007608/*
7609 * These are used as divisors for the fractional part of a number.
7610 * Since the table includes 1.0 (representing '0' fractional digits),
7611 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7612 */
7613static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007614 1.0, 10.0, 100.0, 1000.0, 10000.0,
7615 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7616 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7617 100000000000000.0,
7618 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007619 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007620};
7621
Owen Taylor3473f882001-02-23 17:55:21 +00007622/**
7623 * xmlXPathStringEvalNumber:
7624 * @str: A string to scan
7625 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007626 * [30a] Float ::= Number ('e' Digits?)?
7627 *
Owen Taylor3473f882001-02-23 17:55:21 +00007628 * [30] Number ::= Digits ('.' Digits?)?
7629 * | '.' Digits
7630 * [31] Digits ::= [0-9]+
7631 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007632 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007633 * In complement of the Number expression, this function also handles
7634 * negative values : '-' Number.
7635 *
7636 * Returns the double value.
7637 */
7638double
7639xmlXPathStringEvalNumber(const xmlChar *str) {
7640 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007641 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007642 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007643 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007644 int exponent = 0;
7645 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007646#ifdef __GNUC__
7647 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007648 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007649#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007650 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007651 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007652 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7653 return(xmlXPathNAN);
7654 }
7655 if (*cur == '-') {
7656 isneg = 1;
7657 cur++;
7658 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007659
7660#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007661 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007662 * tmp/temp is a workaround against a gcc compiler bug
7663 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007664 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007665 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007666 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007667 ret = ret * 10;
7668 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007669 ok = 1;
7670 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007671 temp = (double) tmp;
7672 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007673 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007674#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007675 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007676 while ((*cur >= '0') && (*cur <= '9')) {
7677 ret = ret * 10 + (*cur - '0');
7678 ok = 1;
7679 cur++;
7680 }
7681#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007682
Owen Taylor3473f882001-02-23 17:55:21 +00007683 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007684 int v, frac = 0;
7685 double fraction = 0;
7686
Owen Taylor3473f882001-02-23 17:55:21 +00007687 cur++;
7688 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7689 return(xmlXPathNAN);
7690 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007691 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7692 v = (*cur - '0');
7693 fraction = fraction * 10 + v;
7694 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007695 cur++;
7696 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007697 fraction /= my_pow10[frac];
7698 ret = ret + fraction;
7699 while ((*cur >= '0') && (*cur <= '9'))
7700 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007701 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007702 if ((*cur == 'e') || (*cur == 'E')) {
7703 cur++;
7704 if (*cur == '-') {
7705 is_exponent_negative = 1;
7706 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007707 } else if (*cur == '+') {
7708 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007709 }
7710 while ((*cur >= '0') && (*cur <= '9')) {
7711 exponent = exponent * 10 + (*cur - '0');
7712 cur++;
7713 }
7714 }
William M. Brack76e95df2003-10-18 16:20:14 +00007715 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007716 if (*cur != 0) return(xmlXPathNAN);
7717 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007718 if (is_exponent_negative) exponent = -exponent;
7719 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007720 return(ret);
7721}
7722
7723/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007724 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007725 * @ctxt: the XPath Parser context
7726 *
7727 * [30] Number ::= Digits ('.' Digits?)?
7728 * | '.' Digits
7729 * [31] Digits ::= [0-9]+
7730 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007731 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007732 *
7733 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007734static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007735xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7736{
Owen Taylor3473f882001-02-23 17:55:21 +00007737 double ret = 0.0;
7738 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007739 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007740 int exponent = 0;
7741 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007742#ifdef __GNUC__
7743 unsigned long tmp = 0;
7744 double temp;
7745#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007746
7747 CHECK_ERROR;
7748 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7749 XP_ERROR(XPATH_NUMBER_ERROR);
7750 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007751#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007752 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007753 * tmp/temp is a workaround against a gcc compiler bug
7754 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007755 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007756 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007757 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007758 ret = ret * 10;
7759 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007760 ok = 1;
7761 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007762 temp = (double) tmp;
7763 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007764 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007765#else
7766 ret = 0;
7767 while ((CUR >= '0') && (CUR <= '9')) {
7768 ret = ret * 10 + (CUR - '0');
7769 ok = 1;
7770 NEXT;
7771 }
7772#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007773 if (CUR == '.') {
7774 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007775 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7776 XP_ERROR(XPATH_NUMBER_ERROR);
7777 }
7778 while ((CUR >= '0') && (CUR <= '9')) {
7779 mult /= 10;
7780 ret = ret + (CUR - '0') * mult;
7781 NEXT;
7782 }
Owen Taylor3473f882001-02-23 17:55:21 +00007783 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007784 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007785 NEXT;
7786 if (CUR == '-') {
7787 is_exponent_negative = 1;
7788 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007789 } else if (CUR == '+') {
7790 NEXT;
7791 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007792 while ((CUR >= '0') && (CUR <= '9')) {
7793 exponent = exponent * 10 + (CUR - '0');
7794 NEXT;
7795 }
7796 if (is_exponent_negative)
7797 exponent = -exponent;
7798 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007799 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007800 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007801 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007802}
7803
7804/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007805 * xmlXPathParseLiteral:
7806 * @ctxt: the XPath Parser context
7807 *
7808 * Parse a Literal
7809 *
7810 * [29] Literal ::= '"' [^"]* '"'
7811 * | "'" [^']* "'"
7812 *
7813 * Returns the value found or NULL in case of error
7814 */
7815static xmlChar *
7816xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7817 const xmlChar *q;
7818 xmlChar *ret = NULL;
7819
7820 if (CUR == '"') {
7821 NEXT;
7822 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007823 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007824 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007825 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007826 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007827 } else {
7828 ret = xmlStrndup(q, CUR_PTR - q);
7829 NEXT;
7830 }
7831 } else if (CUR == '\'') {
7832 NEXT;
7833 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007834 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007835 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007836 if (!IS_CHAR_CH(CUR)) {
Daniel Veillard24505b02005-07-28 23:49:35 +00007837 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007838 } else {
7839 ret = xmlStrndup(q, CUR_PTR - q);
7840 NEXT;
7841 }
7842 } else {
Daniel Veillard24505b02005-07-28 23:49:35 +00007843 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007844 }
7845 return(ret);
7846}
7847
7848/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007849 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007850 * @ctxt: the XPath Parser context
7851 *
7852 * Parse a Literal and push it on the stack.
7853 *
7854 * [29] Literal ::= '"' [^"]* '"'
7855 * | "'" [^']* "'"
7856 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007857 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007858 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007859static void
7860xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007861 const xmlChar *q;
7862 xmlChar *ret = NULL;
7863
7864 if (CUR == '"') {
7865 NEXT;
7866 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007867 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007868 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007869 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007870 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7871 } else {
7872 ret = xmlStrndup(q, CUR_PTR - q);
7873 NEXT;
7874 }
7875 } else if (CUR == '\'') {
7876 NEXT;
7877 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007878 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007879 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007880 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007881 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7882 } else {
7883 ret = xmlStrndup(q, CUR_PTR - q);
7884 NEXT;
7885 }
7886 } else {
7887 XP_ERROR(XPATH_START_LITERAL_ERROR);
7888 }
7889 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007890 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7891 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007892 xmlFree(ret);
7893}
7894
7895/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007896 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007897 * @ctxt: the XPath Parser context
7898 *
7899 * Parse a VariableReference, evaluate it and push it on the stack.
7900 *
7901 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007902 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007903 * of any of the types that are possible for the value of an expression,
7904 * and may also be of additional types not specified here.
7905 *
7906 * Early evaluation is possible since:
7907 * The variable bindings [...] used to evaluate a subexpression are
7908 * always the same as those used to evaluate the containing expression.
7909 *
7910 * [36] VariableReference ::= '$' QName
7911 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007912static void
7913xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007914 xmlChar *name;
7915 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007916
7917 SKIP_BLANKS;
7918 if (CUR != '$') {
7919 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7920 }
7921 NEXT;
7922 name = xmlXPathParseQName(ctxt, &prefix);
7923 if (name == NULL) {
7924 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7925 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007926 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007927 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7928 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007929 SKIP_BLANKS;
Daniel Veillardb3d14912005-09-04 20:47:39 +00007930 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
7931 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
7932 }
Owen Taylor3473f882001-02-23 17:55:21 +00007933}
7934
7935/**
7936 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007937 * @name: a name string
7938 *
7939 * Is the name given a NodeType one.
7940 *
7941 * [38] NodeType ::= 'comment'
7942 * | 'text'
7943 * | 'processing-instruction'
7944 * | 'node'
7945 *
7946 * Returns 1 if true 0 otherwise
7947 */
7948int
7949xmlXPathIsNodeType(const xmlChar *name) {
7950 if (name == NULL)
7951 return(0);
7952
Daniel Veillard1971ee22002-01-31 20:29:19 +00007953 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007954 return(1);
7955 if (xmlStrEqual(name, BAD_CAST "text"))
7956 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007957 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007958 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007959 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007960 return(1);
7961 return(0);
7962}
7963
7964/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007966 * @ctxt: the XPath Parser context
7967 *
7968 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7969 * [17] Argument ::= Expr
7970 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007971 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007972 * pushed on the stack
7973 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007974static void
7975xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007976 xmlChar *name;
7977 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007978 int nbargs = 0;
7979
7980 name = xmlXPathParseQName(ctxt, &prefix);
7981 if (name == NULL) {
7982 XP_ERROR(XPATH_EXPR_ERROR);
7983 }
7984 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007985#ifdef DEBUG_EXPR
7986 if (prefix == NULL)
7987 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7988 name);
7989 else
7990 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7991 prefix, name);
7992#endif
7993
Owen Taylor3473f882001-02-23 17:55:21 +00007994 if (CUR != '(') {
7995 XP_ERROR(XPATH_EXPR_ERROR);
7996 }
7997 NEXT;
7998 SKIP_BLANKS;
7999
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008000 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00008001 if (CUR != ')') {
8002 while (CUR != 0) {
8003 int op1 = ctxt->comp->last;
8004 ctxt->comp->last = -1;
8005 xmlXPathCompileExpr(ctxt);
8006 CHECK_ERROR;
8007 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8008 nbargs++;
8009 if (CUR == ')') break;
8010 if (CUR != ',') {
8011 XP_ERROR(XPATH_EXPR_ERROR);
8012 }
8013 NEXT;
8014 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008015 }
Owen Taylor3473f882001-02-23 17:55:21 +00008016 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008017 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8018 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008019 NEXT;
8020 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008021}
8022
8023/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008024 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008025 * @ctxt: the XPath Parser context
8026 *
8027 * [15] PrimaryExpr ::= VariableReference
8028 * | '(' Expr ')'
8029 * | Literal
8030 * | Number
8031 * | FunctionCall
8032 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008033 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008034 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008035static void
8036xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008037 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008038 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008039 else if (CUR == '(') {
8040 NEXT;
8041 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008042 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008043 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008044 if (CUR != ')') {
8045 XP_ERROR(XPATH_EXPR_ERROR);
8046 }
8047 NEXT;
8048 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008049 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008050 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008051 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008052 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008053 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008054 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008055 }
8056 SKIP_BLANKS;
8057}
8058
8059/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008060 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008061 * @ctxt: the XPath Parser context
8062 *
8063 * [20] FilterExpr ::= PrimaryExpr
8064 * | FilterExpr Predicate
8065 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008066 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008067 * Square brackets are used to filter expressions in the same way that
8068 * they are used in location paths. It is an error if the expression to
8069 * be filtered does not evaluate to a node-set. The context node list
8070 * used for evaluating the expression in square brackets is the node-set
8071 * to be filtered listed in document order.
8072 */
8073
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008074static void
8075xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8076 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008077 CHECK_ERROR;
8078 SKIP_BLANKS;
8079
8080 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008081 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008082 SKIP_BLANKS;
8083 }
8084
8085
8086}
8087
8088/**
8089 * xmlXPathScanName:
8090 * @ctxt: the XPath Parser context
8091 *
8092 * Trickery: parse an XML name but without consuming the input flow
8093 * Needed to avoid insanity in the parser state.
8094 *
8095 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8096 * CombiningChar | Extender
8097 *
8098 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8099 *
8100 * [6] Names ::= Name (S Name)*
8101 *
8102 * Returns the Name parsed or NULL
8103 */
8104
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008105static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008106xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008107 int len = 0, l;
8108 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008109 const xmlChar *cur;
8110 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008111
Daniel Veillard03226812004-11-01 14:55:21 +00008112 cur = ctxt->cur;
8113
8114 c = CUR_CHAR(l);
8115 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8116 (!IS_LETTER(c) && (c != '_') &&
8117 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008118 return(NULL);
8119 }
8120
Daniel Veillard03226812004-11-01 14:55:21 +00008121 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8122 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8123 (c == '.') || (c == '-') ||
8124 (c == '_') || (c == ':') ||
8125 (IS_COMBINING(c)) ||
8126 (IS_EXTENDER(c)))) {
8127 len += l;
8128 NEXTL(l);
8129 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008130 }
Daniel Veillard03226812004-11-01 14:55:21 +00008131 ret = xmlStrndup(cur, ctxt->cur - cur);
8132 ctxt->cur = cur;
8133 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008134}
8135
8136/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008137 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008138 * @ctxt: the XPath Parser context
8139 *
8140 * [19] PathExpr ::= LocationPath
8141 * | FilterExpr
8142 * | FilterExpr '/' RelativeLocationPath
8143 * | FilterExpr '//' RelativeLocationPath
8144 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008145 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008146 * The / operator and // operators combine an arbitrary expression
8147 * and a relative location path. It is an error if the expression
8148 * does not evaluate to a node-set.
8149 * The / operator does composition in the same way as when / is
8150 * used in a location path. As in location paths, // is short for
8151 * /descendant-or-self::node()/.
8152 */
8153
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008154static void
8155xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008156 int lc = 1; /* Should we branch to LocationPath ? */
8157 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8158
8159 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008160 if ((CUR == '$') || (CUR == '(') ||
8161 (IS_ASCII_DIGIT(CUR)) ||
8162 (CUR == '\'') || (CUR == '"') ||
8163 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008164 lc = 0;
8165 } else if (CUR == '*') {
8166 /* relative or absolute location path */
8167 lc = 1;
8168 } else if (CUR == '/') {
8169 /* relative or absolute location path */
8170 lc = 1;
8171 } else if (CUR == '@') {
8172 /* relative abbreviated attribute location path */
8173 lc = 1;
8174 } else if (CUR == '.') {
8175 /* relative abbreviated attribute location path */
8176 lc = 1;
8177 } else {
8178 /*
8179 * Problem is finding if we have a name here whether it's:
8180 * - a nodetype
8181 * - a function call in which case it's followed by '('
8182 * - an axis in which case it's followed by ':'
8183 * - a element name
8184 * We do an a priori analysis here rather than having to
8185 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008186 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008187 * read/write/debug.
8188 */
8189 SKIP_BLANKS;
8190 name = xmlXPathScanName(ctxt);
8191 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8192#ifdef DEBUG_STEP
8193 xmlGenericError(xmlGenericErrorContext,
8194 "PathExpr: Axis\n");
8195#endif
8196 lc = 1;
8197 xmlFree(name);
8198 } else if (name != NULL) {
8199 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008200
8201
8202 while (NXT(len) != 0) {
8203 if (NXT(len) == '/') {
8204 /* element name */
8205#ifdef DEBUG_STEP
8206 xmlGenericError(xmlGenericErrorContext,
8207 "PathExpr: AbbrRelLocation\n");
8208#endif
8209 lc = 1;
8210 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008211 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008212 /* ignore blanks */
8213 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008214 } else if (NXT(len) == ':') {
8215#ifdef DEBUG_STEP
8216 xmlGenericError(xmlGenericErrorContext,
8217 "PathExpr: AbbrRelLocation\n");
8218#endif
8219 lc = 1;
8220 break;
8221 } else if ((NXT(len) == '(')) {
8222 /* Note Type or Function */
8223 if (xmlXPathIsNodeType(name)) {
8224#ifdef DEBUG_STEP
8225 xmlGenericError(xmlGenericErrorContext,
8226 "PathExpr: Type search\n");
8227#endif
8228 lc = 1;
8229 } else {
8230#ifdef DEBUG_STEP
8231 xmlGenericError(xmlGenericErrorContext,
8232 "PathExpr: function call\n");
8233#endif
8234 lc = 0;
8235 }
8236 break;
8237 } else if ((NXT(len) == '[')) {
8238 /* element name */
8239#ifdef DEBUG_STEP
8240 xmlGenericError(xmlGenericErrorContext,
8241 "PathExpr: AbbrRelLocation\n");
8242#endif
8243 lc = 1;
8244 break;
8245 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8246 (NXT(len) == '=')) {
8247 lc = 1;
8248 break;
8249 } else {
8250 lc = 1;
8251 break;
8252 }
8253 len++;
8254 }
8255 if (NXT(len) == 0) {
8256#ifdef DEBUG_STEP
8257 xmlGenericError(xmlGenericErrorContext,
8258 "PathExpr: AbbrRelLocation\n");
8259#endif
8260 /* element name */
8261 lc = 1;
8262 }
8263 xmlFree(name);
8264 } else {
William M. Brack08171912003-12-29 02:52:11 +00008265 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008266 XP_ERROR(XPATH_EXPR_ERROR);
8267 }
8268 }
8269
8270 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008271 if (CUR == '/') {
8272 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8273 } else {
8274 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008275 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008276 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008277 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008279 CHECK_ERROR;
8280 if ((CUR == '/') && (NXT(1) == '/')) {
8281 SKIP(2);
8282 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008283
8284 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8285 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8286 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8287
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008288 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008289 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008290 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008291 }
8292 }
8293 SKIP_BLANKS;
8294}
8295
8296/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008298 * @ctxt: the XPath Parser context
8299 *
8300 * [18] UnionExpr ::= PathExpr
8301 * | UnionExpr '|' PathExpr
8302 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008303 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008304 */
8305
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008306static void
8307xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8308 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008309 CHECK_ERROR;
8310 SKIP_BLANKS;
8311 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008312 int op1 = ctxt->comp->last;
8313 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008314
8315 NEXT;
8316 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008317 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008318
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008319 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8320
Owen Taylor3473f882001-02-23 17:55:21 +00008321 SKIP_BLANKS;
8322 }
Owen Taylor3473f882001-02-23 17:55:21 +00008323}
8324
8325/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008326 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008327 * @ctxt: the XPath Parser context
8328 *
8329 * [27] UnaryExpr ::= UnionExpr
8330 * | '-' UnaryExpr
8331 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008332 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008333 */
8334
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008335static void
8336xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008337 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008338 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008339
8340 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008341 while (CUR == '-') {
8342 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008343 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008344 NEXT;
8345 SKIP_BLANKS;
8346 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008347
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008348 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008349 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008350 if (found) {
8351 if (minus)
8352 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8353 else
8354 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008355 }
8356}
8357
8358/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008359 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008360 * @ctxt: the XPath Parser context
8361 *
8362 * [26] MultiplicativeExpr ::= UnaryExpr
8363 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8364 * | MultiplicativeExpr 'div' UnaryExpr
8365 * | MultiplicativeExpr 'mod' UnaryExpr
8366 * [34] MultiplyOperator ::= '*'
8367 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008368 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008369 */
8370
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008371static void
8372xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8373 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008374 CHECK_ERROR;
8375 SKIP_BLANKS;
8376 while ((CUR == '*') ||
8377 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8378 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8379 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008380 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008381
8382 if (CUR == '*') {
8383 op = 0;
8384 NEXT;
8385 } else if (CUR == 'd') {
8386 op = 1;
8387 SKIP(3);
8388 } else if (CUR == 'm') {
8389 op = 2;
8390 SKIP(3);
8391 }
8392 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008393 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008394 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008395 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008396 SKIP_BLANKS;
8397 }
8398}
8399
8400/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008401 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008402 * @ctxt: the XPath Parser context
8403 *
8404 * [25] AdditiveExpr ::= MultiplicativeExpr
8405 * | AdditiveExpr '+' MultiplicativeExpr
8406 * | AdditiveExpr '-' MultiplicativeExpr
8407 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008408 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008409 */
8410
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008411static void
8412xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008413
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008414 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008415 CHECK_ERROR;
8416 SKIP_BLANKS;
8417 while ((CUR == '+') || (CUR == '-')) {
8418 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008419 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008420
8421 if (CUR == '+') plus = 1;
8422 else plus = 0;
8423 NEXT;
8424 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008425 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008426 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008427 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008428 SKIP_BLANKS;
8429 }
8430}
8431
8432/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008433 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008434 * @ctxt: the XPath Parser context
8435 *
8436 * [24] RelationalExpr ::= AdditiveExpr
8437 * | RelationalExpr '<' AdditiveExpr
8438 * | RelationalExpr '>' AdditiveExpr
8439 * | RelationalExpr '<=' AdditiveExpr
8440 * | RelationalExpr '>=' AdditiveExpr
8441 *
8442 * A <= B > C is allowed ? Answer from James, yes with
8443 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8444 * which is basically what got implemented.
8445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008446 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008447 * on the stack
8448 */
8449
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008450static void
8451xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8452 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008453 CHECK_ERROR;
8454 SKIP_BLANKS;
8455 while ((CUR == '<') ||
8456 (CUR == '>') ||
8457 ((CUR == '<') && (NXT(1) == '=')) ||
8458 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008459 int inf, strict;
8460 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008461
8462 if (CUR == '<') inf = 1;
8463 else inf = 0;
8464 if (NXT(1) == '=') strict = 0;
8465 else strict = 1;
8466 NEXT;
8467 if (!strict) NEXT;
8468 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008469 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008470 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008471 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008472 SKIP_BLANKS;
8473 }
8474}
8475
8476/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008477 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008478 * @ctxt: the XPath Parser context
8479 *
8480 * [23] EqualityExpr ::= RelationalExpr
8481 * | EqualityExpr '=' RelationalExpr
8482 * | EqualityExpr '!=' RelationalExpr
8483 *
8484 * A != B != C is allowed ? Answer from James, yes with
8485 * (RelationalExpr = RelationalExpr) = RelationalExpr
8486 * (RelationalExpr != RelationalExpr) != RelationalExpr
8487 * which is basically what got implemented.
8488 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008489 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008490 *
8491 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008492static void
8493xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8494 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008495 CHECK_ERROR;
8496 SKIP_BLANKS;
8497 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008498 int eq;
8499 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008500
8501 if (CUR == '=') eq = 1;
8502 else eq = 0;
8503 NEXT;
8504 if (!eq) NEXT;
8505 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008506 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008507 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008508 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008509 SKIP_BLANKS;
8510 }
8511}
8512
8513/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008514 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008515 * @ctxt: the XPath Parser context
8516 *
8517 * [22] AndExpr ::= EqualityExpr
8518 * | AndExpr 'and' EqualityExpr
8519 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008520 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008521 *
8522 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008523static void
8524xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8525 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008526 CHECK_ERROR;
8527 SKIP_BLANKS;
8528 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008529 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008530 SKIP(3);
8531 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008532 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008533 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008534 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008535 SKIP_BLANKS;
8536 }
8537}
8538
8539/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008540 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008541 * @ctxt: the XPath Parser context
8542 *
8543 * [14] Expr ::= OrExpr
8544 * [21] OrExpr ::= AndExpr
8545 * | OrExpr 'or' AndExpr
8546 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008547 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008548 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008549static void
8550xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8551 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008552 CHECK_ERROR;
8553 SKIP_BLANKS;
8554 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008555 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008556 SKIP(2);
8557 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008558 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008559 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008560 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8561 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008562 SKIP_BLANKS;
8563 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008564 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8565 /* more ops could be optimized too */
8566 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8567 }
Owen Taylor3473f882001-02-23 17:55:21 +00008568}
8569
8570/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008571 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008572 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008573 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008574 *
8575 * [8] Predicate ::= '[' PredicateExpr ']'
8576 * [9] PredicateExpr ::= Expr
8577 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008578 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008579 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008580static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008581xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008582 int op1 = ctxt->comp->last;
8583
8584 SKIP_BLANKS;
8585 if (CUR != '[') {
8586 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8587 }
8588 NEXT;
8589 SKIP_BLANKS;
8590
8591 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008592 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008593 CHECK_ERROR;
8594
8595 if (CUR != ']') {
8596 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8597 }
8598
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008599 if (filter)
8600 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8601 else
8602 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008603
8604 NEXT;
8605 SKIP_BLANKS;
8606}
8607
8608/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008609 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008610 * @ctxt: the XPath Parser context
8611 * @test: pointer to a xmlXPathTestVal
8612 * @type: pointer to a xmlXPathTypeVal
8613 * @prefix: placeholder for a possible name prefix
8614 *
8615 * [7] NodeTest ::= NameTest
8616 * | NodeType '(' ')'
8617 * | 'processing-instruction' '(' Literal ')'
8618 *
8619 * [37] NameTest ::= '*'
8620 * | NCName ':' '*'
8621 * | QName
8622 * [38] NodeType ::= 'comment'
8623 * | 'text'
8624 * | 'processing-instruction'
8625 * | 'node'
8626 *
William M. Brack08171912003-12-29 02:52:11 +00008627 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008628 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008629static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008630xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8631 xmlXPathTypeVal *type, const xmlChar **prefix,
8632 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008633 int blanks;
8634
8635 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8636 STRANGE;
8637 return(NULL);
8638 }
William M. Brack78637da2003-07-31 14:47:38 +00008639 *type = (xmlXPathTypeVal) 0;
8640 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008641 *prefix = NULL;
8642 SKIP_BLANKS;
8643
8644 if ((name == NULL) && (CUR == '*')) {
8645 /*
8646 * All elements
8647 */
8648 NEXT;
8649 *test = NODE_TEST_ALL;
8650 return(NULL);
8651 }
8652
8653 if (name == NULL)
8654 name = xmlXPathParseNCName(ctxt);
8655 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008656 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008657 }
8658
William M. Brack76e95df2003-10-18 16:20:14 +00008659 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008660 SKIP_BLANKS;
8661 if (CUR == '(') {
8662 NEXT;
8663 /*
8664 * NodeType or PI search
8665 */
8666 if (xmlStrEqual(name, BAD_CAST "comment"))
8667 *type = NODE_TYPE_COMMENT;
8668 else if (xmlStrEqual(name, BAD_CAST "node"))
8669 *type = NODE_TYPE_NODE;
8670 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8671 *type = NODE_TYPE_PI;
8672 else if (xmlStrEqual(name, BAD_CAST "text"))
8673 *type = NODE_TYPE_TEXT;
8674 else {
8675 if (name != NULL)
8676 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00008677 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008678 }
8679
8680 *test = NODE_TEST_TYPE;
8681
8682 SKIP_BLANKS;
8683 if (*type == NODE_TYPE_PI) {
8684 /*
8685 * Specific case: search a PI by name.
8686 */
Owen Taylor3473f882001-02-23 17:55:21 +00008687 if (name != NULL)
8688 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008689 name = NULL;
8690 if (CUR != ')') {
8691 name = xmlXPathParseLiteral(ctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +00008692 CHECK_ERROR NULL;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008693 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008694 SKIP_BLANKS;
8695 }
Owen Taylor3473f882001-02-23 17:55:21 +00008696 }
8697 if (CUR != ')') {
8698 if (name != NULL)
8699 xmlFree(name);
Daniel Veillard24505b02005-07-28 23:49:35 +00008700 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008701 }
8702 NEXT;
8703 return(name);
8704 }
8705 *test = NODE_TEST_NAME;
8706 if ((!blanks) && (CUR == ':')) {
8707 NEXT;
8708
8709 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008710 * Since currently the parser context don't have a
8711 * namespace list associated:
8712 * The namespace name for this prefix can be computed
8713 * only at evaluation time. The compilation is done
8714 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008715 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008716#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008717 *prefix = xmlXPathNsLookup(ctxt->context, name);
8718 if (name != NULL)
8719 xmlFree(name);
8720 if (*prefix == NULL) {
8721 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8722 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008723#else
8724 *prefix = name;
8725#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008726
8727 if (CUR == '*') {
8728 /*
8729 * All elements
8730 */
8731 NEXT;
8732 *test = NODE_TEST_ALL;
8733 return(NULL);
8734 }
8735
8736 name = xmlXPathParseNCName(ctxt);
8737 if (name == NULL) {
Daniel Veillard24505b02005-07-28 23:49:35 +00008738 XP_ERRORNULL(XPATH_EXPR_ERROR);
Owen Taylor3473f882001-02-23 17:55:21 +00008739 }
8740 }
8741 return(name);
8742}
8743
8744/**
8745 * xmlXPathIsAxisName:
8746 * @name: a preparsed name token
8747 *
8748 * [6] AxisName ::= 'ancestor'
8749 * | 'ancestor-or-self'
8750 * | 'attribute'
8751 * | 'child'
8752 * | 'descendant'
8753 * | 'descendant-or-self'
8754 * | 'following'
8755 * | 'following-sibling'
8756 * | 'namespace'
8757 * | 'parent'
8758 * | 'preceding'
8759 * | 'preceding-sibling'
8760 * | 'self'
8761 *
8762 * Returns the axis or 0
8763 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008764static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008765xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008766 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008767 switch (name[0]) {
8768 case 'a':
8769 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8770 ret = AXIS_ANCESTOR;
8771 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8772 ret = AXIS_ANCESTOR_OR_SELF;
8773 if (xmlStrEqual(name, BAD_CAST "attribute"))
8774 ret = AXIS_ATTRIBUTE;
8775 break;
8776 case 'c':
8777 if (xmlStrEqual(name, BAD_CAST "child"))
8778 ret = AXIS_CHILD;
8779 break;
8780 case 'd':
8781 if (xmlStrEqual(name, BAD_CAST "descendant"))
8782 ret = AXIS_DESCENDANT;
8783 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8784 ret = AXIS_DESCENDANT_OR_SELF;
8785 break;
8786 case 'f':
8787 if (xmlStrEqual(name, BAD_CAST "following"))
8788 ret = AXIS_FOLLOWING;
8789 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8790 ret = AXIS_FOLLOWING_SIBLING;
8791 break;
8792 case 'n':
8793 if (xmlStrEqual(name, BAD_CAST "namespace"))
8794 ret = AXIS_NAMESPACE;
8795 break;
8796 case 'p':
8797 if (xmlStrEqual(name, BAD_CAST "parent"))
8798 ret = AXIS_PARENT;
8799 if (xmlStrEqual(name, BAD_CAST "preceding"))
8800 ret = AXIS_PRECEDING;
8801 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8802 ret = AXIS_PRECEDING_SIBLING;
8803 break;
8804 case 's':
8805 if (xmlStrEqual(name, BAD_CAST "self"))
8806 ret = AXIS_SELF;
8807 break;
8808 }
8809 return(ret);
8810}
8811
8812/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008813 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008814 * @ctxt: the XPath Parser context
8815 *
8816 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8817 * | AbbreviatedStep
8818 *
8819 * [12] AbbreviatedStep ::= '.' | '..'
8820 *
8821 * [5] AxisSpecifier ::= AxisName '::'
8822 * | AbbreviatedAxisSpecifier
8823 *
8824 * [13] AbbreviatedAxisSpecifier ::= '@'?
8825 *
8826 * Modified for XPtr range support as:
8827 *
8828 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8829 * | AbbreviatedStep
8830 * | 'range-to' '(' Expr ')' Predicate*
8831 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008832 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008833 * A location step of . is short for self::node(). This is
8834 * particularly useful in conjunction with //. For example, the
8835 * location path .//para is short for
8836 * self::node()/descendant-or-self::node()/child::para
8837 * and so will select all para descendant elements of the context
8838 * node.
8839 * Similarly, a location step of .. is short for parent::node().
8840 * For example, ../title is short for parent::node()/child::title
8841 * and so will select the title children of the parent of the context
8842 * node.
8843 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008844static void
8845xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008846#ifdef LIBXML_XPTR_ENABLED
8847 int rangeto = 0;
8848 int op2 = -1;
8849#endif
8850
Owen Taylor3473f882001-02-23 17:55:21 +00008851 SKIP_BLANKS;
8852 if ((CUR == '.') && (NXT(1) == '.')) {
8853 SKIP(2);
8854 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008855 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8856 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008857 } else if (CUR == '.') {
8858 NEXT;
8859 SKIP_BLANKS;
8860 } else {
8861 xmlChar *name = NULL;
8862 const xmlChar *prefix = NULL;
8863 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008864 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008865 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008867
8868 /*
8869 * The modification needed for XPointer change to the production
8870 */
8871#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008872 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008873 name = xmlXPathParseNCName(ctxt);
8874 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008875 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008876 xmlFree(name);
8877 SKIP_BLANKS;
8878 if (CUR != '(') {
8879 XP_ERROR(XPATH_EXPR_ERROR);
8880 }
8881 NEXT;
8882 SKIP_BLANKS;
8883
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008884 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008885 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008886 CHECK_ERROR;
8887
8888 SKIP_BLANKS;
8889 if (CUR != ')') {
8890 XP_ERROR(XPATH_EXPR_ERROR);
8891 }
8892 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008893 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008894 goto eval_predicates;
8895 }
8896 }
8897#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008898 if (CUR == '*') {
8899 axis = AXIS_CHILD;
8900 } else {
8901 if (name == NULL)
8902 name = xmlXPathParseNCName(ctxt);
8903 if (name != NULL) {
8904 axis = xmlXPathIsAxisName(name);
8905 if (axis != 0) {
8906 SKIP_BLANKS;
8907 if ((CUR == ':') && (NXT(1) == ':')) {
8908 SKIP(2);
8909 xmlFree(name);
8910 name = NULL;
8911 } else {
8912 /* an element name can conflict with an axis one :-\ */
8913 axis = AXIS_CHILD;
8914 }
Owen Taylor3473f882001-02-23 17:55:21 +00008915 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008916 axis = AXIS_CHILD;
8917 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008918 } else if (CUR == '@') {
8919 NEXT;
8920 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008921 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008922 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008923 }
Owen Taylor3473f882001-02-23 17:55:21 +00008924 }
8925
8926 CHECK_ERROR;
8927
Daniel Veillard8bda20f2005-08-24 09:36:47 +00008928 type = (xmlXPathTypeVal) 0;
8929 test = (xmlXPathTestVal) 0;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008930 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008931 if (test == 0)
8932 return;
8933
Daniel Veillarded6c5492005-07-23 15:00:22 +00008934 if ((prefix != NULL) && (ctxt->context != NULL) &&
8935 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
8936 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
8937 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
8938 }
8939 }
Owen Taylor3473f882001-02-23 17:55:21 +00008940#ifdef DEBUG_STEP
8941 xmlGenericError(xmlGenericErrorContext,
8942 "Basis : computing new set\n");
8943#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008944
Owen Taylor3473f882001-02-23 17:55:21 +00008945#ifdef DEBUG_STEP
8946 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008947 if (ctxt->value == NULL)
8948 xmlGenericError(xmlGenericErrorContext, "no value\n");
8949 else if (ctxt->value->nodesetval == NULL)
8950 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8951 else
8952 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008953#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008954
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008955#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008956eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008957#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008958 op1 = ctxt->comp->last;
8959 ctxt->comp->last = -1;
8960
Owen Taylor3473f882001-02-23 17:55:21 +00008961 SKIP_BLANKS;
8962 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008963 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008964 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008965
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008966#ifdef LIBXML_XPTR_ENABLED
8967 if (rangeto) {
8968 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8969 } else
8970#endif
8971 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8972 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008973
Owen Taylor3473f882001-02-23 17:55:21 +00008974 }
8975#ifdef DEBUG_STEP
8976 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008977 if (ctxt->value == NULL)
8978 xmlGenericError(xmlGenericErrorContext, "no value\n");
8979 else if (ctxt->value->nodesetval == NULL)
8980 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8981 else
8982 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8983 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008984#endif
8985}
8986
8987/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008988 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008989 * @ctxt: the XPath Parser context
8990 *
8991 * [3] RelativeLocationPath ::= Step
8992 * | RelativeLocationPath '/' Step
8993 * | AbbreviatedRelativeLocationPath
8994 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8995 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008996 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008997 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008998static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008999xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00009000(xmlXPathParserContextPtr ctxt) {
9001 SKIP_BLANKS;
9002 if ((CUR == '/') && (NXT(1) == '/')) {
9003 SKIP(2);
9004 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009005 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9006 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00009007 } else if (CUR == '/') {
9008 NEXT;
9009 SKIP_BLANKS;
9010 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009011 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009012 SKIP_BLANKS;
9013 while (CUR == '/') {
9014 if ((CUR == '/') && (NXT(1) == '/')) {
9015 SKIP(2);
9016 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009017 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009018 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009019 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009020 } else if (CUR == '/') {
9021 NEXT;
9022 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009023 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009024 }
9025 SKIP_BLANKS;
9026 }
9027}
9028
9029/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009030 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009031 * @ctxt: the XPath Parser context
9032 *
9033 * [1] LocationPath ::= RelativeLocationPath
9034 * | AbsoluteLocationPath
9035 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9036 * | AbbreviatedAbsoluteLocationPath
9037 * [10] AbbreviatedAbsoluteLocationPath ::=
9038 * '//' RelativeLocationPath
9039 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009040 * Compile a location path
9041 *
Owen Taylor3473f882001-02-23 17:55:21 +00009042 * // is short for /descendant-or-self::node()/. For example,
9043 * //para is short for /descendant-or-self::node()/child::para and
9044 * so will select any para element in the document (even a para element
9045 * that is a document element will be selected by //para since the
9046 * document element node is a child of the root node); div//para is
9047 * short for div/descendant-or-self::node()/child::para and so will
9048 * select all para descendants of div children.
9049 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009050static void
9051xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009052 SKIP_BLANKS;
9053 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009054 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009055 } else {
9056 while (CUR == '/') {
9057 if ((CUR == '/') && (NXT(1) == '/')) {
9058 SKIP(2);
9059 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009060 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9061 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009062 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009063 } else if (CUR == '/') {
9064 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009065 SKIP_BLANKS;
9066 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009067 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009068 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009069 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009070 }
9071 }
9072 }
9073}
9074
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009075/************************************************************************
9076 * *
9077 * XPath precompiled expression evaluation *
9078 * *
9079 ************************************************************************/
9080
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9083
9084/**
9085 * xmlXPathNodeCollectAndTest:
9086 * @ctxt: the XPath Parser context
9087 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009088 * @first: pointer to the first element in document order
9089 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009090 *
9091 * This is the function implementing a step: based on the current list
9092 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009093 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009094 *
9095 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 *
William M. Brack08171912003-12-29 02:52:11 +00009097 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009098 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009099static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009100xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009101 xmlXPathStepOpPtr op,
9102 xmlNodePtr * first, xmlNodePtr * last)
9103{
William M. Brack78637da2003-07-31 14:47:38 +00009104 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9105 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9106 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009107 const xmlChar *prefix = op->value4;
9108 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009109 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110
9111#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115 xmlNodeSetPtr ret, list;
9116 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009117 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009118 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119 xmlNodePtr cur = NULL;
9120 xmlXPathObjectPtr obj;
9121 xmlNodeSetPtr nodelist;
9122 xmlNodePtr tmp;
9123
Daniel Veillardf06307e2001-07-03 10:35:50 +00009124 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009125 obj = valuePop(ctxt);
9126 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009127 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009128 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009130 if (URI == NULL) {
9131 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009132 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009133 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009134 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009137#endif
9138 switch (axis) {
9139 case AXIS_ANCESTOR:
9140#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009141 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009142#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 first = NULL;
9144 next = xmlXPathNextAncestor;
9145 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009146 case AXIS_ANCESTOR_OR_SELF:
9147#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 xmlGenericError(xmlGenericErrorContext,
9149 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 first = NULL;
9152 next = xmlXPathNextAncestorOrSelf;
9153 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009154 case AXIS_ATTRIBUTE:
9155#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009158 first = NULL;
9159 last = NULL;
9160 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009161 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009162 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009163 case AXIS_CHILD:
9164#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009165 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009166#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009167 last = NULL;
9168 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009169 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009170 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009171 case AXIS_DESCENDANT:
9172#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009173 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009174#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009175 last = NULL;
9176 next = xmlXPathNextDescendant;
9177 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009178 case AXIS_DESCENDANT_OR_SELF:
9179#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009180 xmlGenericError(xmlGenericErrorContext,
9181 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009182#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009183 last = NULL;
9184 next = xmlXPathNextDescendantOrSelf;
9185 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009186 case AXIS_FOLLOWING:
9187#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009188 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009189#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 last = NULL;
9191 next = xmlXPathNextFollowing;
9192 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009193 case AXIS_FOLLOWING_SIBLING:
9194#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 xmlGenericError(xmlGenericErrorContext,
9196 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009197#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009198 last = NULL;
9199 next = xmlXPathNextFollowingSibling;
9200 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009201 case AXIS_NAMESPACE:
9202#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009203 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009204#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009205 first = NULL;
9206 last = NULL;
9207 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009208 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009209 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009210 case AXIS_PARENT:
9211#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009212 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009213#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009214 first = NULL;
9215 next = xmlXPathNextParent;
9216 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009217 case AXIS_PRECEDING:
9218#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009219 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009220#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221 first = NULL;
9222 next = xmlXPathNextPrecedingInternal;
9223 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009224 case AXIS_PRECEDING_SIBLING:
9225#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 xmlGenericError(xmlGenericErrorContext,
9227 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009228#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009229 first = NULL;
9230 next = xmlXPathNextPrecedingSibling;
9231 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009232 case AXIS_SELF:
9233#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009234 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009235#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 first = NULL;
9237 last = NULL;
9238 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009239 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009241 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009242 if (next == NULL) {
9243 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009244 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009245 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009246
9247 nodelist = obj->nodesetval;
9248 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009249 xmlXPathFreeObject(obj);
9250 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9251 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009252 }
9253 addNode = xmlXPathNodeSetAddUnique;
9254 ret = NULL;
9255#ifdef DEBUG_STEP
9256 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009257 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009258 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009259 case NODE_TEST_NONE:
9260 xmlGenericError(xmlGenericErrorContext,
9261 " searching for none !!!\n");
9262 break;
9263 case NODE_TEST_TYPE:
9264 xmlGenericError(xmlGenericErrorContext,
9265 " searching for type %d\n", type);
9266 break;
9267 case NODE_TEST_PI:
9268 xmlGenericError(xmlGenericErrorContext,
9269 " searching for PI !!!\n");
9270 break;
9271 case NODE_TEST_ALL:
9272 xmlGenericError(xmlGenericErrorContext,
9273 " searching for *\n");
9274 break;
9275 case NODE_TEST_NS:
9276 xmlGenericError(xmlGenericErrorContext,
9277 " searching for namespace %s\n",
9278 prefix);
9279 break;
9280 case NODE_TEST_NAME:
9281 xmlGenericError(xmlGenericErrorContext,
9282 " searching for name %s\n", name);
9283 if (prefix != NULL)
9284 xmlGenericError(xmlGenericErrorContext,
9285 " with namespace %s\n", prefix);
9286 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009287 }
9288 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9289#endif
9290 /*
9291 * 2.3 Node Tests
9292 * - For the attribute axis, the principal node type is attribute.
9293 * - For the namespace axis, the principal node type is namespace.
9294 * - For other axes, the principal node type is element.
9295 *
9296 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009297 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009298 * select all element children of the context node
9299 */
9300 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009301 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009302 ctxt->context->node = nodelist->nodeTab[i];
9303
Daniel Veillardf06307e2001-07-03 10:35:50 +00009304 cur = NULL;
9305 list = xmlXPathNodeSetCreate(NULL);
9306 do {
9307 cur = next(ctxt, cur);
9308 if (cur == NULL)
9309 break;
9310 if ((first != NULL) && (*first == cur))
9311 break;
9312 if (((t % 256) == 0) &&
9313 (first != NULL) && (*first != NULL) &&
9314 (xmlXPathCmpNodes(*first, cur) >= 0))
9315 break;
9316 if ((last != NULL) && (*last == cur))
9317 break;
9318 if (((t % 256) == 0) &&
9319 (last != NULL) && (*last != NULL) &&
9320 (xmlXPathCmpNodes(cur, *last) >= 0))
9321 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009322 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009323#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009324 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9325#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009326 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009327 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009328 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009329 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009330 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009331 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009332 if ((cur->type == type) ||
9333 ((type == NODE_TYPE_NODE) &&
9334 ((cur->type == XML_DOCUMENT_NODE) ||
9335 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9336 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009337 (cur->type == XML_NAMESPACE_DECL) ||
9338 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009339 (cur->type == XML_PI_NODE) ||
9340 (cur->type == XML_COMMENT_NODE) ||
9341 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009342 (cur->type == XML_TEXT_NODE))) ||
9343 ((type == NODE_TYPE_TEXT) &&
9344 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009345#ifdef DEBUG_STEP
9346 n++;
9347#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009348 addNode(list, cur);
9349 }
9350 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009351 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009352 if (cur->type == XML_PI_NODE) {
9353 if ((name != NULL) &&
9354 (!xmlStrEqual(name, cur->name)))
9355 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009356#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009357 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009358#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 addNode(list, cur);
9360 }
9361 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009362 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009363 if (axis == AXIS_ATTRIBUTE) {
9364 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009365#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009366 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009367#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009368 addNode(list, cur);
9369 }
9370 } else if (axis == AXIS_NAMESPACE) {
9371 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009372#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009373 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009374#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009375 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9376 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009377 }
9378 } else {
9379 if (cur->type == XML_ELEMENT_NODE) {
9380 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009381#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009382 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009383#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009384 addNode(list, cur);
9385 } else if ((cur->ns != NULL) &&
9386 (xmlStrEqual(URI, cur->ns->href))) {
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 }
9392 }
9393 }
9394 break;
9395 case NODE_TEST_NS:{
9396 TODO;
9397 break;
9398 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009399 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009400 switch (cur->type) {
9401 case XML_ELEMENT_NODE:
9402 if (xmlStrEqual(name, cur->name)) {
9403 if (prefix == NULL) {
9404 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009405#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009406 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009407#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009408 addNode(list, cur);
9409 }
9410 } else {
9411 if ((cur->ns != NULL) &&
9412 (xmlStrEqual(URI,
9413 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009414#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009415 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009416#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009417 addNode(list, cur);
9418 }
9419 }
9420 }
9421 break;
9422 case XML_ATTRIBUTE_NODE:{
9423 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009424
Daniel Veillardf06307e2001-07-03 10:35:50 +00009425 if (xmlStrEqual(name, attr->name)) {
9426 if (prefix == NULL) {
9427 if ((attr->ns == NULL) ||
9428 (attr->ns->prefix == NULL)) {
9429#ifdef DEBUG_STEP
9430 n++;
9431#endif
9432 addNode(list,
9433 (xmlNodePtr) attr);
9434 }
9435 } else {
9436 if ((attr->ns != NULL) &&
9437 (xmlStrEqual(URI,
9438 attr->ns->
9439 href))) {
9440#ifdef DEBUG_STEP
9441 n++;
9442#endif
9443 addNode(list,
9444 (xmlNodePtr) attr);
9445 }
9446 }
9447 }
9448 break;
9449 }
9450 case XML_NAMESPACE_DECL:
9451 if (cur->type == XML_NAMESPACE_DECL) {
9452 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009453
Daniel Veillardf06307e2001-07-03 10:35:50 +00009454 if ((ns->prefix != NULL) && (name != NULL)
9455 && (xmlStrEqual(ns->prefix, name))) {
9456#ifdef DEBUG_STEP
9457 n++;
9458#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009459 xmlXPathNodeSetAddNs(list,
9460 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009461 }
9462 }
9463 break;
9464 default:
9465 break;
9466 }
9467 break;
9468 break;
9469 }
9470 } while (cur != NULL);
9471
9472 /*
9473 * If there is some predicate filtering do it now
9474 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009475 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 xmlXPathObjectPtr obj2;
9477
9478 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9479 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9480 CHECK_TYPE0(XPATH_NODESET);
9481 obj2 = valuePop(ctxt);
9482 list = obj2->nodesetval;
9483 obj2->nodesetval = NULL;
9484 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009485 if (ctxt->error != XPATH_EXPRESSION_OK) {
9486 xmlXPathFreeObject(obj);
9487 xmlXPathFreeNodeSet(list);
9488 return(0);
9489 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009490 }
9491 if (ret == NULL) {
9492 ret = list;
9493 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009494 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009495 xmlXPathFreeNodeSet(list);
9496 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009497 }
9498 ctxt->context->node = tmp;
9499#ifdef DEBUG_STEP
9500 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009501 "\nExamined %d nodes, found %d nodes at that step\n",
9502 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009503#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009504 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009505 if ((obj->boolval) && (obj->user != NULL)) {
9506 ctxt->value->boolval = 1;
9507 ctxt->value->user = obj->user;
9508 obj->user = NULL;
9509 obj->boolval = 0;
9510 }
9511 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009512 return(t);
9513}
9514
9515/**
9516 * xmlXPathNodeCollectAndTestNth:
9517 * @ctxt: the XPath Parser context
9518 * @op: the XPath precompiled step operation
9519 * @indx: the index to collect
9520 * @first: pointer to the first element in document order
9521 * @last: pointer to the last element in document order
9522 *
9523 * This is the function implementing a step: based on the current list
9524 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009525 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009526 *
9527 * Pushes the new NodeSet resulting from the search.
9528 * Returns the number of node traversed
9529 */
9530static int
9531xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9532 xmlXPathStepOpPtr op, int indx,
9533 xmlNodePtr * first, xmlNodePtr * last)
9534{
William M. Brack78637da2003-07-31 14:47:38 +00009535 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9536 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9537 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009538 const xmlChar *prefix = op->value4;
9539 const xmlChar *name = op->value5;
9540 const xmlChar *URI = NULL;
9541 int n = 0, t = 0;
9542
9543 int i;
9544 xmlNodeSetPtr list;
9545 xmlXPathTraversalFunction next = NULL;
9546 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9547 xmlNodePtr cur = NULL;
9548 xmlXPathObjectPtr obj;
9549 xmlNodeSetPtr nodelist;
9550 xmlNodePtr tmp;
9551
9552 CHECK_TYPE0(XPATH_NODESET);
9553 obj = valuePop(ctxt);
9554 addNode = xmlXPathNodeSetAdd;
9555 if (prefix != NULL) {
9556 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009557 if (URI == NULL) {
9558 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009559 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009560 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009561 }
9562#ifdef DEBUG_STEP_NTH
9563 xmlGenericError(xmlGenericErrorContext, "new step : ");
9564 if (first != NULL) {
9565 if (*first != NULL)
9566 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9567 (*first)->name);
9568 else
9569 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9570 }
9571 if (last != NULL) {
9572 if (*last != NULL)
9573 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9574 (*last)->name);
9575 else
9576 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9577 }
9578#endif
9579 switch (axis) {
9580 case AXIS_ANCESTOR:
9581#ifdef DEBUG_STEP_NTH
9582 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9583#endif
9584 first = NULL;
9585 next = xmlXPathNextAncestor;
9586 break;
9587 case AXIS_ANCESTOR_OR_SELF:
9588#ifdef DEBUG_STEP_NTH
9589 xmlGenericError(xmlGenericErrorContext,
9590 "axis 'ancestors-or-self' ");
9591#endif
9592 first = NULL;
9593 next = xmlXPathNextAncestorOrSelf;
9594 break;
9595 case AXIS_ATTRIBUTE:
9596#ifdef DEBUG_STEP_NTH
9597 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9598#endif
9599 first = NULL;
9600 last = NULL;
9601 next = xmlXPathNextAttribute;
9602 break;
9603 case AXIS_CHILD:
9604#ifdef DEBUG_STEP_NTH
9605 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9606#endif
9607 last = NULL;
9608 next = xmlXPathNextChild;
9609 break;
9610 case AXIS_DESCENDANT:
9611#ifdef DEBUG_STEP_NTH
9612 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9613#endif
9614 last = NULL;
9615 next = xmlXPathNextDescendant;
9616 break;
9617 case AXIS_DESCENDANT_OR_SELF:
9618#ifdef DEBUG_STEP_NTH
9619 xmlGenericError(xmlGenericErrorContext,
9620 "axis 'descendant-or-self' ");
9621#endif
9622 last = NULL;
9623 next = xmlXPathNextDescendantOrSelf;
9624 break;
9625 case AXIS_FOLLOWING:
9626#ifdef DEBUG_STEP_NTH
9627 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9628#endif
9629 last = NULL;
9630 next = xmlXPathNextFollowing;
9631 break;
9632 case AXIS_FOLLOWING_SIBLING:
9633#ifdef DEBUG_STEP_NTH
9634 xmlGenericError(xmlGenericErrorContext,
9635 "axis 'following-siblings' ");
9636#endif
9637 last = NULL;
9638 next = xmlXPathNextFollowingSibling;
9639 break;
9640 case AXIS_NAMESPACE:
9641#ifdef DEBUG_STEP_NTH
9642 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9643#endif
9644 last = NULL;
9645 first = NULL;
9646 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9647 break;
9648 case AXIS_PARENT:
9649#ifdef DEBUG_STEP_NTH
9650 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9651#endif
9652 first = NULL;
9653 next = xmlXPathNextParent;
9654 break;
9655 case AXIS_PRECEDING:
9656#ifdef DEBUG_STEP_NTH
9657 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9658#endif
9659 first = NULL;
9660 next = xmlXPathNextPrecedingInternal;
9661 break;
9662 case AXIS_PRECEDING_SIBLING:
9663#ifdef DEBUG_STEP_NTH
9664 xmlGenericError(xmlGenericErrorContext,
9665 "axis 'preceding-sibling' ");
9666#endif
9667 first = NULL;
9668 next = xmlXPathNextPrecedingSibling;
9669 break;
9670 case AXIS_SELF:
9671#ifdef DEBUG_STEP_NTH
9672 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9673#endif
9674 first = NULL;
9675 last = NULL;
9676 next = xmlXPathNextSelf;
9677 break;
9678 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009679 if (next == NULL) {
9680 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009681 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009682 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009683
9684 nodelist = obj->nodesetval;
9685 if (nodelist == NULL) {
9686 xmlXPathFreeObject(obj);
9687 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9688 return(0);
9689 }
9690 addNode = xmlXPathNodeSetAddUnique;
9691#ifdef DEBUG_STEP_NTH
9692 xmlGenericError(xmlGenericErrorContext,
9693 " context contains %d nodes\n", nodelist->nodeNr);
9694 switch (test) {
9695 case NODE_TEST_NONE:
9696 xmlGenericError(xmlGenericErrorContext,
9697 " searching for none !!!\n");
9698 break;
9699 case NODE_TEST_TYPE:
9700 xmlGenericError(xmlGenericErrorContext,
9701 " searching for type %d\n", type);
9702 break;
9703 case NODE_TEST_PI:
9704 xmlGenericError(xmlGenericErrorContext,
9705 " searching for PI !!!\n");
9706 break;
9707 case NODE_TEST_ALL:
9708 xmlGenericError(xmlGenericErrorContext,
9709 " searching for *\n");
9710 break;
9711 case NODE_TEST_NS:
9712 xmlGenericError(xmlGenericErrorContext,
9713 " searching for namespace %s\n",
9714 prefix);
9715 break;
9716 case NODE_TEST_NAME:
9717 xmlGenericError(xmlGenericErrorContext,
9718 " searching for name %s\n", name);
9719 if (prefix != NULL)
9720 xmlGenericError(xmlGenericErrorContext,
9721 " with namespace %s\n", prefix);
9722 break;
9723 }
9724 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9725#endif
9726 /*
9727 * 2.3 Node Tests
9728 * - For the attribute axis, the principal node type is attribute.
9729 * - For the namespace axis, the principal node type is namespace.
9730 * - For other axes, the principal node type is element.
9731 *
9732 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009733 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009734 * select all element children of the context node
9735 */
9736 tmp = ctxt->context->node;
9737 list = xmlXPathNodeSetCreate(NULL);
9738 for (i = 0; i < nodelist->nodeNr; i++) {
9739 ctxt->context->node = nodelist->nodeTab[i];
9740
9741 cur = NULL;
9742 n = 0;
9743 do {
9744 cur = next(ctxt, cur);
9745 if (cur == NULL)
9746 break;
9747 if ((first != NULL) && (*first == cur))
9748 break;
9749 if (((t % 256) == 0) &&
9750 (first != NULL) && (*first != NULL) &&
9751 (xmlXPathCmpNodes(*first, cur) >= 0))
9752 break;
9753 if ((last != NULL) && (*last == cur))
9754 break;
9755 if (((t % 256) == 0) &&
9756 (last != NULL) && (*last != NULL) &&
9757 (xmlXPathCmpNodes(cur, *last) >= 0))
9758 break;
9759 t++;
9760 switch (test) {
9761 case NODE_TEST_NONE:
9762 ctxt->context->node = tmp;
9763 STRANGE return(0);
9764 case NODE_TEST_TYPE:
9765 if ((cur->type == type) ||
9766 ((type == NODE_TYPE_NODE) &&
9767 ((cur->type == XML_DOCUMENT_NODE) ||
9768 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9769 (cur->type == XML_ELEMENT_NODE) ||
9770 (cur->type == XML_PI_NODE) ||
9771 (cur->type == XML_COMMENT_NODE) ||
9772 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009773 (cur->type == XML_TEXT_NODE))) ||
9774 ((type == NODE_TYPE_TEXT) &&
9775 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009776 n++;
9777 if (n == indx)
9778 addNode(list, cur);
9779 }
9780 break;
9781 case NODE_TEST_PI:
9782 if (cur->type == XML_PI_NODE) {
9783 if ((name != NULL) &&
9784 (!xmlStrEqual(name, cur->name)))
9785 break;
9786 n++;
9787 if (n == indx)
9788 addNode(list, cur);
9789 }
9790 break;
9791 case NODE_TEST_ALL:
9792 if (axis == AXIS_ATTRIBUTE) {
9793 if (cur->type == XML_ATTRIBUTE_NODE) {
9794 n++;
9795 if (n == indx)
9796 addNode(list, cur);
9797 }
9798 } else if (axis == AXIS_NAMESPACE) {
9799 if (cur->type == XML_NAMESPACE_DECL) {
9800 n++;
9801 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009802 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9803 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009804 }
9805 } else {
9806 if (cur->type == XML_ELEMENT_NODE) {
9807 if (prefix == NULL) {
9808 n++;
9809 if (n == indx)
9810 addNode(list, cur);
9811 } else if ((cur->ns != NULL) &&
9812 (xmlStrEqual(URI, cur->ns->href))) {
9813 n++;
9814 if (n == indx)
9815 addNode(list, cur);
9816 }
9817 }
9818 }
9819 break;
9820 case NODE_TEST_NS:{
9821 TODO;
9822 break;
9823 }
9824 case NODE_TEST_NAME:
9825 switch (cur->type) {
9826 case XML_ELEMENT_NODE:
9827 if (xmlStrEqual(name, cur->name)) {
9828 if (prefix == NULL) {
9829 if (cur->ns == NULL) {
9830 n++;
9831 if (n == indx)
9832 addNode(list, cur);
9833 }
9834 } else {
9835 if ((cur->ns != NULL) &&
9836 (xmlStrEqual(URI,
9837 cur->ns->href))) {
9838 n++;
9839 if (n == indx)
9840 addNode(list, cur);
9841 }
9842 }
9843 }
9844 break;
9845 case XML_ATTRIBUTE_NODE:{
9846 xmlAttrPtr attr = (xmlAttrPtr) cur;
9847
9848 if (xmlStrEqual(name, attr->name)) {
9849 if (prefix == NULL) {
9850 if ((attr->ns == NULL) ||
9851 (attr->ns->prefix == NULL)) {
9852 n++;
9853 if (n == indx)
9854 addNode(list, cur);
9855 }
9856 } else {
9857 if ((attr->ns != NULL) &&
9858 (xmlStrEqual(URI,
9859 attr->ns->
9860 href))) {
9861 n++;
9862 if (n == indx)
9863 addNode(list, cur);
9864 }
9865 }
9866 }
9867 break;
9868 }
9869 case XML_NAMESPACE_DECL:
9870 if (cur->type == XML_NAMESPACE_DECL) {
9871 xmlNsPtr ns = (xmlNsPtr) cur;
9872
9873 if ((ns->prefix != NULL) && (name != NULL)
9874 && (xmlStrEqual(ns->prefix, name))) {
9875 n++;
9876 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009877 xmlXPathNodeSetAddNs(list,
9878 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009879 }
9880 }
9881 break;
9882 default:
9883 break;
9884 }
9885 break;
9886 break;
9887 }
9888 } while (n < indx);
9889 }
9890 ctxt->context->node = tmp;
9891#ifdef DEBUG_STEP_NTH
9892 xmlGenericError(xmlGenericErrorContext,
9893 "\nExamined %d nodes, found %d nodes at that step\n",
9894 t, list->nodeNr);
9895#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009896 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009897 if ((obj->boolval) && (obj->user != NULL)) {
9898 ctxt->value->boolval = 1;
9899 ctxt->value->user = obj->user;
9900 obj->user = NULL;
9901 obj->boolval = 0;
9902 }
9903 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009904 return(t);
9905}
9906
9907/**
9908 * xmlXPathCompOpEvalFirst:
9909 * @ctxt: the XPath parser context with the compiled expression
9910 * @op: an XPath compiled operation
9911 * @first: the first elem found so far
9912 *
9913 * Evaluate the Precompiled XPath operation searching only the first
9914 * element in document order
9915 *
9916 * Returns the number of examined objects.
9917 */
9918static int
9919xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9920 xmlXPathStepOpPtr op, xmlNodePtr * first)
9921{
9922 int total = 0, cur;
9923 xmlXPathCompExprPtr comp;
9924 xmlXPathObjectPtr arg1, arg2;
9925
Daniel Veillard556c6682001-10-06 09:59:51 +00009926 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009927 comp = ctxt->comp;
9928 switch (op->op) {
9929 case XPATH_OP_END:
9930 return (0);
9931 case XPATH_OP_UNION:
9932 total =
9933 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9934 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009935 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936 if ((ctxt->value != NULL)
9937 && (ctxt->value->type == XPATH_NODESET)
9938 && (ctxt->value->nodesetval != NULL)
9939 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9940 /*
9941 * limit tree traversing to first node in the result
9942 */
9943 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9944 *first = ctxt->value->nodesetval->nodeTab[0];
9945 }
9946 cur =
9947 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9948 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009949 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009950 CHECK_TYPE0(XPATH_NODESET);
9951 arg2 = valuePop(ctxt);
9952
9953 CHECK_TYPE0(XPATH_NODESET);
9954 arg1 = valuePop(ctxt);
9955
9956 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9957 arg2->nodesetval);
9958 valuePush(ctxt, arg1);
9959 xmlXPathFreeObject(arg2);
9960 /* optimizer */
9961 if (total > cur)
9962 xmlXPathCompSwap(op);
9963 return (total + cur);
9964 case XPATH_OP_ROOT:
9965 xmlXPathRoot(ctxt);
9966 return (0);
9967 case XPATH_OP_NODE:
9968 if (op->ch1 != -1)
9969 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009970 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009971 if (op->ch2 != -1)
9972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009973 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009974 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9975 return (total);
9976 case XPATH_OP_RESET:
9977 if (op->ch1 != -1)
9978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009979 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009980 if (op->ch2 != -1)
9981 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009982 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009983 ctxt->context->node = NULL;
9984 return (total);
9985 case XPATH_OP_COLLECT:{
9986 if (op->ch1 == -1)
9987 return (total);
9988
9989 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009990 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009991
9992 /*
9993 * Optimization for [n] selection where n is a number
9994 */
9995 if ((op->ch2 != -1) &&
9996 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9997 (comp->steps[op->ch2].ch1 == -1) &&
9998 (comp->steps[op->ch2].ch2 != -1) &&
9999 (comp->steps[comp->steps[op->ch2].ch2].op ==
10000 XPATH_OP_VALUE)) {
10001 xmlXPathObjectPtr val;
10002
10003 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10004 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10005 int indx = (int) val->floatval;
10006
10007 if (val->floatval == (float) indx) {
10008 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
10009 first, NULL);
10010 return (total);
10011 }
10012 }
10013 }
10014 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10015 return (total);
10016 }
10017 case XPATH_OP_VALUE:
10018 valuePush(ctxt,
10019 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10020 return (0);
10021 case XPATH_OP_SORT:
10022 if (op->ch1 != -1)
10023 total +=
10024 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10025 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010026 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010027 if ((ctxt->value != NULL)
10028 && (ctxt->value->type == XPATH_NODESET)
10029 && (ctxt->value->nodesetval != NULL))
10030 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10031 return (total);
10032 default:
10033 return (xmlXPathCompOpEval(ctxt, op));
10034 }
10035}
10036
10037/**
10038 * xmlXPathCompOpEvalLast:
10039 * @ctxt: the XPath parser context with the compiled expression
10040 * @op: an XPath compiled operation
10041 * @last: the last elem found so far
10042 *
10043 * Evaluate the Precompiled XPath operation searching only the last
10044 * element in document order
10045 *
William M. Brack08171912003-12-29 02:52:11 +000010046 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010047 */
10048static int
10049xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10050 xmlNodePtr * last)
10051{
10052 int total = 0, cur;
10053 xmlXPathCompExprPtr comp;
10054 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010055 xmlNodePtr bak;
10056 xmlDocPtr bakd;
10057 int pp;
10058 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059
Daniel Veillard556c6682001-10-06 09:59:51 +000010060 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010061 comp = ctxt->comp;
10062 switch (op->op) {
10063 case XPATH_OP_END:
10064 return (0);
10065 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010066 bakd = ctxt->context->doc;
10067 bak = ctxt->context->node;
10068 pp = ctxt->context->proximityPosition;
10069 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010070 total =
10071 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010072 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010073 if ((ctxt->value != NULL)
10074 && (ctxt->value->type == XPATH_NODESET)
10075 && (ctxt->value->nodesetval != NULL)
10076 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10077 /*
10078 * limit tree traversing to first node in the result
10079 */
10080 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10081 *last =
10082 ctxt->value->nodesetval->nodeTab[ctxt->value->
10083 nodesetval->nodeNr -
10084 1];
10085 }
William M. Brackce4fc562004-01-22 02:47:18 +000010086 ctxt->context->doc = bakd;
10087 ctxt->context->node = bak;
10088 ctxt->context->proximityPosition = pp;
10089 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010090 cur =
10091 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010092 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010093 if ((ctxt->value != NULL)
10094 && (ctxt->value->type == XPATH_NODESET)
10095 && (ctxt->value->nodesetval != NULL)
10096 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10097 }
10098 CHECK_TYPE0(XPATH_NODESET);
10099 arg2 = valuePop(ctxt);
10100
10101 CHECK_TYPE0(XPATH_NODESET);
10102 arg1 = valuePop(ctxt);
10103
10104 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10105 arg2->nodesetval);
10106 valuePush(ctxt, arg1);
10107 xmlXPathFreeObject(arg2);
10108 /* optimizer */
10109 if (total > cur)
10110 xmlXPathCompSwap(op);
10111 return (total + cur);
10112 case XPATH_OP_ROOT:
10113 xmlXPathRoot(ctxt);
10114 return (0);
10115 case XPATH_OP_NODE:
10116 if (op->ch1 != -1)
10117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010118 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010119 if (op->ch2 != -1)
10120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010121 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010122 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10123 return (total);
10124 case XPATH_OP_RESET:
10125 if (op->ch1 != -1)
10126 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010127 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010128 if (op->ch2 != -1)
10129 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010130 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 ctxt->context->node = NULL;
10132 return (total);
10133 case XPATH_OP_COLLECT:{
10134 if (op->ch1 == -1)
10135 return (0);
10136
10137 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010138 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010139
10140 /*
10141 * Optimization for [n] selection where n is a number
10142 */
10143 if ((op->ch2 != -1) &&
10144 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10145 (comp->steps[op->ch2].ch1 == -1) &&
10146 (comp->steps[op->ch2].ch2 != -1) &&
10147 (comp->steps[comp->steps[op->ch2].ch2].op ==
10148 XPATH_OP_VALUE)) {
10149 xmlXPathObjectPtr val;
10150
10151 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10152 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10153 int indx = (int) val->floatval;
10154
10155 if (val->floatval == (float) indx) {
10156 total +=
10157 xmlXPathNodeCollectAndTestNth(ctxt, op,
10158 indx, NULL,
10159 last);
10160 return (total);
10161 }
10162 }
10163 }
10164 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10165 return (total);
10166 }
10167 case XPATH_OP_VALUE:
10168 valuePush(ctxt,
10169 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10170 return (0);
10171 case XPATH_OP_SORT:
10172 if (op->ch1 != -1)
10173 total +=
10174 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10175 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010176 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010177 if ((ctxt->value != NULL)
10178 && (ctxt->value->type == XPATH_NODESET)
10179 && (ctxt->value->nodesetval != NULL))
10180 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10181 return (total);
10182 default:
10183 return (xmlXPathCompOpEval(ctxt, op));
10184 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010185}
10186
Owen Taylor3473f882001-02-23 17:55:21 +000010187/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010188 * xmlXPathCompOpEval:
10189 * @ctxt: the XPath parser context with the compiled expression
10190 * @op: an XPath compiled operation
10191 *
10192 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010193 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010194 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010195static int
10196xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10197{
10198 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010199 int equal, ret;
10200 xmlXPathCompExprPtr comp;
10201 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010202 xmlNodePtr bak;
10203 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010204 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010205 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010206
Daniel Veillard556c6682001-10-06 09:59:51 +000010207 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010208 comp = ctxt->comp;
10209 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010210 case XPATH_OP_END:
10211 return (0);
10212 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010213 bakd = ctxt->context->doc;
10214 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010215 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010216 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010218 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010219 xmlXPathBooleanFunction(ctxt, 1);
10220 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10221 return (total);
10222 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010223 ctxt->context->doc = bakd;
10224 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010225 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010226 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010228 if (ctxt->error) {
10229 xmlXPathFreeObject(arg2);
10230 return(0);
10231 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010232 xmlXPathBooleanFunction(ctxt, 1);
10233 arg1 = valuePop(ctxt);
10234 arg1->boolval &= arg2->boolval;
10235 valuePush(ctxt, arg1);
10236 xmlXPathFreeObject(arg2);
10237 return (total);
10238 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010239 bakd = ctxt->context->doc;
10240 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010241 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010242 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010244 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010245 xmlXPathBooleanFunction(ctxt, 1);
10246 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10247 return (total);
10248 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010249 ctxt->context->doc = bakd;
10250 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010251 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010252 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010253 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010254 if (ctxt->error) {
10255 xmlXPathFreeObject(arg2);
10256 return(0);
10257 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010258 xmlXPathBooleanFunction(ctxt, 1);
10259 arg1 = valuePop(ctxt);
10260 arg1->boolval |= arg2->boolval;
10261 valuePush(ctxt, arg1);
10262 xmlXPathFreeObject(arg2);
10263 return (total);
10264 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010265 bakd = ctxt->context->doc;
10266 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010267 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010268 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010269 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010270 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010271 ctxt->context->doc = bakd;
10272 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010273 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010274 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010275 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010276 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010277 if (op->value)
10278 equal = xmlXPathEqualValues(ctxt);
10279 else
10280 equal = xmlXPathNotEqualValues(ctxt);
10281 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 return (total);
10283 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010284 bakd = ctxt->context->doc;
10285 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010286 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010287 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010288 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010289 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010290 ctxt->context->doc = bakd;
10291 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010292 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010293 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010295 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10297 valuePush(ctxt, xmlXPathNewBoolean(ret));
10298 return (total);
10299 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010300 bakd = ctxt->context->doc;
10301 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010302 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010303 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010304 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010305 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010306 if (op->ch2 != -1) {
10307 ctxt->context->doc = bakd;
10308 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010309 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010310 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010311 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010312 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010313 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010314 if (op->value == 0)
10315 xmlXPathSubValues(ctxt);
10316 else if (op->value == 1)
10317 xmlXPathAddValues(ctxt);
10318 else if (op->value == 2)
10319 xmlXPathValueFlipSign(ctxt);
10320 else if (op->value == 3) {
10321 CAST_TO_NUMBER;
10322 CHECK_TYPE0(XPATH_NUMBER);
10323 }
10324 return (total);
10325 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010326 bakd = ctxt->context->doc;
10327 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010328 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010329 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010330 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010331 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010332 ctxt->context->doc = bakd;
10333 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010334 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010335 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010337 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010338 if (op->value == 0)
10339 xmlXPathMultValues(ctxt);
10340 else if (op->value == 1)
10341 xmlXPathDivValues(ctxt);
10342 else if (op->value == 2)
10343 xmlXPathModValues(ctxt);
10344 return (total);
10345 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010346 bakd = ctxt->context->doc;
10347 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010348 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010349 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010351 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010352 ctxt->context->doc = bakd;
10353 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010354 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010355 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010356 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010357 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010358 CHECK_TYPE0(XPATH_NODESET);
10359 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010360
Daniel Veillardf06307e2001-07-03 10:35:50 +000010361 CHECK_TYPE0(XPATH_NODESET);
10362 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010363
Daniel Veillardf06307e2001-07-03 10:35:50 +000010364 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10365 arg2->nodesetval);
10366 valuePush(ctxt, arg1);
10367 xmlXPathFreeObject(arg2);
10368 return (total);
10369 case XPATH_OP_ROOT:
10370 xmlXPathRoot(ctxt);
10371 return (total);
10372 case XPATH_OP_NODE:
10373 if (op->ch1 != -1)
10374 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010375 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010376 if (op->ch2 != -1)
10377 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010378 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010379 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10380 return (total);
10381 case XPATH_OP_RESET:
10382 if (op->ch1 != -1)
10383 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010384 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010385 if (op->ch2 != -1)
10386 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010387 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010388 ctxt->context->node = NULL;
10389 return (total);
10390 case XPATH_OP_COLLECT:{
10391 if (op->ch1 == -1)
10392 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010393
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010395 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010396
Daniel Veillardf06307e2001-07-03 10:35:50 +000010397 /*
10398 * Optimization for [n] selection where n is a number
10399 */
10400 if ((op->ch2 != -1) &&
10401 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10402 (comp->steps[op->ch2].ch1 == -1) &&
10403 (comp->steps[op->ch2].ch2 != -1) &&
10404 (comp->steps[comp->steps[op->ch2].ch2].op ==
10405 XPATH_OP_VALUE)) {
10406 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010407
Daniel Veillardf06307e2001-07-03 10:35:50 +000010408 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10409 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10410 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010411
Daniel Veillardf06307e2001-07-03 10:35:50 +000010412 if (val->floatval == (float) indx) {
10413 total +=
10414 xmlXPathNodeCollectAndTestNth(ctxt, op,
10415 indx, NULL,
10416 NULL);
10417 return (total);
10418 }
10419 }
10420 }
10421 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10422 return (total);
10423 }
10424 case XPATH_OP_VALUE:
10425 valuePush(ctxt,
10426 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10427 return (total);
10428 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010429 xmlXPathObjectPtr val;
10430
Daniel Veillardf06307e2001-07-03 10:35:50 +000010431 if (op->ch1 != -1)
10432 total +=
10433 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010434 if (op->value5 == NULL) {
10435 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10436 if (val == NULL) {
10437 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10438 return(0);
10439 }
10440 valuePush(ctxt, val);
10441 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010442 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010443
Daniel Veillardf06307e2001-07-03 10:35:50 +000010444 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10445 if (URI == NULL) {
10446 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010447 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010448 op->value4, op->value5);
10449 return (total);
10450 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010451 val = xmlXPathVariableLookupNS(ctxt->context,
10452 op->value4, URI);
10453 if (val == NULL) {
10454 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10455 return(0);
10456 }
10457 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010458 }
10459 return (total);
10460 }
10461 case XPATH_OP_FUNCTION:{
10462 xmlXPathFunction func;
10463 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010464 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010465
10466 if (op->ch1 != -1)
10467 total +=
10468 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010469 if (ctxt->valueNr < op->value) {
10470 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010471 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010472 ctxt->error = XPATH_INVALID_OPERAND;
10473 return (total);
10474 }
10475 for (i = 0; i < op->value; i++)
10476 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10477 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010478 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010479 ctxt->error = XPATH_INVALID_OPERAND;
10480 return (total);
10481 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010482 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010483 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010484 else {
10485 const xmlChar *URI = NULL;
10486
10487 if (op->value5 == NULL)
10488 func =
10489 xmlXPathFunctionLookup(ctxt->context,
10490 op->value4);
10491 else {
10492 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10493 if (URI == NULL) {
10494 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010495 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010496 op->value4, op->value5);
10497 return (total);
10498 }
10499 func = xmlXPathFunctionLookupNS(ctxt->context,
10500 op->value4, URI);
10501 }
10502 if (func == NULL) {
10503 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010504 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010505 op->value4);
10506 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010507 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010508 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010509 op->cacheURI = (void *) URI;
10510 }
10511 oldFunc = ctxt->context->function;
10512 oldFuncURI = ctxt->context->functionURI;
10513 ctxt->context->function = op->value4;
10514 ctxt->context->functionURI = op->cacheURI;
10515 func(ctxt, op->value);
10516 ctxt->context->function = oldFunc;
10517 ctxt->context->functionURI = oldFuncURI;
10518 return (total);
10519 }
10520 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010521 bakd = ctxt->context->doc;
10522 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010523 pp = ctxt->context->proximityPosition;
10524 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 if (op->ch1 != -1)
10526 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010527 ctxt->context->contextSize = cs;
10528 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010529 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010530 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010531 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010532 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010533 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010534 ctxt->context->doc = bakd;
10535 ctxt->context->node = bak;
10536 CHECK_ERROR0;
10537 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010538 return (total);
10539 case XPATH_OP_PREDICATE:
10540 case XPATH_OP_FILTER:{
10541 xmlXPathObjectPtr res;
10542 xmlXPathObjectPtr obj, tmp;
10543 xmlNodeSetPtr newset = NULL;
10544 xmlNodeSetPtr oldset;
10545 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010546 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010547 int i;
10548
10549 /*
10550 * Optimization for ()[1] selection i.e. the first elem
10551 */
10552 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10553 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10554 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10555 xmlXPathObjectPtr val;
10556
10557 val = comp->steps[op->ch2].value4;
10558 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10559 (val->floatval == 1.0)) {
10560 xmlNodePtr first = NULL;
10561
10562 total +=
10563 xmlXPathCompOpEvalFirst(ctxt,
10564 &comp->steps[op->ch1],
10565 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010566 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010567 /*
10568 * The nodeset should be in document order,
10569 * Keep only the first value
10570 */
10571 if ((ctxt->value != NULL) &&
10572 (ctxt->value->type == XPATH_NODESET) &&
10573 (ctxt->value->nodesetval != NULL) &&
10574 (ctxt->value->nodesetval->nodeNr > 1))
10575 ctxt->value->nodesetval->nodeNr = 1;
10576 return (total);
10577 }
10578 }
10579 /*
10580 * Optimization for ()[last()] selection i.e. the last elem
10581 */
10582 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10583 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10584 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10585 int f = comp->steps[op->ch2].ch1;
10586
10587 if ((f != -1) &&
10588 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10589 (comp->steps[f].value5 == NULL) &&
10590 (comp->steps[f].value == 0) &&
10591 (comp->steps[f].value4 != NULL) &&
10592 (xmlStrEqual
10593 (comp->steps[f].value4, BAD_CAST "last"))) {
10594 xmlNodePtr last = NULL;
10595
10596 total +=
10597 xmlXPathCompOpEvalLast(ctxt,
10598 &comp->steps[op->ch1],
10599 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010600 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010601 /*
10602 * The nodeset should be in document order,
10603 * Keep only the last value
10604 */
10605 if ((ctxt->value != NULL) &&
10606 (ctxt->value->type == XPATH_NODESET) &&
10607 (ctxt->value->nodesetval != NULL) &&
10608 (ctxt->value->nodesetval->nodeTab != NULL) &&
10609 (ctxt->value->nodesetval->nodeNr > 1)) {
10610 ctxt->value->nodesetval->nodeTab[0] =
10611 ctxt->value->nodesetval->nodeTab[ctxt->
10612 value->
10613 nodesetval->
10614 nodeNr -
10615 1];
10616 ctxt->value->nodesetval->nodeNr = 1;
10617 }
10618 return (total);
10619 }
10620 }
10621
10622 if (op->ch1 != -1)
10623 total +=
10624 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010625 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010626 if (op->ch2 == -1)
10627 return (total);
10628 if (ctxt->value == NULL)
10629 return (total);
10630
10631 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010632
10633#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010634 /*
10635 * Hum are we filtering the result of an XPointer expression
10636 */
10637 if (ctxt->value->type == XPATH_LOCATIONSET) {
10638 xmlLocationSetPtr newlocset = NULL;
10639 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010640
Daniel Veillardf06307e2001-07-03 10:35:50 +000010641 /*
10642 * Extract the old locset, and then evaluate the result of the
10643 * expression for all the element in the locset. use it to grow
10644 * up a new locset.
10645 */
10646 CHECK_TYPE0(XPATH_LOCATIONSET);
10647 obj = valuePop(ctxt);
10648 oldlocset = obj->user;
10649 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010650
Daniel Veillardf06307e2001-07-03 10:35:50 +000010651 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10652 ctxt->context->contextSize = 0;
10653 ctxt->context->proximityPosition = 0;
10654 if (op->ch2 != -1)
10655 total +=
10656 xmlXPathCompOpEval(ctxt,
10657 &comp->steps[op->ch2]);
10658 res = valuePop(ctxt);
10659 if (res != NULL)
10660 xmlXPathFreeObject(res);
10661 valuePush(ctxt, obj);
10662 CHECK_ERROR0;
10663 return (total);
10664 }
10665 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010666
Daniel Veillardf06307e2001-07-03 10:35:50 +000010667 for (i = 0; i < oldlocset->locNr; i++) {
10668 /*
10669 * Run the evaluation with a node list made of a
10670 * single item in the nodelocset.
10671 */
10672 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010673 ctxt->context->contextSize = oldlocset->locNr;
10674 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010675 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10676 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010677
Daniel Veillardf06307e2001-07-03 10:35:50 +000010678 if (op->ch2 != -1)
10679 total +=
10680 xmlXPathCompOpEval(ctxt,
10681 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010682 if (ctxt->error != XPATH_EXPRESSION_OK) {
10683 xmlXPathFreeObject(obj);
10684 return(0);
10685 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010686
Daniel Veillardf06307e2001-07-03 10:35:50 +000010687 /*
10688 * The result of the evaluation need to be tested to
10689 * decided whether the filter succeeded or not
10690 */
10691 res = valuePop(ctxt);
10692 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10693 xmlXPtrLocationSetAdd(newlocset,
10694 xmlXPathObjectCopy
10695 (oldlocset->locTab[i]));
10696 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010697
Daniel Veillardf06307e2001-07-03 10:35:50 +000010698 /*
10699 * Cleanup
10700 */
10701 if (res != NULL)
10702 xmlXPathFreeObject(res);
10703 if (ctxt->value == tmp) {
10704 res = valuePop(ctxt);
10705 xmlXPathFreeObject(res);
10706 }
10707
10708 ctxt->context->node = NULL;
10709 }
10710
10711 /*
10712 * The result is used as the new evaluation locset.
10713 */
10714 xmlXPathFreeObject(obj);
10715 ctxt->context->node = NULL;
10716 ctxt->context->contextSize = -1;
10717 ctxt->context->proximityPosition = -1;
10718 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10719 ctxt->context->node = oldnode;
10720 return (total);
10721 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722#endif /* LIBXML_XPTR_ENABLED */
10723
Daniel Veillardf06307e2001-07-03 10:35:50 +000010724 /*
10725 * Extract the old set, and then evaluate the result of the
10726 * expression for all the element in the set. use it to grow
10727 * up a new set.
10728 */
10729 CHECK_TYPE0(XPATH_NODESET);
10730 obj = valuePop(ctxt);
10731 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010732
Daniel Veillardf06307e2001-07-03 10:35:50 +000010733 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010734 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010735 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010736
Daniel Veillardf06307e2001-07-03 10:35:50 +000010737 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10738 ctxt->context->contextSize = 0;
10739 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010740/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010741 if (op->ch2 != -1)
10742 total +=
10743 xmlXPathCompOpEval(ctxt,
10744 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010745 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010746 res = valuePop(ctxt);
10747 if (res != NULL)
10748 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010749*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010750 valuePush(ctxt, obj);
10751 ctxt->context->node = oldnode;
10752 CHECK_ERROR0;
10753 } else {
10754 /*
10755 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010756 * Also set the xpath document in case things like
10757 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010758 */
10759 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010760
Daniel Veillardf06307e2001-07-03 10:35:50 +000010761 for (i = 0; i < oldset->nodeNr; i++) {
10762 /*
10763 * Run the evaluation with a node list made of
10764 * a single item in the nodeset.
10765 */
10766 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010767 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10768 (oldset->nodeTab[i]->doc != NULL))
10769 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010770 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10771 valuePush(ctxt, tmp);
10772 ctxt->context->contextSize = oldset->nodeNr;
10773 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010774
Daniel Veillardf06307e2001-07-03 10:35:50 +000010775 if (op->ch2 != -1)
10776 total +=
10777 xmlXPathCompOpEval(ctxt,
10778 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010779 if (ctxt->error != XPATH_EXPRESSION_OK) {
10780 xmlXPathFreeNodeSet(newset);
10781 xmlXPathFreeObject(obj);
10782 return(0);
10783 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010784
Daniel Veillardf06307e2001-07-03 10:35:50 +000010785 /*
William M. Brack08171912003-12-29 02:52:11 +000010786 * The result of the evaluation needs to be tested to
10787 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010788 */
10789 res = valuePop(ctxt);
10790 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10791 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10792 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010793
Daniel Veillardf06307e2001-07-03 10:35:50 +000010794 /*
10795 * Cleanup
10796 */
10797 if (res != NULL)
10798 xmlXPathFreeObject(res);
10799 if (ctxt->value == tmp) {
10800 res = valuePop(ctxt);
10801 xmlXPathFreeObject(res);
10802 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010803
Daniel Veillardf06307e2001-07-03 10:35:50 +000010804 ctxt->context->node = NULL;
10805 }
10806
10807 /*
10808 * The result is used as the new evaluation set.
10809 */
10810 xmlXPathFreeObject(obj);
10811 ctxt->context->node = NULL;
10812 ctxt->context->contextSize = -1;
10813 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010814 /* may want to move this past the '}' later */
10815 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010816 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10817 }
10818 ctxt->context->node = oldnode;
10819 return (total);
10820 }
10821 case XPATH_OP_SORT:
10822 if (op->ch1 != -1)
10823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010824 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010825 if ((ctxt->value != NULL) &&
10826 (ctxt->value->type == XPATH_NODESET) &&
10827 (ctxt->value->nodesetval != NULL))
10828 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10829 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010830#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010831 case XPATH_OP_RANGETO:{
10832 xmlXPathObjectPtr range;
10833 xmlXPathObjectPtr res, obj;
10834 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010835 xmlLocationSetPtr newlocset = NULL;
10836 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010837 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010838 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010839
Daniel Veillardf06307e2001-07-03 10:35:50 +000010840 if (op->ch1 != -1)
10841 total +=
10842 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10843 if (op->ch2 == -1)
10844 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010845
William M. Brack08171912003-12-29 02:52:11 +000010846 if (ctxt->value->type == XPATH_LOCATIONSET) {
10847 /*
10848 * Extract the old locset, and then evaluate the result of the
10849 * expression for all the element in the locset. use it to grow
10850 * up a new locset.
10851 */
10852 CHECK_TYPE0(XPATH_LOCATIONSET);
10853 obj = valuePop(ctxt);
10854 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010855
William M. Brack08171912003-12-29 02:52:11 +000010856 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010857 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010858 ctxt->context->contextSize = 0;
10859 ctxt->context->proximityPosition = 0;
10860 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10861 res = valuePop(ctxt);
10862 if (res != NULL)
10863 xmlXPathFreeObject(res);
10864 valuePush(ctxt, obj);
10865 CHECK_ERROR0;
10866 return (total);
10867 }
10868 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010869
William M. Brack08171912003-12-29 02:52:11 +000010870 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010871 /*
William M. Brack08171912003-12-29 02:52:11 +000010872 * Run the evaluation with a node list made of a
10873 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010874 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010875 ctxt->context->node = oldlocset->locTab[i]->user;
10876 ctxt->context->contextSize = oldlocset->locNr;
10877 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010878 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10879 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010880
Daniel Veillardf06307e2001-07-03 10:35:50 +000010881 if (op->ch2 != -1)
10882 total +=
10883 xmlXPathCompOpEval(ctxt,
10884 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010885 if (ctxt->error != XPATH_EXPRESSION_OK) {
10886 xmlXPathFreeObject(obj);
10887 return(0);
10888 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010889
Daniel Veillardf06307e2001-07-03 10:35:50 +000010890 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010891 if (res->type == XPATH_LOCATIONSET) {
10892 xmlLocationSetPtr rloc =
10893 (xmlLocationSetPtr)res->user;
10894 for (j=0; j<rloc->locNr; j++) {
10895 range = xmlXPtrNewRange(
10896 oldlocset->locTab[i]->user,
10897 oldlocset->locTab[i]->index,
10898 rloc->locTab[j]->user2,
10899 rloc->locTab[j]->index2);
10900 if (range != NULL) {
10901 xmlXPtrLocationSetAdd(newlocset, range);
10902 }
10903 }
10904 } else {
10905 range = xmlXPtrNewRangeNodeObject(
10906 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10907 if (range != NULL) {
10908 xmlXPtrLocationSetAdd(newlocset,range);
10909 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010910 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010911
Daniel Veillardf06307e2001-07-03 10:35:50 +000010912 /*
10913 * Cleanup
10914 */
10915 if (res != NULL)
10916 xmlXPathFreeObject(res);
10917 if (ctxt->value == tmp) {
10918 res = valuePop(ctxt);
10919 xmlXPathFreeObject(res);
10920 }
10921
10922 ctxt->context->node = NULL;
10923 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010924 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010925 CHECK_TYPE0(XPATH_NODESET);
10926 obj = valuePop(ctxt);
10927 oldset = obj->nodesetval;
10928 ctxt->context->node = NULL;
10929
10930 newlocset = xmlXPtrLocationSetCreate(NULL);
10931
10932 if (oldset != NULL) {
10933 for (i = 0; i < oldset->nodeNr; i++) {
10934 /*
10935 * Run the evaluation with a node list made of a single item
10936 * in the nodeset.
10937 */
10938 ctxt->context->node = oldset->nodeTab[i];
10939 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10940 valuePush(ctxt, tmp);
10941
10942 if (op->ch2 != -1)
10943 total +=
10944 xmlXPathCompOpEval(ctxt,
10945 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010946 if (ctxt->error != XPATH_EXPRESSION_OK) {
10947 xmlXPathFreeObject(obj);
10948 return(0);
10949 }
William M. Brack08171912003-12-29 02:52:11 +000010950
William M. Brack08171912003-12-29 02:52:11 +000010951 res = valuePop(ctxt);
10952 range =
10953 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10954 res);
10955 if (range != NULL) {
10956 xmlXPtrLocationSetAdd(newlocset, range);
10957 }
10958
10959 /*
10960 * Cleanup
10961 */
10962 if (res != NULL)
10963 xmlXPathFreeObject(res);
10964 if (ctxt->value == tmp) {
10965 res = valuePop(ctxt);
10966 xmlXPathFreeObject(res);
10967 }
10968
10969 ctxt->context->node = NULL;
10970 }
10971 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010972 }
10973
10974 /*
10975 * The result is used as the new evaluation set.
10976 */
10977 xmlXPathFreeObject(obj);
10978 ctxt->context->node = NULL;
10979 ctxt->context->contextSize = -1;
10980 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010981 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010982 return (total);
10983 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010984#endif /* LIBXML_XPTR_ENABLED */
10985 }
10986 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010987 "XPath: unknown precompiled operation %d\n", op->op);
10988 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010989}
10990
Daniel Veillard56de87e2005-02-16 00:22:29 +000010991#ifdef XPATH_STREAMING
10992/**
10993 * xmlXPathRunStreamEval:
10994 * @ctxt: the XPath parser context with the compiled expression
10995 *
10996 * Evaluate the Precompiled Streamable XPath expression in the given context.
10997 */
10998static xmlXPathObjectPtr
10999xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011000 int max_depth, min_depth;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011001 int from_root;
11002 int ret, depth;
William M. Brack12d37ab2005-02-21 13:54:07 +000011003 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011004 xmlXPathObjectPtr retval;
11005 xmlStreamCtxtPtr patstream;
11006
11007 int nb_nodes = 0;
11008
11009 if ((ctxt == NULL) || (comp == NULL))
11010 return(NULL);
11011 max_depth = xmlPatternMaxDepth(comp);
11012 if (max_depth == -1)
11013 return(NULL);
11014 if (max_depth == -2)
11015 max_depth = 10000;
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011016 min_depth = xmlPatternMinDepth(comp);
11017 if (min_depth == -1)
11018 return(NULL);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011019 from_root = xmlPatternFromRoot(comp);
11020 if (from_root < 0)
11021 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011022#if 0
11023 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11024#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011025
11026 retval = xmlXPathNewNodeSet(NULL);
11027 if (retval == NULL)
11028 return(NULL);
11029
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011030 /*
11031 * handle the special cases of / amd . being matched
11032 */
11033 if (min_depth == 0) {
11034 if (from_root) {
11035 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11036 } else {
11037 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11038 }
11039 }
11040 if (max_depth == 0) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011041 return(retval);
11042 }
Daniel Veillardf03a8cd2005-09-04 12:01:57 +000011043
Daniel Veillard56de87e2005-02-16 00:22:29 +000011044 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011045 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011046 } else if (ctxt->node != NULL) {
11047 switch (ctxt->node->type) {
11048 case XML_ELEMENT_NODE:
11049 case XML_DOCUMENT_NODE:
11050 case XML_DOCUMENT_FRAG_NODE:
11051 case XML_HTML_DOCUMENT_NODE:
11052#ifdef LIBXML_DOCB_ENABLED
11053 case XML_DOCB_DOCUMENT_NODE:
11054#endif
11055 cur = ctxt->node;
11056 break;
11057 case XML_ATTRIBUTE_NODE:
11058 case XML_TEXT_NODE:
11059 case XML_CDATA_SECTION_NODE:
11060 case XML_ENTITY_REF_NODE:
11061 case XML_ENTITY_NODE:
11062 case XML_PI_NODE:
11063 case XML_COMMENT_NODE:
11064 case XML_NOTATION_NODE:
11065 case XML_DTD_NODE:
11066 case XML_DOCUMENT_TYPE_NODE:
11067 case XML_ELEMENT_DECL:
11068 case XML_ATTRIBUTE_DECL:
11069 case XML_ENTITY_DECL:
11070 case XML_NAMESPACE_DECL:
11071 case XML_XINCLUDE_START:
11072 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011073 break;
11074 }
11075 limit = cur;
11076 }
11077 if (cur == NULL)
11078 return(retval);
11079
11080 patstream = xmlPatternGetStreamCtxt(comp);
11081 if (patstream == NULL) {
11082 return(retval);
11083 }
11084
11085 if (from_root) {
11086 ret = xmlStreamPush(patstream, NULL, NULL);
11087 if (ret < 0) {
11088 } else if (ret == 1) {
11089 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11090 }
11091 }
11092
11093 depth = 0;
11094 goto scan_children;
11095 do {
11096next_node:
11097 nb_nodes++;
11098 if (cur->type == XML_ELEMENT_NODE) {
11099 ret = xmlStreamPush(patstream, cur->name,
11100 (cur->ns ? cur->ns->href : NULL));
11101 if (ret < 0) {
11102 } else if (ret == 1) {
11103 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11104 }
11105 if ((cur->children == NULL) || (depth >= max_depth)) {
11106 ret = xmlStreamPop(patstream);
William M. Brackfbb619f2005-06-06 13:49:18 +000011107 while (cur->next != NULL) {
11108 cur = cur->next;
11109 if ((cur->type != XML_ENTITY_DECL) &&
11110 (cur->type != XML_DTD_NODE))
11111 goto next_node;
11112 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011113 }
11114 }
11115
11116scan_children:
11117 if ((cur->children != NULL) && (depth < max_depth)) {
11118 /*
11119 * Do not descend on entities declarations
11120 */
11121 if (cur->children->type != XML_ENTITY_DECL) {
11122 cur = cur->children;
11123 depth++;
11124 /*
11125 * Skip DTDs
11126 */
11127 if (cur->type != XML_DTD_NODE)
11128 continue;
11129 }
11130 }
11131
11132 if (cur == limit)
11133 break;
11134
11135 while (cur->next != NULL) {
11136 cur = cur->next;
11137 if ((cur->type != XML_ENTITY_DECL) &&
11138 (cur->type != XML_DTD_NODE))
11139 goto next_node;
11140 }
11141
11142 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011143 cur = cur->parent;
11144 depth--;
11145 if ((cur == NULL) || (cur == limit))
11146 goto done;
William M. Brackfbb619f2005-06-06 13:49:18 +000011147 if (cur->type == XML_ELEMENT_NODE)
11148 ret = xmlStreamPop(patstream);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011149 if (cur->next != NULL) {
11150 cur = cur->next;
11151 break;
11152 }
11153 } while (cur != NULL);
11154
11155 } while ((cur != NULL) && (depth >= 0));
11156done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011157#if 0
11158 printf("stream eval: checked %d nodes selected %d\n",
11159 nb_nodes, retval->nodesetval->nodeNr);
11160#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011161 xmlFreeStreamCtxt(patstream);
11162 return(retval);
11163}
11164#endif /* XPATH_STREAMING */
11165
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011166/**
11167 * xmlXPathRunEval:
11168 * @ctxt: the XPath parser context with the compiled expression
11169 *
11170 * Evaluate the Precompiled XPath expression in the given context.
11171 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011172static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011173xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11174 xmlXPathCompExprPtr comp;
11175
11176 if ((ctxt == NULL) || (ctxt->comp == NULL))
11177 return;
11178
11179 if (ctxt->valueTab == NULL) {
11180 /* Allocate the value stack */
11181 ctxt->valueTab = (xmlXPathObjectPtr *)
11182 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11183 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011184 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011185 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011186 }
11187 ctxt->valueNr = 0;
11188 ctxt->valueMax = 10;
11189 ctxt->value = NULL;
11190 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011191#ifdef XPATH_STREAMING
11192 if (ctxt->comp->stream) {
11193 xmlXPathObjectPtr ret;
11194 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11195 if (ret != NULL) {
11196 valuePush(ctxt, ret);
11197 return;
11198 }
11199 }
11200#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011201 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011202 if(comp->last < 0) {
11203 xmlGenericError(xmlGenericErrorContext,
11204 "xmlXPathRunEval: last is less than zero\n");
11205 return;
11206 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011207 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11208}
11209
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011210/************************************************************************
11211 * *
11212 * Public interfaces *
11213 * *
11214 ************************************************************************/
11215
11216/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011217 * xmlXPathEvalPredicate:
11218 * @ctxt: the XPath context
11219 * @res: the Predicate Expression evaluation result
11220 *
11221 * Evaluate a predicate result for the current node.
11222 * A PredicateExpr is evaluated by evaluating the Expr and converting
11223 * the result to a boolean. If the result is a number, the result will
11224 * be converted to true if the number is equal to the position of the
11225 * context node in the context node list (as returned by the position
11226 * function) and will be converted to false otherwise; if the result
11227 * is not a number, then the result will be converted as if by a call
11228 * to the boolean function.
11229 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011230 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011231 */
11232int
11233xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011234 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011235 switch (res->type) {
11236 case XPATH_BOOLEAN:
11237 return(res->boolval);
11238 case XPATH_NUMBER:
11239 return(res->floatval == ctxt->proximityPosition);
11240 case XPATH_NODESET:
11241 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011242 if (res->nodesetval == NULL)
11243 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011244 return(res->nodesetval->nodeNr != 0);
11245 case XPATH_STRING:
11246 return((res->stringval != NULL) &&
11247 (xmlStrlen(res->stringval) != 0));
11248 default:
11249 STRANGE
11250 }
11251 return(0);
11252}
11253
11254/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011255 * xmlXPathEvaluatePredicateResult:
11256 * @ctxt: the XPath Parser context
11257 * @res: the Predicate Expression evaluation result
11258 *
11259 * Evaluate a predicate result for the current node.
11260 * A PredicateExpr is evaluated by evaluating the Expr and converting
11261 * the result to a boolean. If the result is a number, the result will
11262 * be converted to true if the number is equal to the position of the
11263 * context node in the context node list (as returned by the position
11264 * function) and will be converted to false otherwise; if the result
11265 * is not a number, then the result will be converted as if by a call
11266 * to the boolean function.
11267 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011268 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011269 */
11270int
11271xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11272 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011273 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011274 switch (res->type) {
11275 case XPATH_BOOLEAN:
11276 return(res->boolval);
11277 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011278#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011279 return((res->floatval == ctxt->context->proximityPosition) &&
11280 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011281#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011282 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011283#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011284 case XPATH_NODESET:
11285 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011286 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011287 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011288 return(res->nodesetval->nodeNr != 0);
11289 case XPATH_STRING:
11290 return((res->stringval != NULL) &&
11291 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011292#ifdef LIBXML_XPTR_ENABLED
11293 case XPATH_LOCATIONSET:{
11294 xmlLocationSetPtr ptr = res->user;
11295 if (ptr == NULL)
11296 return(0);
11297 return (ptr->locNr != 0);
11298 }
11299#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011300 default:
11301 STRANGE
11302 }
11303 return(0);
11304}
11305
Daniel Veillard56de87e2005-02-16 00:22:29 +000011306#ifdef XPATH_STREAMING
11307/**
11308 * xmlXPathTryStreamCompile:
11309 * @ctxt: an XPath context
11310 * @str: the XPath expression
11311 *
11312 * Try to compile the XPath expression as a streamable subset.
11313 *
11314 * Returns the compiled expression or NULL if failed to compile.
11315 */
11316static xmlXPathCompExprPtr
11317xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11318 /*
11319 * Optimization: use streaming patterns when the XPath expression can
11320 * be compiled to a stream lookup
11321 */
11322 xmlPatternPtr stream;
11323 xmlXPathCompExprPtr comp;
11324 xmlDictPtr dict = NULL;
11325 const xmlChar **namespaces = NULL;
11326 xmlNsPtr ns;
11327 int i, j;
11328
11329 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11330 (!xmlStrchr(str, '@'))) {
Daniel Veillard1f33c4d2005-07-10 21:38:31 +000011331 const xmlChar *tmp;
11332
11333 /*
11334 * We don't try to handle :: constructs, just the simplied form at
11335 * this point
11336 */
11337 tmp = xmlStrchr(str, ':');
11338 if ((tmp != NULL) && (tmp[1] == ':'))
11339 return(NULL);
11340
Daniel Veillard56de87e2005-02-16 00:22:29 +000011341 if (ctxt != NULL) {
11342 dict = ctxt->dict;
11343 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000011344 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000011345 if (namespaces == NULL) {
11346 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11347 return(NULL);
11348 }
11349 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11350 ns = ctxt->namespaces[j];
11351 namespaces[i++] = ns->href;
11352 namespaces[i++] = ns->prefix;
11353 }
11354 namespaces[i++] = NULL;
11355 namespaces[i++] = NULL;
11356 }
11357 }
11358
William M. Brackea152c02005-06-09 18:12:28 +000011359 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
11360 &namespaces[0]);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011361 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11362 comp = xmlXPathNewCompExpr();
11363 if (comp == NULL) {
11364 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11365 return(NULL);
11366 }
11367 comp->stream = stream;
11368 comp->dict = dict;
11369 if (comp->dict)
11370 xmlDictReference(comp->dict);
11371 return(comp);
11372 }
11373 xmlFreePattern(stream);
11374 }
11375 return(NULL);
11376}
11377#endif /* XPATH_STREAMING */
11378
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011379/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011380 * xmlXPathCtxtCompile:
11381 * @ctxt: an XPath context
11382 * @str: the XPath expression
11383 *
11384 * Compile an XPath expression
11385 *
11386 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11387 * the caller has to free the object.
11388 */
11389xmlXPathCompExprPtr
11390xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11391 xmlXPathParserContextPtr pctxt;
11392 xmlXPathCompExprPtr comp;
11393
Daniel Veillard56de87e2005-02-16 00:22:29 +000011394#ifdef XPATH_STREAMING
11395 comp = xmlXPathTryStreamCompile(ctxt, str);
11396 if (comp != NULL)
11397 return(comp);
11398#endif
11399
Daniel Veillard4773df22004-01-23 13:15:13 +000011400 xmlXPathInit();
11401
11402 pctxt = xmlXPathNewParserContext(str, ctxt);
11403 xmlXPathCompileExpr(pctxt);
11404
11405 if( pctxt->error != XPATH_EXPRESSION_OK )
11406 {
11407 xmlXPathFreeParserContext(pctxt);
Daniel Veillard24505b02005-07-28 23:49:35 +000011408 return(NULL);
Daniel Veillard4773df22004-01-23 13:15:13 +000011409 }
11410
11411 if (*pctxt->cur != 0) {
11412 /*
11413 * aleksey: in some cases this line prints *second* error message
11414 * (see bug #78858) and probably this should be fixed.
11415 * However, we are not sure that all error messages are printed
11416 * out in other places. It's not critical so we leave it as-is for now
11417 */
11418 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11419 comp = NULL;
11420 } else {
11421 comp = pctxt->comp;
11422 pctxt->comp = NULL;
11423 }
11424 xmlXPathFreeParserContext(pctxt);
11425 if (comp != NULL) {
11426 comp->expr = xmlStrdup(str);
11427#ifdef DEBUG_EVAL_COUNTS
11428 comp->string = xmlStrdup(str);
11429 comp->nb = 0;
11430#endif
11431 }
11432 return(comp);
11433}
11434
11435/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011436 * xmlXPathCompile:
11437 * @str: the XPath expression
11438 *
11439 * Compile an XPath expression
11440 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011441 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011442 * the caller has to free the object.
11443 */
11444xmlXPathCompExprPtr
11445xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011446 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011447}
11448
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011449/**
11450 * xmlXPathCompiledEval:
11451 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011452 * @ctx: the XPath context
11453 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011454 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011455 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011456 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011457 * the caller has to free the object.
11458 */
11459xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011460xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011461 xmlXPathParserContextPtr ctxt;
11462 xmlXPathObjectPtr res, tmp, init = NULL;
11463 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011464#ifndef LIBXML_THREAD_ENABLED
11465 static int reentance = 0;
11466#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011467
William M. Brackf13f77f2004-11-12 16:03:48 +000011468 CHECK_CTXT(ctx)
11469
11470 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011471 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011472 xmlXPathInit();
11473
Daniel Veillard81463942001-10-16 12:34:39 +000011474#ifndef LIBXML_THREAD_ENABLED
11475 reentance++;
11476 if (reentance > 1)
11477 xmlXPathDisableOptimizer = 1;
11478#endif
11479
Daniel Veillardf06307e2001-07-03 10:35:50 +000011480#ifdef DEBUG_EVAL_COUNTS
11481 comp->nb++;
11482 if ((comp->string != NULL) && (comp->nb > 100)) {
11483 fprintf(stderr, "100 x %s\n", comp->string);
11484 comp->nb = 0;
11485 }
11486#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011487 ctxt = xmlXPathCompParserContext(comp, ctx);
11488 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011489
11490 if (ctxt->value == NULL) {
11491 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011492 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011493 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011494 } else {
11495 res = valuePop(ctxt);
11496 }
11497
Daniel Veillardf06307e2001-07-03 10:35:50 +000011498
Owen Taylor3473f882001-02-23 17:55:21 +000011499 do {
11500 tmp = valuePop(ctxt);
11501 if (tmp != NULL) {
11502 if (tmp != init)
11503 stack++;
11504 xmlXPathFreeObject(tmp);
11505 }
11506 } while (tmp != NULL);
11507 if ((stack != 0) && (res != NULL)) {
11508 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011509 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011510 stack);
11511 }
11512 if (ctxt->error != XPATH_EXPRESSION_OK) {
11513 xmlXPathFreeObject(res);
11514 res = NULL;
11515 }
11516
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011517
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011518 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011519 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011520#ifndef LIBXML_THREAD_ENABLED
11521 reentance--;
11522#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011523 return(res);
11524}
11525
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011526/**
11527 * xmlXPathEvalExpr:
11528 * @ctxt: the XPath Parser context
11529 *
11530 * Parse and evaluate an XPath expression in the given context,
11531 * then push the result on the context stack
11532 */
11533void
11534xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011535#ifdef XPATH_STREAMING
11536 xmlXPathCompExprPtr comp;
11537#endif
11538
Daniel Veillarda82b1822004-11-08 16:24:57 +000011539 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011540
11541#ifdef XPATH_STREAMING
11542 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11543 if (comp != NULL) {
11544 if (ctxt->comp != NULL)
11545 xmlXPathFreeCompExpr(ctxt->comp);
11546 ctxt->comp = comp;
11547 if (ctxt->cur != NULL)
11548 while (*ctxt->cur != 0) ctxt->cur++;
11549 } else
11550#endif
11551 {
11552 xmlXPathCompileExpr(ctxt);
11553 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011554 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011555 xmlXPathRunEval(ctxt);
11556}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011557
11558/**
11559 * xmlXPathEval:
11560 * @str: the XPath expression
11561 * @ctx: the XPath context
11562 *
11563 * Evaluate the XPath Location Path in the given context.
11564 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011565 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011566 * the caller has to free the object.
11567 */
11568xmlXPathObjectPtr
11569xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11570 xmlXPathParserContextPtr ctxt;
11571 xmlXPathObjectPtr res, tmp, init = NULL;
11572 int stack = 0;
11573
William M. Brackf13f77f2004-11-12 16:03:48 +000011574 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011575
William M. Brackf13f77f2004-11-12 16:03:48 +000011576 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011577
11578 ctxt = xmlXPathNewParserContext(str, ctx);
11579 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011580
11581 if (ctxt->value == NULL) {
11582 xmlGenericError(xmlGenericErrorContext,
11583 "xmlXPathEval: evaluation failed\n");
11584 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011585 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11586#ifdef XPATH_STREAMING
11587 && (ctxt->comp->stream == NULL)
11588#endif
11589 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011590 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11591 res = NULL;
11592 } else {
11593 res = valuePop(ctxt);
11594 }
11595
11596 do {
11597 tmp = valuePop(ctxt);
11598 if (tmp != NULL) {
11599 if (tmp != init)
11600 stack++;
11601 xmlXPathFreeObject(tmp);
11602 }
11603 } while (tmp != NULL);
11604 if ((stack != 0) && (res != NULL)) {
11605 xmlGenericError(xmlGenericErrorContext,
11606 "xmlXPathEval: %d object left on the stack\n",
11607 stack);
11608 }
11609 if (ctxt->error != XPATH_EXPRESSION_OK) {
11610 xmlXPathFreeObject(res);
11611 res = NULL;
11612 }
11613
Owen Taylor3473f882001-02-23 17:55:21 +000011614 xmlXPathFreeParserContext(ctxt);
11615 return(res);
11616}
11617
11618/**
11619 * xmlXPathEvalExpression:
11620 * @str: the XPath expression
11621 * @ctxt: the XPath context
11622 *
11623 * Evaluate the XPath expression in the given context.
11624 *
11625 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11626 * the caller has to free the object.
11627 */
11628xmlXPathObjectPtr
11629xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11630 xmlXPathParserContextPtr pctxt;
11631 xmlXPathObjectPtr res, tmp;
11632 int stack = 0;
11633
William M. Brackf13f77f2004-11-12 16:03:48 +000011634 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011635
William M. Brackf13f77f2004-11-12 16:03:48 +000011636 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011637
11638 pctxt = xmlXPathNewParserContext(str, ctxt);
11639 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011640
11641 if (*pctxt->cur != 0) {
11642 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11643 res = NULL;
11644 } else {
11645 res = valuePop(pctxt);
11646 }
11647 do {
11648 tmp = valuePop(pctxt);
11649 if (tmp != NULL) {
11650 xmlXPathFreeObject(tmp);
11651 stack++;
11652 }
11653 } while (tmp != NULL);
11654 if ((stack != 0) && (res != NULL)) {
11655 xmlGenericError(xmlGenericErrorContext,
11656 "xmlXPathEvalExpression: %d object left on the stack\n",
11657 stack);
11658 }
11659 xmlXPathFreeParserContext(pctxt);
11660 return(res);
11661}
11662
Daniel Veillard42766c02002-08-22 20:52:17 +000011663/************************************************************************
11664 * *
11665 * Extra functions not pertaining to the XPath spec *
11666 * *
11667 ************************************************************************/
11668/**
11669 * xmlXPathEscapeUriFunction:
11670 * @ctxt: the XPath Parser context
11671 * @nargs: the number of arguments
11672 *
11673 * Implement the escape-uri() XPath function
11674 * string escape-uri(string $str, bool $escape-reserved)
11675 *
11676 * This function applies the URI escaping rules defined in section 2 of [RFC
11677 * 2396] to the string supplied as $uri-part, which typically represents all
11678 * or part of a URI. The effect of the function is to replace any special
11679 * character in the string by an escape sequence of the form %xx%yy...,
11680 * where xxyy... is the hexadecimal representation of the octets used to
11681 * represent the character in UTF-8.
11682 *
11683 * The set of characters that are escaped depends on the setting of the
11684 * boolean argument $escape-reserved.
11685 *
11686 * If $escape-reserved is true, all characters are escaped other than lower
11687 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11688 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11689 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11690 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11691 * A-F).
11692 *
11693 * If $escape-reserved is false, the behavior differs in that characters
11694 * referred to in [RFC 2396] as reserved characters are not escaped. These
11695 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11696 *
11697 * [RFC 2396] does not define whether escaped URIs should use lower case or
11698 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11699 * compared using string comparison functions, this function must always use
11700 * the upper-case letters A-F.
11701 *
11702 * Generally, $escape-reserved should be set to true when escaping a string
11703 * that is to form a single part of a URI, and to false when escaping an
11704 * entire URI or URI reference.
11705 *
11706 * In the case of non-ascii characters, the string is encoded according to
11707 * utf-8 and then converted according to RFC 2396.
11708 *
11709 * Examples
11710 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11711 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11712 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11713 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11714 *
11715 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011716static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011717xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11718 xmlXPathObjectPtr str;
11719 int escape_reserved;
11720 xmlBufferPtr target;
11721 xmlChar *cptr;
11722 xmlChar escape[4];
11723
11724 CHECK_ARITY(2);
11725
11726 escape_reserved = xmlXPathPopBoolean(ctxt);
11727
11728 CAST_TO_STRING;
11729 str = valuePop(ctxt);
11730
11731 target = xmlBufferCreate();
11732
11733 escape[0] = '%';
11734 escape[3] = 0;
11735
11736 if (target) {
11737 for (cptr = str->stringval; *cptr; cptr++) {
11738 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11739 (*cptr >= 'a' && *cptr <= 'z') ||
11740 (*cptr >= '0' && *cptr <= '9') ||
11741 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11742 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11743 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11744 (*cptr == '%' &&
11745 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11746 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11747 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11748 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11749 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11750 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11751 (!escape_reserved &&
11752 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11753 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11754 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11755 *cptr == ','))) {
11756 xmlBufferAdd(target, cptr, 1);
11757 } else {
11758 if ((*cptr >> 4) < 10)
11759 escape[1] = '0' + (*cptr >> 4);
11760 else
11761 escape[1] = 'A' - 10 + (*cptr >> 4);
11762 if ((*cptr & 0xF) < 10)
11763 escape[2] = '0' + (*cptr & 0xF);
11764 else
11765 escape[2] = 'A' - 10 + (*cptr & 0xF);
11766
11767 xmlBufferAdd(target, &escape[0], 3);
11768 }
11769 }
11770 }
11771 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11772 xmlBufferFree(target);
11773 xmlXPathFreeObject(str);
11774}
11775
Owen Taylor3473f882001-02-23 17:55:21 +000011776/**
11777 * xmlXPathRegisterAllFunctions:
11778 * @ctxt: the XPath context
11779 *
11780 * Registers all default XPath functions in this context
11781 */
11782void
11783xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11784{
11785 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11786 xmlXPathBooleanFunction);
11787 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11788 xmlXPathCeilingFunction);
11789 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11790 xmlXPathCountFunction);
11791 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11792 xmlXPathConcatFunction);
11793 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11794 xmlXPathContainsFunction);
11795 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11796 xmlXPathIdFunction);
11797 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11798 xmlXPathFalseFunction);
11799 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11800 xmlXPathFloorFunction);
11801 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11802 xmlXPathLastFunction);
11803 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11804 xmlXPathLangFunction);
11805 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11806 xmlXPathLocalNameFunction);
11807 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11808 xmlXPathNotFunction);
11809 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11810 xmlXPathNameFunction);
11811 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11812 xmlXPathNamespaceURIFunction);
11813 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11814 xmlXPathNormalizeFunction);
11815 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11816 xmlXPathNumberFunction);
11817 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11818 xmlXPathPositionFunction);
11819 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11820 xmlXPathRoundFunction);
11821 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11822 xmlXPathStringFunction);
11823 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11824 xmlXPathStringLengthFunction);
11825 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11826 xmlXPathStartsWithFunction);
11827 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11828 xmlXPathSubstringFunction);
11829 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11830 xmlXPathSubstringBeforeFunction);
11831 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11832 xmlXPathSubstringAfterFunction);
11833 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11834 xmlXPathSumFunction);
11835 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11836 xmlXPathTrueFunction);
11837 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11838 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011839
11840 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11841 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11842 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011843}
11844
11845#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000011846#define bottom_xpath
11847#include "elfgcchack.h"