blob: 8ee080521f0967eebdc909f6eb482cf04341fde0 [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 Veillard5fc1f082002-03-27 09:05:40 +000092double xmlXPathNZERO = 0;
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
William M. Brack08171912003-12-29 02:52:11 +0000192/*
193 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
194 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000195static const char *xmlXPathErrorMessages[] = {
196 "Ok\n",
197 "Number encoding\n",
198 "Unfinished literal\n",
199 "Start of literal\n",
200 "Expected $ for variable reference\n",
201 "Undefined variable\n",
202 "Invalid predicate\n",
203 "Invalid expression\n",
204 "Missing closing curly brace\n",
205 "Unregistered function\n",
206 "Invalid operand\n",
207 "Invalid type\n",
208 "Invalid number of arguments\n",
209 "Invalid context size\n",
210 "Invalid context position\n",
211 "Memory allocation error\n",
212 "Syntax error\n",
213 "Resource error\n",
214 "Sub resource error\n",
215 "Undefined namespace prefix\n",
216 "Encoding error\n",
Daniel Veillard57b25162004-11-06 14:50:18 +0000217 "Char out of XML range\n",
William M. Brackcd65bc92005-01-06 09:39:18 +0000218 "Invalid or incomplete context\n",
219 "?? Unknown error ??\n" /* Must be last in the list! */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000220};
William M. Brackcd65bc92005-01-06 09:39:18 +0000221#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
222 sizeof(xmlXPathErrorMessages[0])) - 1)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000223/**
224 * xmlXPathErrMemory:
225 * @ctxt: an XPath context
226 * @extra: extra informations
227 *
228 * Handle a redefinition of attribute error
229 */
230static void
231xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
232{
233 if (ctxt != NULL) {
234 if (extra) {
235 xmlChar buf[200];
236
237 xmlStrPrintf(buf, 200,
238 BAD_CAST "Memory allocation failed : %s\n",
239 extra);
240 ctxt->lastError.message = (char *) xmlStrdup(buf);
241 } else {
242 ctxt->lastError.message = (char *)
243 xmlStrdup(BAD_CAST "Memory allocation failed\n");
244 }
245 ctxt->lastError.domain = XML_FROM_XPATH;
246 ctxt->lastError.code = XML_ERR_NO_MEMORY;
247 if (ctxt->error != NULL)
248 ctxt->error(ctxt->userData, &ctxt->lastError);
249 } else {
250 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000251 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000252 NULL, NULL, XML_FROM_XPATH,
253 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
254 extra, NULL, NULL, 0, 0,
255 "Memory allocation failed : %s\n", extra);
256 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000257 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000258 NULL, NULL, XML_FROM_XPATH,
259 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
260 NULL, NULL, NULL, 0, 0,
261 "Memory allocation failed\n");
262 }
263}
264
265/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000266 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000267 * @ctxt: an XPath parser context
268 * @extra: extra informations
269 *
270 * Handle a redefinition of attribute error
271 */
272static void
273xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
274{
275 ctxt->error = XPATH_MEMORY_ERROR;
276 if (ctxt == NULL)
277 xmlXPathErrMemory(NULL, extra);
278 else
279 xmlXPathErrMemory(ctxt->context, extra);
280}
281
282/**
283 * xmlXPathErr:
284 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000285 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000286 *
William M. Brackcd65bc92005-01-06 09:39:18 +0000287 * Handle an XPath error
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000288 */
289void
290xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
291{
William M. Brackcd65bc92005-01-06 09:39:18 +0000292 if ((error < 0) || (error > MAXERRNO))
293 error = MAXERRNO;
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000294 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000295 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000296 NULL, NULL, XML_FROM_XPATH,
297 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
298 XML_ERR_ERROR, NULL, 0,
299 NULL, NULL, NULL, 0, 0,
300 xmlXPathErrorMessages[error]);
301 return;
302 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000303 ctxt->error = error;
304 if (ctxt->context == NULL) {
305 __xmlRaiseError(NULL, NULL, NULL,
306 NULL, NULL, XML_FROM_XPATH,
307 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
308 XML_ERR_ERROR, NULL, 0,
309 (const char *) ctxt->base, NULL, NULL,
310 ctxt->cur - ctxt->base, 0,
311 xmlXPathErrorMessages[error]);
312 return;
313 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000314 ctxt->context->lastError.domain = XML_FROM_XPATH;
315 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
316 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000317 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000318 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
319 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
320 ctxt->context->lastError.node = ctxt->context->debugNode;
321 if (ctxt->context->error != NULL) {
322 ctxt->context->error(ctxt->context->userData,
323 &ctxt->context->lastError);
324 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000325 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000326 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
327 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
328 XML_ERR_ERROR, NULL, 0,
329 (const char *) ctxt->base, NULL, NULL,
330 ctxt->cur - ctxt->base, 0,
331 xmlXPathErrorMessages[error]);
332 }
333
334}
335
336/**
337 * xmlXPatherror:
338 * @ctxt: the XPath Parser context
339 * @file: the file name
340 * @line: the line number
341 * @no: the error number
342 *
343 * Formats an error message.
344 */
345void
346xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
347 int line ATTRIBUTE_UNUSED, int no) {
348 xmlXPathErr(ctxt, no);
349}
350
351
352/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000353 * *
354 * Parser Types *
355 * *
356 ************************************************************************/
357
358/*
359 * Types are private:
360 */
361
362typedef enum {
363 XPATH_OP_END=0,
364 XPATH_OP_AND,
365 XPATH_OP_OR,
366 XPATH_OP_EQUAL,
367 XPATH_OP_CMP,
368 XPATH_OP_PLUS,
369 XPATH_OP_MULT,
370 XPATH_OP_UNION,
371 XPATH_OP_ROOT,
372 XPATH_OP_NODE,
373 XPATH_OP_RESET,
374 XPATH_OP_COLLECT,
375 XPATH_OP_VALUE,
376 XPATH_OP_VARIABLE,
377 XPATH_OP_FUNCTION,
378 XPATH_OP_ARG,
379 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000380 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000381 XPATH_OP_SORT
382#ifdef LIBXML_XPTR_ENABLED
383 ,XPATH_OP_RANGETO
384#endif
385} xmlXPathOp;
386
387typedef enum {
388 AXIS_ANCESTOR = 1,
389 AXIS_ANCESTOR_OR_SELF,
390 AXIS_ATTRIBUTE,
391 AXIS_CHILD,
392 AXIS_DESCENDANT,
393 AXIS_DESCENDANT_OR_SELF,
394 AXIS_FOLLOWING,
395 AXIS_FOLLOWING_SIBLING,
396 AXIS_NAMESPACE,
397 AXIS_PARENT,
398 AXIS_PRECEDING,
399 AXIS_PRECEDING_SIBLING,
400 AXIS_SELF
401} xmlXPathAxisVal;
402
403typedef enum {
404 NODE_TEST_NONE = 0,
405 NODE_TEST_TYPE = 1,
406 NODE_TEST_PI = 2,
407 NODE_TEST_ALL = 3,
408 NODE_TEST_NS = 4,
409 NODE_TEST_NAME = 5
410} xmlXPathTestVal;
411
412typedef enum {
413 NODE_TYPE_NODE = 0,
414 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
415 NODE_TYPE_TEXT = XML_TEXT_NODE,
416 NODE_TYPE_PI = XML_PI_NODE
417} xmlXPathTypeVal;
418
419
420typedef struct _xmlXPathStepOp xmlXPathStepOp;
421typedef xmlXPathStepOp *xmlXPathStepOpPtr;
422struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000423 xmlXPathOp op; /* The identifier of the operation */
424 int ch1; /* First child */
425 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000426 int value;
427 int value2;
428 int value3;
429 void *value4;
430 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000431 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000432 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000433};
434
435struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000436 int nbStep; /* Number of steps in this expression */
437 int maxStep; /* Maximum number of steps allocated */
438 xmlXPathStepOp *steps; /* ops for computation of this expression */
439 int last; /* index of last step in expression */
440 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000441 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000442#ifdef DEBUG_EVAL_COUNTS
443 int nb;
444 xmlChar *string;
445#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000446#ifdef XPATH_STREAMING
447 xmlPatternPtr stream;
448#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000449};
450
451/************************************************************************
452 * *
453 * Parser Type functions *
454 * *
455 ************************************************************************/
456
457/**
458 * xmlXPathNewCompExpr:
459 *
460 * Create a new Xpath component
461 *
462 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
463 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000464static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000465xmlXPathNewCompExpr(void) {
466 xmlXPathCompExprPtr cur;
467
468 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
469 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000470 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000471 return(NULL);
472 }
473 memset(cur, 0, sizeof(xmlXPathCompExpr));
474 cur->maxStep = 10;
475 cur->nbStep = 0;
476 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
477 sizeof(xmlXPathStepOp));
478 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000479 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000480 xmlFree(cur);
481 return(NULL);
482 }
483 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
484 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000485#ifdef DEBUG_EVAL_COUNTS
486 cur->nb = 0;
487#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000488 return(cur);
489}
490
491/**
492 * xmlXPathFreeCompExpr:
493 * @comp: an XPATH comp
494 *
495 * Free up the memory allocated by @comp
496 */
497void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000498xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
499{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000500 xmlXPathStepOpPtr op;
501 int i;
502
503 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000504 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000505 if (comp->dict == NULL) {
506 for (i = 0; i < comp->nbStep; i++) {
507 op = &comp->steps[i];
508 if (op->value4 != NULL) {
509 if (op->op == XPATH_OP_VALUE)
510 xmlXPathFreeObject(op->value4);
511 else
512 xmlFree(op->value4);
513 }
514 if (op->value5 != NULL)
515 xmlFree(op->value5);
516 }
517 } else {
518 for (i = 0; i < comp->nbStep; i++) {
519 op = &comp->steps[i];
520 if (op->value4 != NULL) {
521 if (op->op == XPATH_OP_VALUE)
522 xmlXPathFreeObject(op->value4);
523 }
524 }
525 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000526 }
527 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000528 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000529 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000530#ifdef DEBUG_EVAL_COUNTS
531 if (comp->string != NULL) {
532 xmlFree(comp->string);
533 }
534#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +0000535#ifdef XPATH_STREAMING
536 if (comp->stream != NULL) {
537 xmlFreePatternList(comp->stream);
538 }
539#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000540 if (comp->expr != NULL) {
541 xmlFree(comp->expr);
542 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000543
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000544 xmlFree(comp);
545}
546
547/**
548 * xmlXPathCompExprAdd:
549 * @comp: the compiled expression
550 * @ch1: first child index
551 * @ch2: second child index
552 * @op: an op
553 * @value: the first int value
554 * @value2: the second int value
555 * @value3: the third int value
556 * @value4: the first string value
557 * @value5: the second string value
558 *
William M. Brack08171912003-12-29 02:52:11 +0000559 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000560 *
561 * Returns -1 in case of failure, the index otherwise
562 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000563static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000564xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
565 xmlXPathOp op, int value,
566 int value2, int value3, void *value4, void *value5) {
567 if (comp->nbStep >= comp->maxStep) {
568 xmlXPathStepOp *real;
569
570 comp->maxStep *= 2;
571 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
572 comp->maxStep * sizeof(xmlXPathStepOp));
573 if (real == NULL) {
574 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000575 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000576 return(-1);
577 }
578 comp->steps = real;
579 }
580 comp->last = comp->nbStep;
581 comp->steps[comp->nbStep].ch1 = ch1;
582 comp->steps[comp->nbStep].ch2 = ch2;
583 comp->steps[comp->nbStep].op = op;
584 comp->steps[comp->nbStep].value = value;
585 comp->steps[comp->nbStep].value2 = value2;
586 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000587 if ((comp->dict != NULL) &&
588 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
589 (op == XPATH_OP_COLLECT))) {
590 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000591 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000592 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000593 xmlFree(value4);
594 } else
595 comp->steps[comp->nbStep].value4 = NULL;
596 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000597 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000598 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000599 xmlFree(value5);
600 } else
601 comp->steps[comp->nbStep].value5 = NULL;
602 } else {
603 comp->steps[comp->nbStep].value4 = value4;
604 comp->steps[comp->nbStep].value5 = value5;
605 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000606 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000607 return(comp->nbStep++);
608}
609
Daniel Veillardf06307e2001-07-03 10:35:50 +0000610/**
611 * xmlXPathCompSwap:
612 * @comp: the compiled expression
613 * @op: operation index
614 *
615 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000616 */
617static void
618xmlXPathCompSwap(xmlXPathStepOpPtr op) {
619 int tmp;
620
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000621#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000622 /*
623 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000624 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000625 * application
626 */
627 if (xmlXPathDisableOptimizer)
628 return;
629#endif
630
Daniel Veillardf06307e2001-07-03 10:35:50 +0000631 tmp = op->ch1;
632 op->ch1 = op->ch2;
633 op->ch2 = tmp;
634}
635
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000636#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
637 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
638 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000639#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
640 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
641 (op), (val), (val2), (val3), (val4), (val5))
642
643#define PUSH_LEAVE_EXPR(op, val, val2) \
644xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
645
646#define PUSH_UNARY_EXPR(op, ch, val, val2) \
647xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
648
649#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000650xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
651 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000652
653/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000654 * *
655 * Debugging related functions *
656 * *
657 ************************************************************************/
658
Owen Taylor3473f882001-02-23 17:55:21 +0000659#define STRANGE \
660 xmlGenericError(xmlGenericErrorContext, \
661 "Internal error at %s:%d\n", \
662 __FILE__, __LINE__);
663
664#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000665static void
666xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000667 int i;
668 char shift[100];
669
670 for (i = 0;((i < depth) && (i < 25));i++)
671 shift[2 * i] = shift[2 * i + 1] = ' ';
672 shift[2 * i] = shift[2 * i + 1] = 0;
673 if (cur == NULL) {
674 fprintf(output, shift);
675 fprintf(output, "Node is NULL !\n");
676 return;
677
678 }
679
680 if ((cur->type == XML_DOCUMENT_NODE) ||
681 (cur->type == XML_HTML_DOCUMENT_NODE)) {
682 fprintf(output, shift);
683 fprintf(output, " /\n");
684 } else if (cur->type == XML_ATTRIBUTE_NODE)
685 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
686 else
687 xmlDebugDumpOneNode(output, cur, depth);
688}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000689static void
690xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000691 xmlNodePtr tmp;
692 int i;
693 char shift[100];
694
695 for (i = 0;((i < depth) && (i < 25));i++)
696 shift[2 * i] = shift[2 * i + 1] = ' ';
697 shift[2 * i] = shift[2 * i + 1] = 0;
698 if (cur == NULL) {
699 fprintf(output, shift);
700 fprintf(output, "Node is NULL !\n");
701 return;
702
703 }
704
705 while (cur != NULL) {
706 tmp = cur;
707 cur = cur->next;
708 xmlDebugDumpOneNode(output, tmp, depth);
709 }
710}
Owen Taylor3473f882001-02-23 17:55:21 +0000711
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000712static void
713xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000714 int i;
715 char shift[100];
716
717 for (i = 0;((i < depth) && (i < 25));i++)
718 shift[2 * i] = shift[2 * i + 1] = ' ';
719 shift[2 * i] = shift[2 * i + 1] = 0;
720
721 if (cur == NULL) {
722 fprintf(output, shift);
723 fprintf(output, "NodeSet is NULL !\n");
724 return;
725
726 }
727
Daniel Veillard911f49a2001-04-07 15:39:35 +0000728 if (cur != NULL) {
729 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
730 for (i = 0;i < cur->nodeNr;i++) {
731 fprintf(output, shift);
732 fprintf(output, "%d", i + 1);
733 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
734 }
Owen Taylor3473f882001-02-23 17:55:21 +0000735 }
736}
737
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000738static void
739xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000740 int i;
741 char shift[100];
742
743 for (i = 0;((i < depth) && (i < 25));i++)
744 shift[2 * i] = shift[2 * i + 1] = ' ';
745 shift[2 * i] = shift[2 * i + 1] = 0;
746
747 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
748 fprintf(output, shift);
749 fprintf(output, "Value Tree is NULL !\n");
750 return;
751
752 }
753
754 fprintf(output, shift);
755 fprintf(output, "%d", i + 1);
756 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
757}
Owen Taylor3473f882001-02-23 17:55:21 +0000758#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000759static void
760xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000761 int i;
762 char shift[100];
763
764 for (i = 0;((i < depth) && (i < 25));i++)
765 shift[2 * i] = shift[2 * i + 1] = ' ';
766 shift[2 * i] = shift[2 * i + 1] = 0;
767
768 if (cur == NULL) {
769 fprintf(output, shift);
770 fprintf(output, "LocationSet is NULL !\n");
771 return;
772
773 }
774
775 for (i = 0;i < cur->locNr;i++) {
776 fprintf(output, shift);
777 fprintf(output, "%d : ", i + 1);
778 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
779 }
780}
Daniel Veillard017b1082001-06-21 11:20:21 +0000781#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000782
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000783/**
784 * xmlXPathDebugDumpObject:
785 * @output: the FILE * to dump the output
786 * @cur: the object to inspect
787 * @depth: indentation level
788 *
789 * Dump the content of the object for debugging purposes
790 */
791void
792xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000793 int i;
794 char shift[100];
795
Daniel Veillarda82b1822004-11-08 16:24:57 +0000796 if (output == NULL) return;
797
Owen Taylor3473f882001-02-23 17:55:21 +0000798 for (i = 0;((i < depth) && (i < 25));i++)
799 shift[2 * i] = shift[2 * i + 1] = ' ';
800 shift[2 * i] = shift[2 * i + 1] = 0;
801
802 fprintf(output, shift);
803
804 if (cur == NULL) {
805 fprintf(output, "Object is empty (NULL)\n");
806 return;
807 }
808 switch(cur->type) {
809 case XPATH_UNDEFINED:
810 fprintf(output, "Object is uninitialized\n");
811 break;
812 case XPATH_NODESET:
813 fprintf(output, "Object is a Node Set :\n");
814 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
815 break;
816 case XPATH_XSLT_TREE:
817 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000818 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000819 break;
820 case XPATH_BOOLEAN:
821 fprintf(output, "Object is a Boolean : ");
822 if (cur->boolval) fprintf(output, "true\n");
823 else fprintf(output, "false\n");
824 break;
825 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000826 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000827 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000828 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000829 break;
830 case -1:
831 fprintf(output, "Object is a number : -Infinity\n");
832 break;
833 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000834 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000835 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000836 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
837 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000838 } else {
839 fprintf(output, "Object is a number : %0g\n", cur->floatval);
840 }
841 }
Owen Taylor3473f882001-02-23 17:55:21 +0000842 break;
843 case XPATH_STRING:
844 fprintf(output, "Object is a string : ");
845 xmlDebugDumpString(output, cur->stringval);
846 fprintf(output, "\n");
847 break;
848 case XPATH_POINT:
849 fprintf(output, "Object is a point : index %d in node", cur->index);
850 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
851 fprintf(output, "\n");
852 break;
853 case XPATH_RANGE:
854 if ((cur->user2 == NULL) ||
855 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
856 fprintf(output, "Object is a collapsed range :\n");
857 fprintf(output, shift);
858 if (cur->index >= 0)
859 fprintf(output, "index %d in ", cur->index);
860 fprintf(output, "node\n");
861 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
862 depth + 1);
863 } else {
864 fprintf(output, "Object is a range :\n");
865 fprintf(output, shift);
866 fprintf(output, "From ");
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 fprintf(output, shift);
873 fprintf(output, "To ");
874 if (cur->index2 >= 0)
875 fprintf(output, "index %d in ", cur->index2);
876 fprintf(output, "node\n");
877 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
878 depth + 1);
879 fprintf(output, "\n");
880 }
881 break;
882 case XPATH_LOCATIONSET:
883#if defined(LIBXML_XPTR_ENABLED)
884 fprintf(output, "Object is a Location Set:\n");
885 xmlXPathDebugDumpLocationSet(output,
886 (xmlLocationSetPtr) cur->user, depth);
887#endif
888 break;
889 case XPATH_USERS:
890 fprintf(output, "Object is user defined\n");
891 break;
892 }
893}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000894
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000895static void
896xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000897 xmlXPathStepOpPtr op, int depth) {
898 int i;
899 char shift[100];
900
901 for (i = 0;((i < depth) && (i < 25));i++)
902 shift[2 * i] = shift[2 * i + 1] = ' ';
903 shift[2 * i] = shift[2 * i + 1] = 0;
904
905 fprintf(output, shift);
906 if (op == NULL) {
907 fprintf(output, "Step is NULL\n");
908 return;
909 }
910 switch (op->op) {
911 case XPATH_OP_END:
912 fprintf(output, "END"); break;
913 case XPATH_OP_AND:
914 fprintf(output, "AND"); break;
915 case XPATH_OP_OR:
916 fprintf(output, "OR"); break;
917 case XPATH_OP_EQUAL:
918 if (op->value)
919 fprintf(output, "EQUAL =");
920 else
921 fprintf(output, "EQUAL !=");
922 break;
923 case XPATH_OP_CMP:
924 if (op->value)
925 fprintf(output, "CMP <");
926 else
927 fprintf(output, "CMP >");
928 if (!op->value2)
929 fprintf(output, "=");
930 break;
931 case XPATH_OP_PLUS:
932 if (op->value == 0)
933 fprintf(output, "PLUS -");
934 else if (op->value == 1)
935 fprintf(output, "PLUS +");
936 else if (op->value == 2)
937 fprintf(output, "PLUS unary -");
938 else if (op->value == 3)
939 fprintf(output, "PLUS unary - -");
940 break;
941 case XPATH_OP_MULT:
942 if (op->value == 0)
943 fprintf(output, "MULT *");
944 else if (op->value == 1)
945 fprintf(output, "MULT div");
946 else
947 fprintf(output, "MULT mod");
948 break;
949 case XPATH_OP_UNION:
950 fprintf(output, "UNION"); break;
951 case XPATH_OP_ROOT:
952 fprintf(output, "ROOT"); break;
953 case XPATH_OP_NODE:
954 fprintf(output, "NODE"); break;
955 case XPATH_OP_RESET:
956 fprintf(output, "RESET"); break;
957 case XPATH_OP_SORT:
958 fprintf(output, "SORT"); break;
959 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000960 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
961 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
962 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000963 const xmlChar *prefix = op->value4;
964 const xmlChar *name = op->value5;
965
966 fprintf(output, "COLLECT ");
967 switch (axis) {
968 case AXIS_ANCESTOR:
969 fprintf(output, " 'ancestors' "); break;
970 case AXIS_ANCESTOR_OR_SELF:
971 fprintf(output, " 'ancestors-or-self' "); break;
972 case AXIS_ATTRIBUTE:
973 fprintf(output, " 'attributes' "); break;
974 case AXIS_CHILD:
975 fprintf(output, " 'child' "); break;
976 case AXIS_DESCENDANT:
977 fprintf(output, " 'descendant' "); break;
978 case AXIS_DESCENDANT_OR_SELF:
979 fprintf(output, " 'descendant-or-self' "); break;
980 case AXIS_FOLLOWING:
981 fprintf(output, " 'following' "); break;
982 case AXIS_FOLLOWING_SIBLING:
983 fprintf(output, " 'following-siblings' "); break;
984 case AXIS_NAMESPACE:
985 fprintf(output, " 'namespace' "); break;
986 case AXIS_PARENT:
987 fprintf(output, " 'parent' "); break;
988 case AXIS_PRECEDING:
989 fprintf(output, " 'preceding' "); break;
990 case AXIS_PRECEDING_SIBLING:
991 fprintf(output, " 'preceding-sibling' "); break;
992 case AXIS_SELF:
993 fprintf(output, " 'self' "); break;
994 }
995 switch (test) {
996 case NODE_TEST_NONE:
997 fprintf(output, "'none' "); break;
998 case NODE_TEST_TYPE:
999 fprintf(output, "'type' "); break;
1000 case NODE_TEST_PI:
1001 fprintf(output, "'PI' "); break;
1002 case NODE_TEST_ALL:
1003 fprintf(output, "'all' "); break;
1004 case NODE_TEST_NS:
1005 fprintf(output, "'namespace' "); break;
1006 case NODE_TEST_NAME:
1007 fprintf(output, "'name' "); break;
1008 }
1009 switch (type) {
1010 case NODE_TYPE_NODE:
1011 fprintf(output, "'node' "); break;
1012 case NODE_TYPE_COMMENT:
1013 fprintf(output, "'comment' "); break;
1014 case NODE_TYPE_TEXT:
1015 fprintf(output, "'text' "); break;
1016 case NODE_TYPE_PI:
1017 fprintf(output, "'PI' "); break;
1018 }
1019 if (prefix != NULL)
1020 fprintf(output, "%s:", prefix);
1021 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001022 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001023 break;
1024
1025 }
1026 case XPATH_OP_VALUE: {
1027 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1028
1029 fprintf(output, "ELEM ");
1030 xmlXPathDebugDumpObject(output, object, 0);
1031 goto finish;
1032 }
1033 case XPATH_OP_VARIABLE: {
1034 const xmlChar *prefix = op->value5;
1035 const xmlChar *name = op->value4;
1036
1037 if (prefix != NULL)
1038 fprintf(output, "VARIABLE %s:%s", prefix, name);
1039 else
1040 fprintf(output, "VARIABLE %s", name);
1041 break;
1042 }
1043 case XPATH_OP_FUNCTION: {
1044 int nbargs = op->value;
1045 const xmlChar *prefix = op->value5;
1046 const xmlChar *name = op->value4;
1047
1048 if (prefix != NULL)
1049 fprintf(output, "FUNCTION %s:%s(%d args)",
1050 prefix, name, nbargs);
1051 else
1052 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1053 break;
1054 }
1055 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1056 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001057 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001058#ifdef LIBXML_XPTR_ENABLED
1059 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1060#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001061 default:
1062 fprintf(output, "UNKNOWN %d\n", op->op); return;
1063 }
1064 fprintf(output, "\n");
1065finish:
1066 if (op->ch1 >= 0)
1067 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1068 if (op->ch2 >= 0)
1069 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1070}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001071
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001072/**
1073 * xmlXPathDebugDumpCompExpr:
1074 * @output: the FILE * for the output
1075 * @comp: the precompiled XPath expression
1076 * @depth: the indentation level.
1077 *
1078 * Dumps the tree of the compiled XPath expression.
1079 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001080void
1081xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1082 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001083 int i;
1084 char shift[100];
1085
Daniel Veillarda82b1822004-11-08 16:24:57 +00001086 if ((output == NULL) || (comp == NULL)) return;
1087
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001088 for (i = 0;((i < depth) && (i < 25));i++)
1089 shift[2 * i] = shift[2 * i + 1] = ' ';
1090 shift[2 * i] = shift[2 * i + 1] = 0;
1091
1092 fprintf(output, shift);
1093
1094 if (comp == NULL) {
1095 fprintf(output, "Compiled Expression is NULL\n");
1096 return;
1097 }
1098 fprintf(output, "Compiled Expression : %d elements\n",
1099 comp->nbStep);
1100 i = comp->last;
1101 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1102}
Daniel Veillard017b1082001-06-21 11:20:21 +00001103#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001104
1105/************************************************************************
1106 * *
1107 * Parser stacks related functions and macros *
1108 * *
1109 ************************************************************************/
1110
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001111/**
1112 * valuePop:
1113 * @ctxt: an XPath evaluation context
1114 *
1115 * Pops the top XPath object from the value stack
1116 *
1117 * Returns the XPath object just removed
1118 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001119extern xmlXPathObjectPtr
1120valuePop(xmlXPathParserContextPtr ctxt)
1121{
1122 xmlXPathObjectPtr ret;
1123
Daniel Veillarda82b1822004-11-08 16:24:57 +00001124 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
Daniel Veillard1c732d22002-11-30 11:22:59 +00001125 return (0);
1126 ctxt->valueNr--;
1127 if (ctxt->valueNr > 0)
1128 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1129 else
1130 ctxt->value = NULL;
1131 ret = ctxt->valueTab[ctxt->valueNr];
1132 ctxt->valueTab[ctxt->valueNr] = 0;
1133 return (ret);
1134}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001135/**
1136 * valuePush:
1137 * @ctxt: an XPath evaluation context
1138 * @value: the XPath object
1139 *
1140 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001141 *
1142 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001143 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001144extern int
1145valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1146{
Daniel Veillarda82b1822004-11-08 16:24:57 +00001147 if ((ctxt == NULL) || (value == NULL)) return(-1);
Daniel Veillard1c732d22002-11-30 11:22:59 +00001148 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001149 xmlXPathObjectPtr *tmp;
1150
1151 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1152 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001153 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001154 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001155 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1156 return (0);
1157 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001158 ctxt->valueMax *= 2;
1159 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001160 }
1161 ctxt->valueTab[ctxt->valueNr] = value;
1162 ctxt->value = value;
1163 return (ctxt->valueNr++);
1164}
Owen Taylor3473f882001-02-23 17:55:21 +00001165
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001166/**
1167 * xmlXPathPopBoolean:
1168 * @ctxt: an XPath parser context
1169 *
1170 * Pops a boolean from the stack, handling conversion if needed.
1171 * Check error with #xmlXPathCheckError.
1172 *
1173 * Returns the boolean
1174 */
1175int
1176xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1177 xmlXPathObjectPtr obj;
1178 int ret;
1179
1180 obj = valuePop(ctxt);
1181 if (obj == NULL) {
1182 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1183 return(0);
1184 }
William M. Brack08171912003-12-29 02:52:11 +00001185 if (obj->type != XPATH_BOOLEAN)
1186 ret = xmlXPathCastToBoolean(obj);
1187 else
1188 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001189 xmlXPathFreeObject(obj);
1190 return(ret);
1191}
1192
1193/**
1194 * xmlXPathPopNumber:
1195 * @ctxt: an XPath parser context
1196 *
1197 * Pops a number from the stack, handling conversion if needed.
1198 * Check error with #xmlXPathCheckError.
1199 *
1200 * Returns the number
1201 */
1202double
1203xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1204 xmlXPathObjectPtr obj;
1205 double ret;
1206
1207 obj = valuePop(ctxt);
1208 if (obj == NULL) {
1209 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1210 return(0);
1211 }
William M. Brack08171912003-12-29 02:52:11 +00001212 if (obj->type != XPATH_NUMBER)
1213 ret = xmlXPathCastToNumber(obj);
1214 else
1215 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001216 xmlXPathFreeObject(obj);
1217 return(ret);
1218}
1219
1220/**
1221 * xmlXPathPopString:
1222 * @ctxt: an XPath parser context
1223 *
1224 * Pops a string from the stack, handling conversion if needed.
1225 * Check error with #xmlXPathCheckError.
1226 *
1227 * Returns the string
1228 */
1229xmlChar *
1230xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1231 xmlXPathObjectPtr obj;
1232 xmlChar * ret;
1233
1234 obj = valuePop(ctxt);
1235 if (obj == NULL) {
1236 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1237 return(NULL);
1238 }
William M. Brack08171912003-12-29 02:52:11 +00001239 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001240 /* TODO: needs refactoring somewhere else */
1241 if (obj->stringval == ret)
1242 obj->stringval = NULL;
1243 xmlXPathFreeObject(obj);
1244 return(ret);
1245}
1246
1247/**
1248 * xmlXPathPopNodeSet:
1249 * @ctxt: an XPath parser context
1250 *
1251 * Pops a node-set from the stack, handling conversion if needed.
1252 * Check error with #xmlXPathCheckError.
1253 *
1254 * Returns the node-set
1255 */
1256xmlNodeSetPtr
1257xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1258 xmlXPathObjectPtr obj;
1259 xmlNodeSetPtr ret;
1260
Daniel Veillardf2a36f92004-11-08 17:55:01 +00001261 if (ctxt == NULL) return(NULL);
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001262 if (ctxt->value == NULL) {
1263 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1264 return(NULL);
1265 }
1266 if (!xmlXPathStackIsNodeSet(ctxt)) {
1267 xmlXPathSetTypeError(ctxt);
1268 return(NULL);
1269 }
1270 obj = valuePop(ctxt);
1271 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001272#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001273 /* to fix memory leak of not clearing obj->user */
1274 if (obj->boolval && obj->user != NULL)
1275 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001276#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001277 xmlXPathFreeNodeSetList(obj);
1278 return(ret);
1279}
1280
1281/**
1282 * xmlXPathPopExternal:
1283 * @ctxt: an XPath parser context
1284 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001285 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001286 * Check error with #xmlXPathCheckError.
1287 *
1288 * Returns the object
1289 */
1290void *
1291xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1292 xmlXPathObjectPtr obj;
1293 void * ret;
1294
Daniel Veillarda82b1822004-11-08 16:24:57 +00001295 if ((ctxt == NULL) || (ctxt->value == NULL)) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001296 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1297 return(NULL);
1298 }
1299 if (ctxt->value->type != XPATH_USERS) {
1300 xmlXPathSetTypeError(ctxt);
1301 return(NULL);
1302 }
1303 obj = valuePop(ctxt);
1304 ret = obj->user;
1305 xmlXPathFreeObject(obj);
1306 return(ret);
1307}
1308
Owen Taylor3473f882001-02-23 17:55:21 +00001309/*
1310 * Macros for accessing the content. Those should be used only by the parser,
1311 * and not exported.
1312 *
1313 * Dirty macros, i.e. one need to make assumption on the context to use them
1314 *
1315 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1316 * CUR returns the current xmlChar value, i.e. a 8 bit value
1317 * in ISO-Latin or UTF-8.
1318 * This should be used internally by the parser
1319 * only to compare to ASCII values otherwise it would break when
1320 * running with UTF-8 encoding.
1321 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1322 * to compare on ASCII based substring.
1323 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1324 * strings within the parser.
1325 * CURRENT Returns the current char value, with the full decoding of
1326 * UTF-8 if we are using this mode. It returns an int.
1327 * NEXT Skip to the next character, this does the proper decoding
1328 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1329 * It returns the pointer to the current xmlChar.
1330 */
1331
1332#define CUR (*ctxt->cur)
1333#define SKIP(val) ctxt->cur += (val)
1334#define NXT(val) ctxt->cur[(val)]
1335#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001336#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1337
1338#define COPY_BUF(l,b,i,v) \
1339 if (l == 1) b[i++] = (xmlChar) v; \
1340 else i += xmlCopyChar(l,&b[i],v)
1341
1342#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001343
1344#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001345 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001346
1347#define CURRENT (*ctxt->cur)
1348#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1349
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001350
1351#ifndef DBL_DIG
1352#define DBL_DIG 16
1353#endif
1354#ifndef DBL_EPSILON
1355#define DBL_EPSILON 1E-9
1356#endif
1357
1358#define UPPER_DOUBLE 1E9
1359#define LOWER_DOUBLE 1E-5
1360
1361#define INTEGER_DIGITS DBL_DIG
1362#define FRACTION_DIGITS (DBL_DIG + 1)
1363#define EXPONENT_DIGITS (3 + 2)
1364
1365/**
1366 * xmlXPathFormatNumber:
1367 * @number: number to format
1368 * @buffer: output buffer
1369 * @buffersize: size of output buffer
1370 *
1371 * Convert the number into a string representation.
1372 */
1373static void
1374xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1375{
Daniel Veillardcda96922001-08-21 10:56:31 +00001376 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001377 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001378 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001379 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001380 break;
1381 case -1:
1382 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001383 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001384 break;
1385 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001386 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001387 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001388 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001389 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001390 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001391 } else if (number == ((int) number)) {
1392 char work[30];
1393 char *ptr, *cur;
1394 int res, value = (int) number;
1395
1396 ptr = &buffer[0];
1397 if (value < 0) {
1398 *ptr++ = '-';
1399 value = -value;
1400 }
1401 if (value == 0) {
1402 *ptr++ = '0';
1403 } else {
1404 cur = &work[0];
1405 while (value != 0) {
1406 res = value % 10;
1407 value = value / 10;
1408 *cur++ = '0' + res;
1409 }
1410 cur--;
1411 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1412 *ptr++ = *cur--;
1413 }
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 }
4580 }
4581 }
4582 }
4583 }
4584
4585 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004586}
4587
4588
4589/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004590 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004591 * @arg1: first nodeset object argument
4592 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004593 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004594 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004595 * Implement the equal / not equal operation on XPath nodesets:
4596 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004597 * If both objects to be compared are node-sets, then the comparison
4598 * will be true if and only if there is a node in the first node-set and
4599 * a node in the second node-set such that the result of performing the
4600 * comparison on the string-values of the two nodes is true.
4601 *
4602 * (needless to say, this is a costly operation)
4603 *
4604 * Returns 0 or 1 depending on the results of the test.
4605 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004606static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004607xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004608 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004609 unsigned int *hashs1;
4610 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004611 xmlChar **values1;
4612 xmlChar **values2;
4613 int ret = 0;
4614 xmlNodeSetPtr ns1;
4615 xmlNodeSetPtr ns2;
4616
4617 if ((arg1 == NULL) ||
4618 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4619 return(0);
4620 if ((arg2 == NULL) ||
4621 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4622 return(0);
4623
4624 ns1 = arg1->nodesetval;
4625 ns2 = arg2->nodesetval;
4626
Daniel Veillard911f49a2001-04-07 15:39:35 +00004627 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004628 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004629 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004630 return(0);
4631
4632 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004633 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004634 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004635 if (neq == 0)
4636 for (i = 0;i < ns1->nodeNr;i++)
4637 for (j = 0;j < ns2->nodeNr;j++)
4638 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4639 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004640
4641 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004642 if (values1 == NULL) {
4643 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004644 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004645 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004646 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4647 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004648 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004649 xmlFree(values1);
4650 return(0);
4651 }
Owen Taylor3473f882001-02-23 17:55:21 +00004652 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4653 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4654 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004655 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004656 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004657 xmlFree(values1);
4658 return(0);
4659 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004660 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4661 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004662 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004663 xmlFree(hashs1);
4664 xmlFree(values1);
4665 xmlFree(values2);
4666 return(0);
4667 }
Owen Taylor3473f882001-02-23 17:55:21 +00004668 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4669 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004670 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004671 for (j = 0;j < ns2->nodeNr;j++) {
4672 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004673 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004674 if (hashs1[i] != hashs2[j]) {
4675 if (neq) {
4676 ret = 1;
4677 break;
4678 }
4679 }
4680 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004681 if (values1[i] == NULL)
4682 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4683 if (values2[j] == NULL)
4684 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004685 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004686 if (ret)
4687 break;
4688 }
Owen Taylor3473f882001-02-23 17:55:21 +00004689 }
4690 if (ret)
4691 break;
4692 }
4693 for (i = 0;i < ns1->nodeNr;i++)
4694 if (values1[i] != NULL)
4695 xmlFree(values1[i]);
4696 for (j = 0;j < ns2->nodeNr;j++)
4697 if (values2[j] != NULL)
4698 xmlFree(values2[j]);
4699 xmlFree(values1);
4700 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004701 xmlFree(hashs1);
4702 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004703 return(ret);
4704}
4705
William M. Brack0c022ad2002-07-12 00:56:01 +00004706static int
4707xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4708 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004709 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004710 /*
4711 *At this point we are assured neither arg1 nor arg2
4712 *is a nodeset, so we can just pick the appropriate routine.
4713 */
Owen Taylor3473f882001-02-23 17:55:21 +00004714 switch (arg1->type) {
4715 case XPATH_UNDEFINED:
4716#ifdef DEBUG_EXPR
4717 xmlGenericError(xmlGenericErrorContext,
4718 "Equal: undefined\n");
4719#endif
4720 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004721 case XPATH_BOOLEAN:
4722 switch (arg2->type) {
4723 case XPATH_UNDEFINED:
4724#ifdef DEBUG_EXPR
4725 xmlGenericError(xmlGenericErrorContext,
4726 "Equal: undefined\n");
4727#endif
4728 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004729 case XPATH_BOOLEAN:
4730#ifdef DEBUG_EXPR
4731 xmlGenericError(xmlGenericErrorContext,
4732 "Equal: %d boolean %d \n",
4733 arg1->boolval, arg2->boolval);
4734#endif
4735 ret = (arg1->boolval == arg2->boolval);
4736 break;
4737 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004738 ret = (arg1->boolval ==
4739 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004740 break;
4741 case XPATH_STRING:
4742 if ((arg2->stringval == NULL) ||
4743 (arg2->stringval[0] == 0)) ret = 0;
4744 else
4745 ret = 1;
4746 ret = (arg1->boolval == ret);
4747 break;
4748 case XPATH_USERS:
4749 case XPATH_POINT:
4750 case XPATH_RANGE:
4751 case XPATH_LOCATIONSET:
4752 TODO
4753 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004754 case XPATH_NODESET:
4755 case XPATH_XSLT_TREE:
4756 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004757 }
4758 break;
4759 case XPATH_NUMBER:
4760 switch (arg2->type) {
4761 case XPATH_UNDEFINED:
4762#ifdef DEBUG_EXPR
4763 xmlGenericError(xmlGenericErrorContext,
4764 "Equal: undefined\n");
4765#endif
4766 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004767 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004768 ret = (arg2->boolval==
4769 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004770 break;
4771 case XPATH_STRING:
4772 valuePush(ctxt, arg2);
4773 xmlXPathNumberFunction(ctxt, 1);
4774 arg2 = valuePop(ctxt);
4775 /* no break on purpose */
4776 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004777 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004778 if (xmlXPathIsNaN(arg1->floatval) ||
4779 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004780 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004781 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4782 if (xmlXPathIsInf(arg2->floatval) == 1)
4783 ret = 1;
4784 else
4785 ret = 0;
4786 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4787 if (xmlXPathIsInf(arg2->floatval) == -1)
4788 ret = 1;
4789 else
4790 ret = 0;
4791 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4792 if (xmlXPathIsInf(arg1->floatval) == 1)
4793 ret = 1;
4794 else
4795 ret = 0;
4796 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4797 if (xmlXPathIsInf(arg1->floatval) == -1)
4798 ret = 1;
4799 else
4800 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004801 } else {
4802 ret = (arg1->floatval == arg2->floatval);
4803 }
Owen Taylor3473f882001-02-23 17:55:21 +00004804 break;
4805 case XPATH_USERS:
4806 case XPATH_POINT:
4807 case XPATH_RANGE:
4808 case XPATH_LOCATIONSET:
4809 TODO
4810 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004811 case XPATH_NODESET:
4812 case XPATH_XSLT_TREE:
4813 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004814 }
4815 break;
4816 case XPATH_STRING:
4817 switch (arg2->type) {
4818 case XPATH_UNDEFINED:
4819#ifdef DEBUG_EXPR
4820 xmlGenericError(xmlGenericErrorContext,
4821 "Equal: undefined\n");
4822#endif
4823 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004824 case XPATH_BOOLEAN:
4825 if ((arg1->stringval == NULL) ||
4826 (arg1->stringval[0] == 0)) ret = 0;
4827 else
4828 ret = 1;
4829 ret = (arg2->boolval == ret);
4830 break;
4831 case XPATH_STRING:
4832 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4833 break;
4834 case XPATH_NUMBER:
4835 valuePush(ctxt, arg1);
4836 xmlXPathNumberFunction(ctxt, 1);
4837 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004838 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004839 if (xmlXPathIsNaN(arg1->floatval) ||
4840 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004841 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004842 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4843 if (xmlXPathIsInf(arg2->floatval) == 1)
4844 ret = 1;
4845 else
4846 ret = 0;
4847 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4848 if (xmlXPathIsInf(arg2->floatval) == -1)
4849 ret = 1;
4850 else
4851 ret = 0;
4852 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4853 if (xmlXPathIsInf(arg1->floatval) == 1)
4854 ret = 1;
4855 else
4856 ret = 0;
4857 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4858 if (xmlXPathIsInf(arg1->floatval) == -1)
4859 ret = 1;
4860 else
4861 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004862 } else {
4863 ret = (arg1->floatval == arg2->floatval);
4864 }
Owen Taylor3473f882001-02-23 17:55:21 +00004865 break;
4866 case XPATH_USERS:
4867 case XPATH_POINT:
4868 case XPATH_RANGE:
4869 case XPATH_LOCATIONSET:
4870 TODO
4871 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004872 case XPATH_NODESET:
4873 case XPATH_XSLT_TREE:
4874 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004875 }
4876 break;
4877 case XPATH_USERS:
4878 case XPATH_POINT:
4879 case XPATH_RANGE:
4880 case XPATH_LOCATIONSET:
4881 TODO
4882 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004883 case XPATH_NODESET:
4884 case XPATH_XSLT_TREE:
4885 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004886 }
4887 xmlXPathFreeObject(arg1);
4888 xmlXPathFreeObject(arg2);
4889 return(ret);
4890}
4891
William M. Brack0c022ad2002-07-12 00:56:01 +00004892/**
4893 * xmlXPathEqualValues:
4894 * @ctxt: the XPath Parser context
4895 *
4896 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4897 *
4898 * Returns 0 or 1 depending on the results of the test.
4899 */
4900int
4901xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4902 xmlXPathObjectPtr arg1, arg2, argtmp;
4903 int ret = 0;
4904
Daniel Veillard6128c012004-11-08 17:16:15 +00004905 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004906 arg2 = valuePop(ctxt);
4907 arg1 = valuePop(ctxt);
4908 if ((arg1 == NULL) || (arg2 == NULL)) {
4909 if (arg1 != NULL)
4910 xmlXPathFreeObject(arg1);
4911 else
4912 xmlXPathFreeObject(arg2);
4913 XP_ERROR0(XPATH_INVALID_OPERAND);
4914 }
4915
4916 if (arg1 == arg2) {
4917#ifdef DEBUG_EXPR
4918 xmlGenericError(xmlGenericErrorContext,
4919 "Equal: by pointer\n");
4920#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00004921 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004922 return(1);
4923 }
4924
4925 /*
4926 *If either argument is a nodeset, it's a 'special case'
4927 */
4928 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4929 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4930 /*
4931 *Hack it to assure arg1 is the nodeset
4932 */
4933 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4934 argtmp = arg2;
4935 arg2 = arg1;
4936 arg1 = argtmp;
4937 }
4938 switch (arg2->type) {
4939 case XPATH_UNDEFINED:
4940#ifdef DEBUG_EXPR
4941 xmlGenericError(xmlGenericErrorContext,
4942 "Equal: undefined\n");
4943#endif
4944 break;
4945 case XPATH_NODESET:
4946 case XPATH_XSLT_TREE:
4947 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4948 break;
4949 case XPATH_BOOLEAN:
4950 if ((arg1->nodesetval == NULL) ||
4951 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4952 else
4953 ret = 1;
4954 ret = (ret == arg2->boolval);
4955 break;
4956 case XPATH_NUMBER:
4957 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4958 break;
4959 case XPATH_STRING:
4960 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4961 break;
4962 case XPATH_USERS:
4963 case XPATH_POINT:
4964 case XPATH_RANGE:
4965 case XPATH_LOCATIONSET:
4966 TODO
4967 break;
4968 }
4969 xmlXPathFreeObject(arg1);
4970 xmlXPathFreeObject(arg2);
4971 return(ret);
4972 }
4973
4974 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4975}
4976
4977/**
4978 * xmlXPathNotEqualValues:
4979 * @ctxt: the XPath Parser context
4980 *
4981 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4982 *
4983 * Returns 0 or 1 depending on the results of the test.
4984 */
4985int
4986xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4987 xmlXPathObjectPtr arg1, arg2, argtmp;
4988 int ret = 0;
4989
Daniel Veillard6128c012004-11-08 17:16:15 +00004990 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00004991 arg2 = valuePop(ctxt);
4992 arg1 = valuePop(ctxt);
4993 if ((arg1 == NULL) || (arg2 == NULL)) {
4994 if (arg1 != NULL)
4995 xmlXPathFreeObject(arg1);
4996 else
4997 xmlXPathFreeObject(arg2);
4998 XP_ERROR0(XPATH_INVALID_OPERAND);
4999 }
5000
5001 if (arg1 == arg2) {
5002#ifdef DEBUG_EXPR
5003 xmlGenericError(xmlGenericErrorContext,
5004 "NotEqual: by pointer\n");
5005#endif
William M. Brack2c19a7b2005-04-10 01:03:23 +00005006 xmlXPathFreeObject(arg1);
William M. Brack0c022ad2002-07-12 00:56:01 +00005007 return(0);
5008 }
5009
5010 /*
5011 *If either argument is a nodeset, it's a 'special case'
5012 */
5013 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5014 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5015 /*
5016 *Hack it to assure arg1 is the nodeset
5017 */
5018 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5019 argtmp = arg2;
5020 arg2 = arg1;
5021 arg1 = argtmp;
5022 }
5023 switch (arg2->type) {
5024 case XPATH_UNDEFINED:
5025#ifdef DEBUG_EXPR
5026 xmlGenericError(xmlGenericErrorContext,
5027 "NotEqual: undefined\n");
5028#endif
5029 break;
5030 case XPATH_NODESET:
5031 case XPATH_XSLT_TREE:
5032 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
5033 break;
5034 case XPATH_BOOLEAN:
5035 if ((arg1->nodesetval == NULL) ||
5036 (arg1->nodesetval->nodeNr == 0)) ret = 0;
5037 else
5038 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005039 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005040 break;
5041 case XPATH_NUMBER:
5042 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5043 break;
5044 case XPATH_STRING:
5045 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5046 break;
5047 case XPATH_USERS:
5048 case XPATH_POINT:
5049 case XPATH_RANGE:
5050 case XPATH_LOCATIONSET:
5051 TODO
5052 break;
5053 }
5054 xmlXPathFreeObject(arg1);
5055 xmlXPathFreeObject(arg2);
5056 return(ret);
5057 }
5058
5059 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5060}
Owen Taylor3473f882001-02-23 17:55:21 +00005061
5062/**
5063 * xmlXPathCompareValues:
5064 * @ctxt: the XPath Parser context
5065 * @inf: less than (1) or greater than (0)
5066 * @strict: is the comparison strict
5067 *
5068 * Implement the compare operation on XPath objects:
5069 * @arg1 < @arg2 (1, 1, ...
5070 * @arg1 <= @arg2 (1, 0, ...
5071 * @arg1 > @arg2 (0, 1, ...
5072 * @arg1 >= @arg2 (0, 0, ...
5073 *
5074 * When neither object to be compared is a node-set and the operator is
5075 * <=, <, >=, >, then the objects are compared by converted both objects
5076 * to numbers and comparing the numbers according to IEEE 754. The <
5077 * comparison will be true if and only if the first number is less than the
5078 * second number. The <= comparison will be true if and only if the first
5079 * number is less than or equal to the second number. The > comparison
5080 * will be true if and only if the first number is greater than the second
5081 * number. The >= comparison will be true if and only if the first number
5082 * is greater than or equal to the second number.
5083 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005084 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005085 */
5086int
5087xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005088 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005089 xmlXPathObjectPtr arg1, arg2;
5090
Daniel Veillard6128c012004-11-08 17:16:15 +00005091 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
William M. Brack0c022ad2002-07-12 00:56:01 +00005092 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005093 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005094 if ((arg1 == NULL) || (arg2 == NULL)) {
5095 if (arg1 != NULL)
5096 xmlXPathFreeObject(arg1);
5097 else
5098 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005099 XP_ERROR0(XPATH_INVALID_OPERAND);
5100 }
5101
William M. Brack0c022ad2002-07-12 00:56:01 +00005102 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5103 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
William M. Brackd6e347e2005-04-15 01:34:41 +00005104 /*
5105 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5106 * are not freed from within this routine; they will be freed from the
5107 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5108 */
William M. Brack0c022ad2002-07-12 00:56:01 +00005109 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5110 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005111 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005112 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005113 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005114 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5115 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005116 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005117 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5118 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005119 }
5120 }
5121 return(ret);
5122 }
5123
5124 if (arg1->type != XPATH_NUMBER) {
5125 valuePush(ctxt, arg1);
5126 xmlXPathNumberFunction(ctxt, 1);
5127 arg1 = valuePop(ctxt);
5128 }
5129 if (arg1->type != XPATH_NUMBER) {
5130 xmlXPathFreeObject(arg1);
5131 xmlXPathFreeObject(arg2);
5132 XP_ERROR0(XPATH_INVALID_OPERAND);
5133 }
5134 if (arg2->type != XPATH_NUMBER) {
5135 valuePush(ctxt, arg2);
5136 xmlXPathNumberFunction(ctxt, 1);
5137 arg2 = valuePop(ctxt);
5138 }
5139 if (arg2->type != XPATH_NUMBER) {
5140 xmlXPathFreeObject(arg1);
5141 xmlXPathFreeObject(arg2);
5142 XP_ERROR0(XPATH_INVALID_OPERAND);
5143 }
5144 /*
5145 * Add tests for infinity and nan
5146 * => feedback on 3.4 for Inf and NaN
5147 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005148 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005149 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005150 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005151 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005152 arg1i=xmlXPathIsInf(arg1->floatval);
5153 arg2i=xmlXPathIsInf(arg2->floatval);
5154 if (inf && strict) {
5155 if ((arg1i == -1 && arg2i != -1) ||
5156 (arg2i == 1 && arg1i != 1)) {
5157 ret = 1;
5158 } else if (arg1i == 0 && arg2i == 0) {
5159 ret = (arg1->floatval < arg2->floatval);
5160 } else {
5161 ret = 0;
5162 }
5163 }
5164 else if (inf && !strict) {
5165 if (arg1i == -1 || arg2i == 1) {
5166 ret = 1;
5167 } else if (arg1i == 0 && arg2i == 0) {
5168 ret = (arg1->floatval <= arg2->floatval);
5169 } else {
5170 ret = 0;
5171 }
5172 }
5173 else if (!inf && strict) {
5174 if ((arg1i == 1 && arg2i != 1) ||
5175 (arg2i == -1 && arg1i != -1)) {
5176 ret = 1;
5177 } else if (arg1i == 0 && arg2i == 0) {
5178 ret = (arg1->floatval > arg2->floatval);
5179 } else {
5180 ret = 0;
5181 }
5182 }
5183 else if (!inf && !strict) {
5184 if (arg1i == 1 || arg2i == -1) {
5185 ret = 1;
5186 } else if (arg1i == 0 && arg2i == 0) {
5187 ret = (arg1->floatval >= arg2->floatval);
5188 } else {
5189 ret = 0;
5190 }
5191 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005192 }
Owen Taylor3473f882001-02-23 17:55:21 +00005193 xmlXPathFreeObject(arg1);
5194 xmlXPathFreeObject(arg2);
5195 return(ret);
5196}
5197
5198/**
5199 * xmlXPathValueFlipSign:
5200 * @ctxt: the XPath Parser context
5201 *
5202 * Implement the unary - operation on an XPath object
5203 * The numeric operators convert their operands to numbers as if
5204 * by calling the number function.
5205 */
5206void
5207xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005208 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005209 CAST_TO_NUMBER;
5210 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005211 if (xmlXPathIsNaN(ctxt->value->floatval))
5212 ctxt->value->floatval=xmlXPathNAN;
5213 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5214 ctxt->value->floatval=xmlXPathNINF;
5215 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5216 ctxt->value->floatval=xmlXPathPINF;
5217 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005218 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5219 ctxt->value->floatval = xmlXPathNZERO;
5220 else
5221 ctxt->value->floatval = 0;
5222 }
5223 else
5224 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005225}
5226
5227/**
5228 * xmlXPathAddValues:
5229 * @ctxt: the XPath Parser context
5230 *
5231 * Implement the add operation on XPath objects:
5232 * The numeric operators convert their operands to numbers as if
5233 * by calling the number function.
5234 */
5235void
5236xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5237 xmlXPathObjectPtr arg;
5238 double val;
5239
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005240 arg = valuePop(ctxt);
5241 if (arg == NULL)
5242 XP_ERROR(XPATH_INVALID_OPERAND);
5243 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005244 xmlXPathFreeObject(arg);
5245
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005246 CAST_TO_NUMBER;
5247 CHECK_TYPE(XPATH_NUMBER);
5248 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005249}
5250
5251/**
5252 * xmlXPathSubValues:
5253 * @ctxt: the XPath Parser context
5254 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005255 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005256 * The numeric operators convert their operands to numbers as if
5257 * by calling the number function.
5258 */
5259void
5260xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5261 xmlXPathObjectPtr arg;
5262 double val;
5263
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005264 arg = valuePop(ctxt);
5265 if (arg == NULL)
5266 XP_ERROR(XPATH_INVALID_OPERAND);
5267 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005268 xmlXPathFreeObject(arg);
5269
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005270 CAST_TO_NUMBER;
5271 CHECK_TYPE(XPATH_NUMBER);
5272 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005273}
5274
5275/**
5276 * xmlXPathMultValues:
5277 * @ctxt: the XPath Parser context
5278 *
5279 * Implement the multiply operation on XPath objects:
5280 * The numeric operators convert their operands to numbers as if
5281 * by calling the number function.
5282 */
5283void
5284xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5285 xmlXPathObjectPtr arg;
5286 double val;
5287
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005288 arg = valuePop(ctxt);
5289 if (arg == NULL)
5290 XP_ERROR(XPATH_INVALID_OPERAND);
5291 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005292 xmlXPathFreeObject(arg);
5293
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005294 CAST_TO_NUMBER;
5295 CHECK_TYPE(XPATH_NUMBER);
5296 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005297}
5298
5299/**
5300 * xmlXPathDivValues:
5301 * @ctxt: the XPath Parser context
5302 *
5303 * Implement the div operation on XPath objects @arg1 / @arg2:
5304 * The numeric operators convert their operands to numbers as if
5305 * by calling the number function.
5306 */
5307void
5308xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5309 xmlXPathObjectPtr arg;
5310 double val;
5311
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005312 arg = valuePop(ctxt);
5313 if (arg == NULL)
5314 XP_ERROR(XPATH_INVALID_OPERAND);
5315 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005316 xmlXPathFreeObject(arg);
5317
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005318 CAST_TO_NUMBER;
5319 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005320 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5321 ctxt->value->floatval = xmlXPathNAN;
5322 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005323 if (ctxt->value->floatval == 0)
5324 ctxt->value->floatval = xmlXPathNAN;
5325 else if (ctxt->value->floatval > 0)
5326 ctxt->value->floatval = xmlXPathNINF;
5327 else if (ctxt->value->floatval < 0)
5328 ctxt->value->floatval = xmlXPathPINF;
5329 }
5330 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005331 if (ctxt->value->floatval == 0)
5332 ctxt->value->floatval = xmlXPathNAN;
5333 else if (ctxt->value->floatval > 0)
5334 ctxt->value->floatval = xmlXPathPINF;
5335 else if (ctxt->value->floatval < 0)
5336 ctxt->value->floatval = xmlXPathNINF;
5337 } else
5338 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005339}
5340
5341/**
5342 * xmlXPathModValues:
5343 * @ctxt: the XPath Parser context
5344 *
5345 * Implement the mod operation on XPath objects: @arg1 / @arg2
5346 * The numeric operators convert their operands to numbers as if
5347 * by calling the number function.
5348 */
5349void
5350xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5351 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005352 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005353
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005354 arg = valuePop(ctxt);
5355 if (arg == NULL)
5356 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005357 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005358 xmlXPathFreeObject(arg);
5359
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005360 CAST_TO_NUMBER;
5361 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005362 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005363 if (arg2 == 0)
5364 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005365 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005366 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005367 }
Owen Taylor3473f882001-02-23 17:55:21 +00005368}
5369
5370/************************************************************************
5371 * *
5372 * The traversal functions *
5373 * *
5374 ************************************************************************/
5375
Owen Taylor3473f882001-02-23 17:55:21 +00005376/*
5377 * A traversal function enumerates nodes along an axis.
5378 * Initially it must be called with NULL, and it indicates
5379 * termination on the axis by returning NULL.
5380 */
5381typedef xmlNodePtr (*xmlXPathTraversalFunction)
5382 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5383
5384/**
5385 * xmlXPathNextSelf:
5386 * @ctxt: the XPath Parser context
5387 * @cur: the current node in the traversal
5388 *
5389 * Traversal function for the "self" direction
5390 * The self axis contains just the context node itself
5391 *
5392 * Returns the next element following that axis
5393 */
5394xmlNodePtr
5395xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005396 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005397 if (cur == NULL)
5398 return(ctxt->context->node);
5399 return(NULL);
5400}
5401
5402/**
5403 * xmlXPathNextChild:
5404 * @ctxt: the XPath Parser context
5405 * @cur: the current node in the traversal
5406 *
5407 * Traversal function for the "child" direction
5408 * The child axis contains the children of the context node in document order.
5409 *
5410 * Returns the next element following that axis
5411 */
5412xmlNodePtr
5413xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005414 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005415 if (cur == NULL) {
5416 if (ctxt->context->node == NULL) return(NULL);
5417 switch (ctxt->context->node->type) {
5418 case XML_ELEMENT_NODE:
5419 case XML_TEXT_NODE:
5420 case XML_CDATA_SECTION_NODE:
5421 case XML_ENTITY_REF_NODE:
5422 case XML_ENTITY_NODE:
5423 case XML_PI_NODE:
5424 case XML_COMMENT_NODE:
5425 case XML_NOTATION_NODE:
5426 case XML_DTD_NODE:
5427 return(ctxt->context->node->children);
5428 case XML_DOCUMENT_NODE:
5429 case XML_DOCUMENT_TYPE_NODE:
5430 case XML_DOCUMENT_FRAG_NODE:
5431 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005432#ifdef LIBXML_DOCB_ENABLED
5433 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005434#endif
5435 return(((xmlDocPtr) ctxt->context->node)->children);
5436 case XML_ELEMENT_DECL:
5437 case XML_ATTRIBUTE_DECL:
5438 case XML_ENTITY_DECL:
5439 case XML_ATTRIBUTE_NODE:
5440 case XML_NAMESPACE_DECL:
5441 case XML_XINCLUDE_START:
5442 case XML_XINCLUDE_END:
5443 return(NULL);
5444 }
5445 return(NULL);
5446 }
5447 if ((cur->type == XML_DOCUMENT_NODE) ||
5448 (cur->type == XML_HTML_DOCUMENT_NODE))
5449 return(NULL);
5450 return(cur->next);
5451}
5452
5453/**
5454 * xmlXPathNextDescendant:
5455 * @ctxt: the XPath Parser context
5456 * @cur: the current node in the traversal
5457 *
5458 * Traversal function for the "descendant" direction
5459 * the descendant axis contains the descendants of the context node in document
5460 * order; a descendant is a child or a child of a child and so on.
5461 *
5462 * Returns the next element following that axis
5463 */
5464xmlNodePtr
5465xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005466 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005467 if (cur == NULL) {
5468 if (ctxt->context->node == NULL)
5469 return(NULL);
5470 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5471 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5472 return(NULL);
5473
5474 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5475 return(ctxt->context->doc->children);
5476 return(ctxt->context->node->children);
5477 }
5478
Daniel Veillard567e1b42001-08-01 15:53:47 +00005479 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005480 /*
5481 * Do not descend on entities declarations
5482 */
5483 if (cur->children->type != XML_ENTITY_DECL) {
5484 cur = cur->children;
5485 /*
5486 * Skip DTDs
5487 */
5488 if (cur->type != XML_DTD_NODE)
5489 return(cur);
5490 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005491 }
5492
5493 if (cur == ctxt->context->node) return(NULL);
5494
Daniel Veillard68e9e742002-11-16 15:35:11 +00005495 while (cur->next != NULL) {
5496 cur = cur->next;
5497 if ((cur->type != XML_ENTITY_DECL) &&
5498 (cur->type != XML_DTD_NODE))
5499 return(cur);
5500 }
Owen Taylor3473f882001-02-23 17:55:21 +00005501
5502 do {
5503 cur = cur->parent;
5504 if (cur == NULL) return(NULL);
5505 if (cur == ctxt->context->node) return(NULL);
5506 if (cur->next != NULL) {
5507 cur = cur->next;
5508 return(cur);
5509 }
5510 } while (cur != NULL);
5511 return(cur);
5512}
5513
5514/**
5515 * xmlXPathNextDescendantOrSelf:
5516 * @ctxt: the XPath Parser context
5517 * @cur: the current node in the traversal
5518 *
5519 * Traversal function for the "descendant-or-self" direction
5520 * the descendant-or-self axis contains the context node and the descendants
5521 * of the context node in document order; thus the context node is the first
5522 * node on the axis, and the first child of the context node is the second node
5523 * on the axis
5524 *
5525 * Returns the next element following that axis
5526 */
5527xmlNodePtr
5528xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005529 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005530 if (cur == NULL) {
5531 if (ctxt->context->node == NULL)
5532 return(NULL);
5533 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5534 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5535 return(NULL);
5536 return(ctxt->context->node);
5537 }
5538
5539 return(xmlXPathNextDescendant(ctxt, cur));
5540}
5541
5542/**
5543 * xmlXPathNextParent:
5544 * @ctxt: the XPath Parser context
5545 * @cur: the current node in the traversal
5546 *
5547 * Traversal function for the "parent" direction
5548 * The parent axis contains the parent of the context node, if there is one.
5549 *
5550 * Returns the next element following that axis
5551 */
5552xmlNodePtr
5553xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005554 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005555 /*
5556 * the parent of an attribute or namespace node is the element
5557 * to which the attribute or namespace node is attached
5558 * Namespace handling !!!
5559 */
5560 if (cur == NULL) {
5561 if (ctxt->context->node == NULL) return(NULL);
5562 switch (ctxt->context->node->type) {
5563 case XML_ELEMENT_NODE:
5564 case XML_TEXT_NODE:
5565 case XML_CDATA_SECTION_NODE:
5566 case XML_ENTITY_REF_NODE:
5567 case XML_ENTITY_NODE:
5568 case XML_PI_NODE:
5569 case XML_COMMENT_NODE:
5570 case XML_NOTATION_NODE:
5571 case XML_DTD_NODE:
5572 case XML_ELEMENT_DECL:
5573 case XML_ATTRIBUTE_DECL:
5574 case XML_XINCLUDE_START:
5575 case XML_XINCLUDE_END:
5576 case XML_ENTITY_DECL:
5577 if (ctxt->context->node->parent == NULL)
5578 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005579 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005580 ((ctxt->context->node->parent->name[0] == ' ') ||
5581 (xmlStrEqual(ctxt->context->node->parent->name,
5582 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005583 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005584 return(ctxt->context->node->parent);
5585 case XML_ATTRIBUTE_NODE: {
5586 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5587
5588 return(att->parent);
5589 }
5590 case XML_DOCUMENT_NODE:
5591 case XML_DOCUMENT_TYPE_NODE:
5592 case XML_DOCUMENT_FRAG_NODE:
5593 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005594#ifdef LIBXML_DOCB_ENABLED
5595 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005596#endif
5597 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005598 case XML_NAMESPACE_DECL: {
5599 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5600
5601 if ((ns->next != NULL) &&
5602 (ns->next->type != XML_NAMESPACE_DECL))
5603 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005604 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005605 }
Owen Taylor3473f882001-02-23 17:55:21 +00005606 }
5607 }
5608 return(NULL);
5609}
5610
5611/**
5612 * xmlXPathNextAncestor:
5613 * @ctxt: the XPath Parser context
5614 * @cur: the current node in the traversal
5615 *
5616 * Traversal function for the "ancestor" direction
5617 * the ancestor axis contains the ancestors of the context node; the ancestors
5618 * of the context node consist of the parent of context node and the parent's
5619 * parent and so on; the nodes are ordered in reverse document order; thus the
5620 * parent is the first node on the axis, and the parent's parent is the second
5621 * node on the axis
5622 *
5623 * Returns the next element following that axis
5624 */
5625xmlNodePtr
5626xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005627 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005628 /*
5629 * the parent of an attribute or namespace node is the element
5630 * to which the attribute or namespace node is attached
5631 * !!!!!!!!!!!!!
5632 */
5633 if (cur == NULL) {
5634 if (ctxt->context->node == NULL) return(NULL);
5635 switch (ctxt->context->node->type) {
5636 case XML_ELEMENT_NODE:
5637 case XML_TEXT_NODE:
5638 case XML_CDATA_SECTION_NODE:
5639 case XML_ENTITY_REF_NODE:
5640 case XML_ENTITY_NODE:
5641 case XML_PI_NODE:
5642 case XML_COMMENT_NODE:
5643 case XML_DTD_NODE:
5644 case XML_ELEMENT_DECL:
5645 case XML_ATTRIBUTE_DECL:
5646 case XML_ENTITY_DECL:
5647 case XML_NOTATION_NODE:
5648 case XML_XINCLUDE_START:
5649 case XML_XINCLUDE_END:
5650 if (ctxt->context->node->parent == NULL)
5651 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005652 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005653 ((ctxt->context->node->parent->name[0] == ' ') ||
5654 (xmlStrEqual(ctxt->context->node->parent->name,
5655 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005656 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005657 return(ctxt->context->node->parent);
5658 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005659 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005660
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005661 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005662 }
5663 case XML_DOCUMENT_NODE:
5664 case XML_DOCUMENT_TYPE_NODE:
5665 case XML_DOCUMENT_FRAG_NODE:
5666 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005667#ifdef LIBXML_DOCB_ENABLED
5668 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005669#endif
5670 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005671 case XML_NAMESPACE_DECL: {
5672 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5673
5674 if ((ns->next != NULL) &&
5675 (ns->next->type != XML_NAMESPACE_DECL))
5676 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005677 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005678 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005679 }
Owen Taylor3473f882001-02-23 17:55:21 +00005680 }
5681 return(NULL);
5682 }
5683 if (cur == ctxt->context->doc->children)
5684 return((xmlNodePtr) ctxt->context->doc);
5685 if (cur == (xmlNodePtr) ctxt->context->doc)
5686 return(NULL);
5687 switch (cur->type) {
5688 case XML_ELEMENT_NODE:
5689 case XML_TEXT_NODE:
5690 case XML_CDATA_SECTION_NODE:
5691 case XML_ENTITY_REF_NODE:
5692 case XML_ENTITY_NODE:
5693 case XML_PI_NODE:
5694 case XML_COMMENT_NODE:
5695 case XML_NOTATION_NODE:
5696 case XML_DTD_NODE:
5697 case XML_ELEMENT_DECL:
5698 case XML_ATTRIBUTE_DECL:
5699 case XML_ENTITY_DECL:
5700 case XML_XINCLUDE_START:
5701 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005702 if (cur->parent == NULL)
5703 return(NULL);
5704 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005705 ((cur->parent->name[0] == ' ') ||
5706 (xmlStrEqual(cur->parent->name,
5707 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005708 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005709 return(cur->parent);
5710 case XML_ATTRIBUTE_NODE: {
5711 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5712
5713 return(att->parent);
5714 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005715 case XML_NAMESPACE_DECL: {
5716 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5717
5718 if ((ns->next != NULL) &&
5719 (ns->next->type != XML_NAMESPACE_DECL))
5720 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005721 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005722 return(NULL);
5723 }
Owen Taylor3473f882001-02-23 17:55:21 +00005724 case XML_DOCUMENT_NODE:
5725 case XML_DOCUMENT_TYPE_NODE:
5726 case XML_DOCUMENT_FRAG_NODE:
5727 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005728#ifdef LIBXML_DOCB_ENABLED
5729 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005730#endif
5731 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005732 }
5733 return(NULL);
5734}
5735
5736/**
5737 * xmlXPathNextAncestorOrSelf:
5738 * @ctxt: the XPath Parser context
5739 * @cur: the current node in the traversal
5740 *
5741 * Traversal function for the "ancestor-or-self" direction
5742 * he ancestor-or-self axis contains the context node and ancestors of
5743 * the context node in reverse document order; thus the context node is
5744 * the first node on the axis, and the context node's parent the second;
5745 * parent here is defined the same as with the parent axis.
5746 *
5747 * Returns the next element following that axis
5748 */
5749xmlNodePtr
5750xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005751 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005752 if (cur == NULL)
5753 return(ctxt->context->node);
5754 return(xmlXPathNextAncestor(ctxt, cur));
5755}
5756
5757/**
5758 * xmlXPathNextFollowingSibling:
5759 * @ctxt: the XPath Parser context
5760 * @cur: the current node in the traversal
5761 *
5762 * Traversal function for the "following-sibling" direction
5763 * The following-sibling axis contains the following siblings of the context
5764 * node in document order.
5765 *
5766 * Returns the next element following that axis
5767 */
5768xmlNodePtr
5769xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005770 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005771 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5772 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5773 return(NULL);
5774 if (cur == (xmlNodePtr) ctxt->context->doc)
5775 return(NULL);
5776 if (cur == NULL)
5777 return(ctxt->context->node->next);
5778 return(cur->next);
5779}
5780
5781/**
5782 * xmlXPathNextPrecedingSibling:
5783 * @ctxt: the XPath Parser context
5784 * @cur: the current node in the traversal
5785 *
5786 * Traversal function for the "preceding-sibling" direction
5787 * The preceding-sibling axis contains the preceding siblings of the context
5788 * node in reverse document order; the first preceding sibling is first on the
5789 * axis; the sibling preceding that node is the second on the axis and so on.
5790 *
5791 * Returns the next element following that axis
5792 */
5793xmlNodePtr
5794xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005795 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005796 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5797 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5798 return(NULL);
5799 if (cur == (xmlNodePtr) ctxt->context->doc)
5800 return(NULL);
5801 if (cur == NULL)
5802 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005803 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5804 cur = cur->prev;
5805 if (cur == NULL)
5806 return(ctxt->context->node->prev);
5807 }
Owen Taylor3473f882001-02-23 17:55:21 +00005808 return(cur->prev);
5809}
5810
5811/**
5812 * xmlXPathNextFollowing:
5813 * @ctxt: the XPath Parser context
5814 * @cur: the current node in the traversal
5815 *
5816 * Traversal function for the "following" direction
5817 * The following axis contains all nodes in the same document as the context
5818 * node that are after the context node in document order, excluding any
5819 * descendants and excluding attribute nodes and namespace nodes; the nodes
5820 * are ordered in document order
5821 *
5822 * Returns the next element following that axis
5823 */
5824xmlNodePtr
5825xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005826 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005827 if (cur != NULL && cur->children != NULL)
5828 return cur->children ;
5829 if (cur == NULL) cur = ctxt->context->node;
5830 if (cur == NULL) return(NULL) ; /* ERROR */
5831 if (cur->next != NULL) return(cur->next) ;
5832 do {
5833 cur = cur->parent;
5834 if (cur == NULL) return(NULL);
5835 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5836 if (cur->next != NULL) return(cur->next);
5837 } while (cur != NULL);
5838 return(cur);
5839}
5840
5841/*
5842 * xmlXPathIsAncestor:
5843 * @ancestor: the ancestor node
5844 * @node: the current node
5845 *
5846 * Check that @ancestor is a @node's ancestor
5847 *
5848 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5849 */
5850static int
5851xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5852 if ((ancestor == NULL) || (node == NULL)) return(0);
5853 /* nodes need to be in the same document */
5854 if (ancestor->doc != node->doc) return(0);
5855 /* avoid searching if ancestor or node is the root node */
5856 if (ancestor == (xmlNodePtr) node->doc) return(1);
5857 if (node == (xmlNodePtr) ancestor->doc) return(0);
5858 while (node->parent != NULL) {
5859 if (node->parent == ancestor)
5860 return(1);
5861 node = node->parent;
5862 }
5863 return(0);
5864}
5865
5866/**
5867 * xmlXPathNextPreceding:
5868 * @ctxt: the XPath Parser context
5869 * @cur: the current node in the traversal
5870 *
5871 * Traversal function for the "preceding" direction
5872 * the preceding axis contains all nodes in the same document as the context
5873 * node that are before the context node in document order, excluding any
5874 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5875 * ordered in reverse document order
5876 *
5877 * Returns the next element following that axis
5878 */
5879xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005880xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5881{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005882 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005883 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005884 cur = ctxt->context->node;
5885 if (cur == NULL)
5886 return (NULL);
5887 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5888 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005889 do {
5890 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005891 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5892 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005893 }
5894
5895 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005896 if (cur == NULL)
5897 return (NULL);
5898 if (cur == ctxt->context->doc->children)
5899 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005900 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005901 return (cur);
5902}
5903
5904/**
5905 * xmlXPathNextPrecedingInternal:
5906 * @ctxt: the XPath Parser context
5907 * @cur: the current node in the traversal
5908 *
5909 * Traversal function for the "preceding" direction
5910 * the preceding axis contains all nodes in the same document as the context
5911 * node that are before the context node in document order, excluding any
5912 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5913 * ordered in reverse document order
5914 * This is a faster implementation but internal only since it requires a
5915 * state kept in the parser context: ctxt->ancestor.
5916 *
5917 * Returns the next element following that axis
5918 */
5919static xmlNodePtr
5920xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5921 xmlNodePtr cur)
5922{
Daniel Veillarda82b1822004-11-08 16:24:57 +00005923 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005924 if (cur == NULL) {
5925 cur = ctxt->context->node;
5926 if (cur == NULL)
5927 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005928 if (cur->type == XML_NAMESPACE_DECL)
5929 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005930 ctxt->ancestor = cur->parent;
5931 }
5932 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5933 cur = cur->prev;
5934 while (cur->prev == NULL) {
5935 cur = cur->parent;
5936 if (cur == NULL)
5937 return (NULL);
5938 if (cur == ctxt->context->doc->children)
5939 return (NULL);
5940 if (cur != ctxt->ancestor)
5941 return (cur);
5942 ctxt->ancestor = cur->parent;
5943 }
5944 cur = cur->prev;
5945 while (cur->last != NULL)
5946 cur = cur->last;
5947 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005948}
5949
5950/**
5951 * xmlXPathNextNamespace:
5952 * @ctxt: the XPath Parser context
5953 * @cur: the current attribute in the traversal
5954 *
5955 * Traversal function for the "namespace" direction
5956 * the namespace axis contains the namespace nodes of the context node;
5957 * the order of nodes on this axis is implementation-defined; the axis will
5958 * be empty unless the context node is an element
5959 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005960 * We keep the XML namespace node at the end of the list.
5961 *
Owen Taylor3473f882001-02-23 17:55:21 +00005962 * Returns the next element following that axis
5963 */
5964xmlNodePtr
5965xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00005966 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005967 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005968 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005969 if (ctxt->context->tmpNsList != NULL)
5970 xmlFree(ctxt->context->tmpNsList);
5971 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005972 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005973 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005974 if (ctxt->context->tmpNsList != NULL) {
5975 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5976 ctxt->context->tmpNsNr++;
5977 }
5978 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005979 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005980 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005981 if (ctxt->context->tmpNsNr > 0) {
5982 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5983 } else {
5984 if (ctxt->context->tmpNsList != NULL)
5985 xmlFree(ctxt->context->tmpNsList);
5986 ctxt->context->tmpNsList = NULL;
5987 return(NULL);
5988 }
Owen Taylor3473f882001-02-23 17:55:21 +00005989}
5990
5991/**
5992 * xmlXPathNextAttribute:
5993 * @ctxt: the XPath Parser context
5994 * @cur: the current attribute in the traversal
5995 *
5996 * Traversal function for the "attribute" direction
5997 * TODO: support DTD inherited default attributes
5998 *
5999 * Returns the next element following that axis
6000 */
6001xmlNodePtr
6002xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006003 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
Daniel Veillarde470df72001-04-18 21:41:07 +00006004 if (ctxt->context->node == NULL)
6005 return(NULL);
6006 if (ctxt->context->node->type != XML_ELEMENT_NODE)
6007 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006008 if (cur == NULL) {
6009 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6010 return(NULL);
6011 return((xmlNodePtr)ctxt->context->node->properties);
6012 }
6013 return((xmlNodePtr)cur->next);
6014}
6015
6016/************************************************************************
6017 * *
6018 * NodeTest Functions *
6019 * *
6020 ************************************************************************/
6021
Owen Taylor3473f882001-02-23 17:55:21 +00006022#define IS_FUNCTION 200
6023
Owen Taylor3473f882001-02-23 17:55:21 +00006024
6025/************************************************************************
6026 * *
6027 * Implicit tree core function library *
6028 * *
6029 ************************************************************************/
6030
6031/**
6032 * xmlXPathRoot:
6033 * @ctxt: the XPath Parser context
6034 *
6035 * Initialize the context to the root of the document
6036 */
6037void
6038xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006039 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006040 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
6041 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6042}
6043
6044/************************************************************************
6045 * *
6046 * The explicit core function library *
6047 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6048 * *
6049 ************************************************************************/
6050
6051
6052/**
6053 * xmlXPathLastFunction:
6054 * @ctxt: the XPath Parser context
6055 * @nargs: the number of arguments
6056 *
6057 * Implement the last() XPath function
6058 * number last()
6059 * The last function returns the number of nodes in the context node list.
6060 */
6061void
6062xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6063 CHECK_ARITY(0);
6064 if (ctxt->context->contextSize >= 0) {
6065 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6066#ifdef DEBUG_EXPR
6067 xmlGenericError(xmlGenericErrorContext,
6068 "last() : %d\n", ctxt->context->contextSize);
6069#endif
6070 } else {
6071 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6072 }
6073}
6074
6075/**
6076 * xmlXPathPositionFunction:
6077 * @ctxt: the XPath Parser context
6078 * @nargs: the number of arguments
6079 *
6080 * Implement the position() XPath function
6081 * number position()
6082 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006083 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006084 * will be equal to last().
6085 */
6086void
6087xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6088 CHECK_ARITY(0);
6089 if (ctxt->context->proximityPosition >= 0) {
6090 valuePush(ctxt,
6091 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6092#ifdef DEBUG_EXPR
6093 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6094 ctxt->context->proximityPosition);
6095#endif
6096 } else {
6097 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6098 }
6099}
6100
6101/**
6102 * xmlXPathCountFunction:
6103 * @ctxt: the XPath Parser context
6104 * @nargs: the number of arguments
6105 *
6106 * Implement the count() XPath function
6107 * number count(node-set)
6108 */
6109void
6110xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6111 xmlXPathObjectPtr cur;
6112
6113 CHECK_ARITY(1);
6114 if ((ctxt->value == NULL) ||
6115 ((ctxt->value->type != XPATH_NODESET) &&
6116 (ctxt->value->type != XPATH_XSLT_TREE)))
6117 XP_ERROR(XPATH_INVALID_TYPE);
6118 cur = valuePop(ctxt);
6119
Daniel Veillard911f49a2001-04-07 15:39:35 +00006120 if ((cur == NULL) || (cur->nodesetval == NULL))
6121 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006122 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006123 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006124 } else {
6125 if ((cur->nodesetval->nodeNr != 1) ||
6126 (cur->nodesetval->nodeTab == NULL)) {
6127 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6128 } else {
6129 xmlNodePtr tmp;
6130 int i = 0;
6131
6132 tmp = cur->nodesetval->nodeTab[0];
6133 if (tmp != NULL) {
6134 tmp = tmp->children;
6135 while (tmp != NULL) {
6136 tmp = tmp->next;
6137 i++;
6138 }
6139 }
6140 valuePush(ctxt, xmlXPathNewFloat((double) i));
6141 }
6142 }
Owen Taylor3473f882001-02-23 17:55:21 +00006143 xmlXPathFreeObject(cur);
6144}
6145
6146/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006147 * xmlXPathGetElementsByIds:
6148 * @doc: the document
6149 * @ids: a whitespace separated list of IDs
6150 *
6151 * Selects elements by their unique ID.
6152 *
6153 * Returns a node-set of selected elements.
6154 */
6155static xmlNodeSetPtr
6156xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6157 xmlNodeSetPtr ret;
6158 const xmlChar *cur = ids;
6159 xmlChar *ID;
6160 xmlAttrPtr attr;
6161 xmlNodePtr elem = NULL;
6162
Daniel Veillard7a985a12003-07-06 17:57:42 +00006163 if (ids == NULL) return(NULL);
6164
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006165 ret = xmlXPathNodeSetCreate(NULL);
6166
William M. Brack76e95df2003-10-18 16:20:14 +00006167 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006168 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006169 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006170 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006171
6172 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006173 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006174 /*
6175 * We used to check the fact that the value passed
6176 * was an NCName, but this generated much troubles for
6177 * me and Aleksey Sanin, people blatantly violated that
6178 * constaint, like Visa3D spec.
6179 * if (xmlValidateNCName(ID, 1) == 0)
6180 */
6181 attr = xmlGetID(doc, ID);
6182 if (attr != NULL) {
6183 if (attr->type == XML_ATTRIBUTE_NODE)
6184 elem = attr->parent;
6185 else if (attr->type == XML_ELEMENT_NODE)
6186 elem = (xmlNodePtr) attr;
6187 else
6188 elem = NULL;
6189 if (elem != NULL)
6190 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006191 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006192 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006193 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006194
William M. Brack76e95df2003-10-18 16:20:14 +00006195 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006196 ids = cur;
6197 }
6198 return(ret);
6199}
6200
6201/**
Owen Taylor3473f882001-02-23 17:55:21 +00006202 * xmlXPathIdFunction:
6203 * @ctxt: the XPath Parser context
6204 * @nargs: the number of arguments
6205 *
6206 * Implement the id() XPath function
6207 * node-set id(object)
6208 * The id function selects elements by their unique ID
6209 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6210 * then the result is the union of the result of applying id to the
6211 * string value of each of the nodes in the argument node-set. When the
6212 * argument to id is of any other type, the argument is converted to a
6213 * string as if by a call to the string function; the string is split
6214 * into a whitespace-separated list of tokens (whitespace is any sequence
6215 * of characters matching the production S); the result is a node-set
6216 * containing the elements in the same document as the context node that
6217 * have a unique ID equal to any of the tokens in the list.
6218 */
6219void
6220xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006221 xmlChar *tokens;
6222 xmlNodeSetPtr ret;
6223 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006224
6225 CHECK_ARITY(1);
6226 obj = valuePop(ctxt);
6227 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006228 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006229 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006230 int i;
6231
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006232 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006233
Daniel Veillard911f49a2001-04-07 15:39:35 +00006234 if (obj->nodesetval != NULL) {
6235 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006236 tokens =
6237 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6238 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6239 ret = xmlXPathNodeSetMerge(ret, ns);
6240 xmlXPathFreeNodeSet(ns);
6241 if (tokens != NULL)
6242 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006243 }
Owen Taylor3473f882001-02-23 17:55:21 +00006244 }
6245
6246 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006247 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006248 return;
6249 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006250 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006251
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006252 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6253 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006254
Owen Taylor3473f882001-02-23 17:55:21 +00006255 xmlXPathFreeObject(obj);
6256 return;
6257}
6258
6259/**
6260 * xmlXPathLocalNameFunction:
6261 * @ctxt: the XPath Parser context
6262 * @nargs: the number of arguments
6263 *
6264 * Implement the local-name() XPath function
6265 * string local-name(node-set?)
6266 * The local-name function returns a string containing the local part
6267 * of the name of the node in the argument node-set that is first in
6268 * document order. If the node-set is empty or the first node has no
6269 * name, an empty string is returned. If the argument is omitted it
6270 * defaults to the context node.
6271 */
6272void
6273xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6274 xmlXPathObjectPtr cur;
6275
Daniel Veillarda82b1822004-11-08 16:24:57 +00006276 if (ctxt == NULL) return;
6277
Owen Taylor3473f882001-02-23 17:55:21 +00006278 if (nargs == 0) {
6279 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6280 nargs = 1;
6281 }
6282
6283 CHECK_ARITY(1);
6284 if ((ctxt->value == NULL) ||
6285 ((ctxt->value->type != XPATH_NODESET) &&
6286 (ctxt->value->type != XPATH_XSLT_TREE)))
6287 XP_ERROR(XPATH_INVALID_TYPE);
6288 cur = valuePop(ctxt);
6289
Daniel Veillard911f49a2001-04-07 15:39:35 +00006290 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006291 valuePush(ctxt, xmlXPathNewCString(""));
6292 } else {
6293 int i = 0; /* Should be first in document order !!!!! */
6294 switch (cur->nodesetval->nodeTab[i]->type) {
6295 case XML_ELEMENT_NODE:
6296 case XML_ATTRIBUTE_NODE:
6297 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006298 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6299 valuePush(ctxt, xmlXPathNewCString(""));
6300 else
6301 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006302 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6303 break;
6304 case XML_NAMESPACE_DECL:
6305 valuePush(ctxt, xmlXPathNewString(
6306 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6307 break;
6308 default:
6309 valuePush(ctxt, xmlXPathNewCString(""));
6310 }
6311 }
6312 xmlXPathFreeObject(cur);
6313}
6314
6315/**
6316 * xmlXPathNamespaceURIFunction:
6317 * @ctxt: the XPath Parser context
6318 * @nargs: the number of arguments
6319 *
6320 * Implement the namespace-uri() XPath function
6321 * string namespace-uri(node-set?)
6322 * The namespace-uri function returns a string containing the
6323 * namespace URI of the expanded name of the node in the argument
6324 * node-set that is first in document order. If the node-set is empty,
6325 * the first node has no name, or the expanded name has no namespace
6326 * URI, an empty string is returned. If the argument is omitted it
6327 * defaults to the context node.
6328 */
6329void
6330xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6331 xmlXPathObjectPtr cur;
6332
Daniel Veillarda82b1822004-11-08 16:24:57 +00006333 if (ctxt == NULL) return;
6334
Owen Taylor3473f882001-02-23 17:55:21 +00006335 if (nargs == 0) {
6336 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6337 nargs = 1;
6338 }
6339 CHECK_ARITY(1);
6340 if ((ctxt->value == NULL) ||
6341 ((ctxt->value->type != XPATH_NODESET) &&
6342 (ctxt->value->type != XPATH_XSLT_TREE)))
6343 XP_ERROR(XPATH_INVALID_TYPE);
6344 cur = valuePop(ctxt);
6345
Daniel Veillard911f49a2001-04-07 15:39:35 +00006346 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006347 valuePush(ctxt, xmlXPathNewCString(""));
6348 } else {
6349 int i = 0; /* Should be first in document order !!!!! */
6350 switch (cur->nodesetval->nodeTab[i]->type) {
6351 case XML_ELEMENT_NODE:
6352 case XML_ATTRIBUTE_NODE:
6353 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6354 valuePush(ctxt, xmlXPathNewCString(""));
6355 else
6356 valuePush(ctxt, xmlXPathNewString(
6357 cur->nodesetval->nodeTab[i]->ns->href));
6358 break;
6359 default:
6360 valuePush(ctxt, xmlXPathNewCString(""));
6361 }
6362 }
6363 xmlXPathFreeObject(cur);
6364}
6365
6366/**
6367 * xmlXPathNameFunction:
6368 * @ctxt: the XPath Parser context
6369 * @nargs: the number of arguments
6370 *
6371 * Implement the name() XPath function
6372 * string name(node-set?)
6373 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006374 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006375 * order. The QName must represent the name with respect to the namespace
6376 * declarations in effect on the node whose name is being represented.
6377 * Typically, this will be the form in which the name occurred in the XML
6378 * source. This need not be the case if there are namespace declarations
6379 * in effect on the node that associate multiple prefixes with the same
6380 * namespace. However, an implementation may include information about
6381 * the original prefix in its representation of nodes; in this case, an
6382 * implementation can ensure that the returned string is always the same
6383 * as the QName used in the XML source. If the argument it omitted it
6384 * defaults to the context node.
6385 * Libxml keep the original prefix so the "real qualified name" used is
6386 * returned.
6387 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006388static void
Daniel Veillard04383752001-07-08 14:27:15 +00006389xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6390{
Owen Taylor3473f882001-02-23 17:55:21 +00006391 xmlXPathObjectPtr cur;
6392
6393 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006394 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6395 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006396 }
6397
6398 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006399 if ((ctxt->value == NULL) ||
6400 ((ctxt->value->type != XPATH_NODESET) &&
6401 (ctxt->value->type != XPATH_XSLT_TREE)))
6402 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006403 cur = valuePop(ctxt);
6404
Daniel Veillard911f49a2001-04-07 15:39:35 +00006405 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006406 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006407 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006408 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006409
Daniel Veillard04383752001-07-08 14:27:15 +00006410 switch (cur->nodesetval->nodeTab[i]->type) {
6411 case XML_ELEMENT_NODE:
6412 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006413 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6414 valuePush(ctxt, xmlXPathNewCString(""));
6415 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6416 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006417 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006418 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006419
Daniel Veillard652d8a92003-02-04 19:28:49 +00006420 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006421 xmlChar *fullname;
6422
6423 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6424 cur->nodesetval->nodeTab[i]->ns->prefix,
6425 NULL, 0);
6426 if (fullname == cur->nodesetval->nodeTab[i]->name)
6427 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6428 if (fullname == NULL) {
6429 XP_ERROR(XPATH_MEMORY_ERROR);
6430 }
6431 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006432 }
6433 break;
6434 default:
6435 valuePush(ctxt,
6436 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6437 xmlXPathLocalNameFunction(ctxt, 1);
6438 }
Owen Taylor3473f882001-02-23 17:55:21 +00006439 }
6440 xmlXPathFreeObject(cur);
6441}
6442
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006443
6444/**
Owen Taylor3473f882001-02-23 17:55:21 +00006445 * xmlXPathStringFunction:
6446 * @ctxt: the XPath Parser context
6447 * @nargs: the number of arguments
6448 *
6449 * Implement the string() XPath function
6450 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006451 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006452 * - A node-set is converted to a string by returning the value of
6453 * the node in the node-set that is first in document order.
6454 * If the node-set is empty, an empty string is returned.
6455 * - A number is converted to a string as follows
6456 * + NaN is converted to the string NaN
6457 * + positive zero is converted to the string 0
6458 * + negative zero is converted to the string 0
6459 * + positive infinity is converted to the string Infinity
6460 * + negative infinity is converted to the string -Infinity
6461 * + if the number is an integer, the number is represented in
6462 * decimal form as a Number with no decimal point and no leading
6463 * zeros, preceded by a minus sign (-) if the number is negative
6464 * + otherwise, the number is represented in decimal form as a
6465 * Number including a decimal point with at least one digit
6466 * before the decimal point and at least one digit after the
6467 * decimal point, preceded by a minus sign (-) if the number
6468 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006469 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006470 * before the decimal point; beyond the one required digit
6471 * after the decimal point there must be as many, but only as
6472 * many, more digits as are needed to uniquely distinguish the
6473 * number from all other IEEE 754 numeric values.
6474 * - The boolean false value is converted to the string false.
6475 * The boolean true value is converted to the string true.
6476 *
6477 * If the argument is omitted, it defaults to a node-set with the
6478 * context node as its only member.
6479 */
6480void
6481xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6482 xmlXPathObjectPtr cur;
6483
Daniel Veillarda82b1822004-11-08 16:24:57 +00006484 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006485 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006486 valuePush(ctxt,
6487 xmlXPathWrapString(
6488 xmlXPathCastNodeToString(ctxt->context->node)));
6489 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006490 }
6491
6492 CHECK_ARITY(1);
6493 cur = valuePop(ctxt);
6494 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006495 cur = xmlXPathConvertString(cur);
6496 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006497}
6498
6499/**
6500 * xmlXPathStringLengthFunction:
6501 * @ctxt: the XPath Parser context
6502 * @nargs: the number of arguments
6503 *
6504 * Implement the string-length() XPath function
6505 * number string-length(string?)
6506 * The string-length returns the number of characters in the string
6507 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6508 * the context node converted to a string, in other words the value
6509 * of the context node.
6510 */
6511void
6512xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6513 xmlXPathObjectPtr cur;
6514
6515 if (nargs == 0) {
Daniel Veillarda82b1822004-11-08 16:24:57 +00006516 if ((ctxt == NULL) || (ctxt->context == NULL))
6517 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006518 if (ctxt->context->node == NULL) {
6519 valuePush(ctxt, xmlXPathNewFloat(0));
6520 } else {
6521 xmlChar *content;
6522
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006523 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006524 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006525 xmlFree(content);
6526 }
6527 return;
6528 }
6529 CHECK_ARITY(1);
6530 CAST_TO_STRING;
6531 CHECK_TYPE(XPATH_STRING);
6532 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006533 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006534 xmlXPathFreeObject(cur);
6535}
6536
6537/**
6538 * xmlXPathConcatFunction:
6539 * @ctxt: the XPath Parser context
6540 * @nargs: the number of arguments
6541 *
6542 * Implement the concat() XPath function
6543 * string concat(string, string, string*)
6544 * The concat function returns the concatenation of its arguments.
6545 */
6546void
6547xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6548 xmlXPathObjectPtr cur, newobj;
6549 xmlChar *tmp;
6550
Daniel Veillarda82b1822004-11-08 16:24:57 +00006551 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006552 if (nargs < 2) {
6553 CHECK_ARITY(2);
6554 }
6555
6556 CAST_TO_STRING;
6557 cur = valuePop(ctxt);
6558 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6559 xmlXPathFreeObject(cur);
6560 return;
6561 }
6562 nargs--;
6563
6564 while (nargs > 0) {
6565 CAST_TO_STRING;
6566 newobj = valuePop(ctxt);
6567 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6568 xmlXPathFreeObject(newobj);
6569 xmlXPathFreeObject(cur);
6570 XP_ERROR(XPATH_INVALID_TYPE);
6571 }
6572 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6573 newobj->stringval = cur->stringval;
6574 cur->stringval = tmp;
6575
6576 xmlXPathFreeObject(newobj);
6577 nargs--;
6578 }
6579 valuePush(ctxt, cur);
6580}
6581
6582/**
6583 * xmlXPathContainsFunction:
6584 * @ctxt: the XPath Parser context
6585 * @nargs: the number of arguments
6586 *
6587 * Implement the contains() XPath function
6588 * boolean contains(string, string)
6589 * The contains function returns true if the first argument string
6590 * contains the second argument string, and otherwise returns false.
6591 */
6592void
6593xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6594 xmlXPathObjectPtr hay, needle;
6595
6596 CHECK_ARITY(2);
6597 CAST_TO_STRING;
6598 CHECK_TYPE(XPATH_STRING);
6599 needle = valuePop(ctxt);
6600 CAST_TO_STRING;
6601 hay = valuePop(ctxt);
6602 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6603 xmlXPathFreeObject(hay);
6604 xmlXPathFreeObject(needle);
6605 XP_ERROR(XPATH_INVALID_TYPE);
6606 }
6607 if (xmlStrstr(hay->stringval, needle->stringval))
6608 valuePush(ctxt, xmlXPathNewBoolean(1));
6609 else
6610 valuePush(ctxt, xmlXPathNewBoolean(0));
6611 xmlXPathFreeObject(hay);
6612 xmlXPathFreeObject(needle);
6613}
6614
6615/**
6616 * xmlXPathStartsWithFunction:
6617 * @ctxt: the XPath Parser context
6618 * @nargs: the number of arguments
6619 *
6620 * Implement the starts-with() XPath function
6621 * boolean starts-with(string, string)
6622 * The starts-with function returns true if the first argument string
6623 * starts with the second argument string, and otherwise returns false.
6624 */
6625void
6626xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6627 xmlXPathObjectPtr hay, needle;
6628 int n;
6629
6630 CHECK_ARITY(2);
6631 CAST_TO_STRING;
6632 CHECK_TYPE(XPATH_STRING);
6633 needle = valuePop(ctxt);
6634 CAST_TO_STRING;
6635 hay = valuePop(ctxt);
6636 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6637 xmlXPathFreeObject(hay);
6638 xmlXPathFreeObject(needle);
6639 XP_ERROR(XPATH_INVALID_TYPE);
6640 }
6641 n = xmlStrlen(needle->stringval);
6642 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6643 valuePush(ctxt, xmlXPathNewBoolean(0));
6644 else
6645 valuePush(ctxt, xmlXPathNewBoolean(1));
6646 xmlXPathFreeObject(hay);
6647 xmlXPathFreeObject(needle);
6648}
6649
6650/**
6651 * xmlXPathSubstringFunction:
6652 * @ctxt: the XPath Parser context
6653 * @nargs: the number of arguments
6654 *
6655 * Implement the substring() XPath function
6656 * string substring(string, number, number?)
6657 * The substring function returns the substring of the first argument
6658 * starting at the position specified in the second argument with
6659 * length specified in the third argument. For example,
6660 * substring("12345",2,3) returns "234". If the third argument is not
6661 * specified, it returns the substring starting at the position specified
6662 * in the second argument and continuing to the end of the string. For
6663 * example, substring("12345",2) returns "2345". More precisely, each
6664 * character in the string (see [3.6 Strings]) is considered to have a
6665 * numeric position: the position of the first character is 1, the position
6666 * of the second character is 2 and so on. The returned substring contains
6667 * those characters for which the position of the character is greater than
6668 * or equal to the second argument and, if the third argument is specified,
6669 * less than the sum of the second and third arguments; the comparisons
6670 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6671 * - substring("12345", 1.5, 2.6) returns "234"
6672 * - substring("12345", 0, 3) returns "12"
6673 * - substring("12345", 0 div 0, 3) returns ""
6674 * - substring("12345", 1, 0 div 0) returns ""
6675 * - substring("12345", -42, 1 div 0) returns "12345"
6676 * - substring("12345", -1 div 0, 1 div 0) returns ""
6677 */
6678void
6679xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6680 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006681 double le=0, in;
6682 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006683 xmlChar *ret;
6684
Owen Taylor3473f882001-02-23 17:55:21 +00006685 if (nargs < 2) {
6686 CHECK_ARITY(2);
6687 }
6688 if (nargs > 3) {
6689 CHECK_ARITY(3);
6690 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006691 /*
6692 * take care of possible last (position) argument
6693 */
Owen Taylor3473f882001-02-23 17:55:21 +00006694 if (nargs == 3) {
6695 CAST_TO_NUMBER;
6696 CHECK_TYPE(XPATH_NUMBER);
6697 len = valuePop(ctxt);
6698 le = len->floatval;
6699 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006700 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006701
Owen Taylor3473f882001-02-23 17:55:21 +00006702 CAST_TO_NUMBER;
6703 CHECK_TYPE(XPATH_NUMBER);
6704 start = valuePop(ctxt);
6705 in = start->floatval;
6706 xmlXPathFreeObject(start);
6707 CAST_TO_STRING;
6708 CHECK_TYPE(XPATH_STRING);
6709 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006710 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006711
Daniel Veillard97ac1312001-05-30 19:14:17 +00006712 /*
6713 * If last pos not present, calculate last position
6714 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006715 if (nargs != 3) {
6716 le = (double)m;
6717 if (in < 1.0)
6718 in = 1.0;
6719 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006720
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006721 /* Need to check for the special cases where either
6722 * the index is NaN, the length is NaN, or both
6723 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006724 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006725 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006726 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006727 * To meet the requirements of the spec, the arguments
6728 * must be converted to integer format before
6729 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006730 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006731 * First we go to integer form, rounding up
6732 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006733 */
6734 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006735 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006736
Daniel Veillard9e412302002-06-10 15:59:44 +00006737 if (xmlXPathIsInf(le) == 1) {
6738 l = m;
6739 if (i < 1)
6740 i = 1;
6741 }
6742 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6743 l = 0;
6744 else {
6745 l = (int) le;
6746 if (((double)l)+0.5 <= le) l++;
6747 }
6748
6749 /* Now we normalize inidices */
6750 i -= 1;
6751 l += i;
6752 if (i < 0)
6753 i = 0;
6754 if (l > m)
6755 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006756
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006757 /* number of chars to copy */
6758 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006759
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006760 ret = xmlUTF8Strsub(str->stringval, i, l);
6761 }
6762 else {
6763 ret = NULL;
6764 }
6765
Owen Taylor3473f882001-02-23 17:55:21 +00006766 if (ret == NULL)
6767 valuePush(ctxt, xmlXPathNewCString(""));
6768 else {
6769 valuePush(ctxt, xmlXPathNewString(ret));
6770 xmlFree(ret);
6771 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006772
Owen Taylor3473f882001-02-23 17:55:21 +00006773 xmlXPathFreeObject(str);
6774}
6775
6776/**
6777 * xmlXPathSubstringBeforeFunction:
6778 * @ctxt: the XPath Parser context
6779 * @nargs: the number of arguments
6780 *
6781 * Implement the substring-before() XPath function
6782 * string substring-before(string, string)
6783 * The substring-before function returns the substring of the first
6784 * argument string that precedes the first occurrence of the second
6785 * argument string in the first argument string, or the empty string
6786 * if the first argument string does not contain the second argument
6787 * string. For example, substring-before("1999/04/01","/") returns 1999.
6788 */
6789void
6790xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6791 xmlXPathObjectPtr str;
6792 xmlXPathObjectPtr find;
6793 xmlBufferPtr target;
6794 const xmlChar *point;
6795 int offset;
6796
6797 CHECK_ARITY(2);
6798 CAST_TO_STRING;
6799 find = valuePop(ctxt);
6800 CAST_TO_STRING;
6801 str = valuePop(ctxt);
6802
6803 target = xmlBufferCreate();
6804 if (target) {
6805 point = xmlStrstr(str->stringval, find->stringval);
6806 if (point) {
6807 offset = (int)(point - str->stringval);
6808 xmlBufferAdd(target, str->stringval, offset);
6809 }
6810 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6811 xmlBufferFree(target);
6812 }
6813
6814 xmlXPathFreeObject(str);
6815 xmlXPathFreeObject(find);
6816}
6817
6818/**
6819 * xmlXPathSubstringAfterFunction:
6820 * @ctxt: the XPath Parser context
6821 * @nargs: the number of arguments
6822 *
6823 * Implement the substring-after() XPath function
6824 * string substring-after(string, string)
6825 * The substring-after function returns the substring of the first
6826 * argument string that follows the first occurrence of the second
6827 * argument string in the first argument string, or the empty stringi
6828 * if the first argument string does not contain the second argument
6829 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6830 * and substring-after("1999/04/01","19") returns 99/04/01.
6831 */
6832void
6833xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6834 xmlXPathObjectPtr str;
6835 xmlXPathObjectPtr find;
6836 xmlBufferPtr target;
6837 const xmlChar *point;
6838 int offset;
6839
6840 CHECK_ARITY(2);
6841 CAST_TO_STRING;
6842 find = valuePop(ctxt);
6843 CAST_TO_STRING;
6844 str = valuePop(ctxt);
6845
6846 target = xmlBufferCreate();
6847 if (target) {
6848 point = xmlStrstr(str->stringval, find->stringval);
6849 if (point) {
6850 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6851 xmlBufferAdd(target, &str->stringval[offset],
6852 xmlStrlen(str->stringval) - offset);
6853 }
6854 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6855 xmlBufferFree(target);
6856 }
6857
6858 xmlXPathFreeObject(str);
6859 xmlXPathFreeObject(find);
6860}
6861
6862/**
6863 * xmlXPathNormalizeFunction:
6864 * @ctxt: the XPath Parser context
6865 * @nargs: the number of arguments
6866 *
6867 * Implement the normalize-space() XPath function
6868 * string normalize-space(string?)
6869 * The normalize-space function returns the argument string with white
6870 * space normalized by stripping leading and trailing whitespace
6871 * and replacing sequences of whitespace characters by a single
6872 * space. Whitespace characters are the same allowed by the S production
6873 * in XML. If the argument is omitted, it defaults to the context
6874 * node converted to a string, in other words the value of the context node.
6875 */
6876void
6877xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6878 xmlXPathObjectPtr obj = NULL;
6879 xmlChar *source = NULL;
6880 xmlBufferPtr target;
6881 xmlChar blank;
6882
Daniel Veillarda82b1822004-11-08 16:24:57 +00006883 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00006884 if (nargs == 0) {
6885 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006886 valuePush(ctxt,
6887 xmlXPathWrapString(
6888 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006889 nargs = 1;
6890 }
6891
6892 CHECK_ARITY(1);
6893 CAST_TO_STRING;
6894 CHECK_TYPE(XPATH_STRING);
6895 obj = valuePop(ctxt);
6896 source = obj->stringval;
6897
6898 target = xmlBufferCreate();
6899 if (target && source) {
6900
6901 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006902 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006903 source++;
6904
6905 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6906 blank = 0;
6907 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006908 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006909 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006910 } else {
6911 if (blank) {
6912 xmlBufferAdd(target, &blank, 1);
6913 blank = 0;
6914 }
6915 xmlBufferAdd(target, source, 1);
6916 }
6917 source++;
6918 }
6919
6920 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6921 xmlBufferFree(target);
6922 }
6923 xmlXPathFreeObject(obj);
6924}
6925
6926/**
6927 * xmlXPathTranslateFunction:
6928 * @ctxt: the XPath Parser context
6929 * @nargs: the number of arguments
6930 *
6931 * Implement the translate() XPath function
6932 * string translate(string, string, string)
6933 * The translate function returns the first argument string with
6934 * occurrences of characters in the second argument string replaced
6935 * by the character at the corresponding position in the third argument
6936 * string. For example, translate("bar","abc","ABC") returns the string
6937 * BAr. If there is a character in the second argument string with no
6938 * character at a corresponding position in the third argument string
6939 * (because the second argument string is longer than the third argument
6940 * string), then occurrences of that character in the first argument
6941 * string are removed. For example, translate("--aaa--","abc-","ABC")
6942 * returns "AAA". If a character occurs more than once in second
6943 * argument string, then the first occurrence determines the replacement
6944 * character. If the third argument string is longer than the second
6945 * argument string, then excess characters are ignored.
6946 */
6947void
6948xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006949 xmlXPathObjectPtr str;
6950 xmlXPathObjectPtr from;
6951 xmlXPathObjectPtr to;
6952 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006953 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006954 xmlChar ch;
William M. Brackb031cef2004-11-05 16:34:22 +00006955 const xmlChar *point;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006956 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006957
Daniel Veillarde043ee12001-04-16 14:08:07 +00006958 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006959
Daniel Veillarde043ee12001-04-16 14:08:07 +00006960 CAST_TO_STRING;
6961 to = valuePop(ctxt);
6962 CAST_TO_STRING;
6963 from = valuePop(ctxt);
6964 CAST_TO_STRING;
6965 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006966
Daniel Veillarde043ee12001-04-16 14:08:07 +00006967 target = xmlBufferCreate();
6968 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006969 max = xmlUTF8Strlen(to->stringval);
6970 for (cptr = str->stringval; (ch=*cptr); ) {
6971 offset = xmlUTF8Strloc(from->stringval, cptr);
6972 if (offset >= 0) {
6973 if (offset < max) {
6974 point = xmlUTF8Strpos(to->stringval, offset);
6975 if (point)
6976 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6977 }
6978 } else
6979 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6980
6981 /* Step to next character in input */
6982 cptr++;
6983 if ( ch & 0x80 ) {
6984 /* if not simple ascii, verify proper format */
6985 if ( (ch & 0xc0) != 0xc0 ) {
6986 xmlGenericError(xmlGenericErrorContext,
6987 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6988 break;
6989 }
6990 /* then skip over remaining bytes for this char */
6991 while ( (ch <<= 1) & 0x80 )
6992 if ( (*cptr++ & 0xc0) != 0x80 ) {
6993 xmlGenericError(xmlGenericErrorContext,
6994 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6995 break;
6996 }
6997 if (ch & 0x80) /* must have had error encountered */
6998 break;
6999 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007000 }
Owen Taylor3473f882001-02-23 17:55:21 +00007001 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00007002 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
7003 xmlBufferFree(target);
7004 xmlXPathFreeObject(str);
7005 xmlXPathFreeObject(from);
7006 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00007007}
7008
7009/**
7010 * xmlXPathBooleanFunction:
7011 * @ctxt: the XPath Parser context
7012 * @nargs: the number of arguments
7013 *
7014 * Implement the boolean() XPath function
7015 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00007016 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00007017 * - a number is true if and only if it is neither positive or
7018 * negative zero nor NaN
7019 * - a node-set is true if and only if it is non-empty
7020 * - a string is true if and only if its length is non-zero
7021 */
7022void
7023xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7024 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00007025
7026 CHECK_ARITY(1);
7027 cur = valuePop(ctxt);
7028 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007029 cur = xmlXPathConvertBoolean(cur);
7030 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007031}
7032
7033/**
7034 * xmlXPathNotFunction:
7035 * @ctxt: the XPath Parser context
7036 * @nargs: the number of arguments
7037 *
7038 * Implement the not() XPath function
7039 * boolean not(boolean)
7040 * The not function returns true if its argument is false,
7041 * and false otherwise.
7042 */
7043void
7044xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7045 CHECK_ARITY(1);
7046 CAST_TO_BOOLEAN;
7047 CHECK_TYPE(XPATH_BOOLEAN);
7048 ctxt->value->boolval = ! ctxt->value->boolval;
7049}
7050
7051/**
7052 * xmlXPathTrueFunction:
7053 * @ctxt: the XPath Parser context
7054 * @nargs: the number of arguments
7055 *
7056 * Implement the true() XPath function
7057 * boolean true()
7058 */
7059void
7060xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7061 CHECK_ARITY(0);
7062 valuePush(ctxt, xmlXPathNewBoolean(1));
7063}
7064
7065/**
7066 * xmlXPathFalseFunction:
7067 * @ctxt: the XPath Parser context
7068 * @nargs: the number of arguments
7069 *
7070 * Implement the false() XPath function
7071 * boolean false()
7072 */
7073void
7074xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7075 CHECK_ARITY(0);
7076 valuePush(ctxt, xmlXPathNewBoolean(0));
7077}
7078
7079/**
7080 * xmlXPathLangFunction:
7081 * @ctxt: the XPath Parser context
7082 * @nargs: the number of arguments
7083 *
7084 * Implement the lang() XPath function
7085 * boolean lang(string)
7086 * The lang function returns true or false depending on whether the
7087 * language of the context node as specified by xml:lang attributes
7088 * is the same as or is a sublanguage of the language specified by
7089 * the argument string. The language of the context node is determined
7090 * by the value of the xml:lang attribute on the context node, or, if
7091 * the context node has no xml:lang attribute, by the value of the
7092 * xml:lang attribute on the nearest ancestor of the context node that
7093 * has an xml:lang attribute. If there is no such attribute, then lang
7094 * returns false. If there is such an attribute, then lang returns
7095 * true if the attribute value is equal to the argument ignoring case,
7096 * or if there is some suffix starting with - such that the attribute
7097 * value is equal to the argument ignoring that suffix of the attribute
7098 * value and ignoring case.
7099 */
7100void
7101xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007102 xmlXPathObjectPtr val = NULL;
7103 const xmlChar *theLang = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00007104 const xmlChar *lang;
7105 int ret = 0;
7106 int i;
7107
7108 CHECK_ARITY(1);
7109 CAST_TO_STRING;
7110 CHECK_TYPE(XPATH_STRING);
7111 val = valuePop(ctxt);
7112 lang = val->stringval;
7113 theLang = xmlNodeGetLang(ctxt->context->node);
7114 if ((theLang != NULL) && (lang != NULL)) {
7115 for (i = 0;lang[i] != 0;i++)
7116 if (toupper(lang[i]) != toupper(theLang[i]))
7117 goto not_equal;
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007118 if ((theLang[i] == 0) || (theLang[i] == '-'))
7119 ret = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007120 }
7121not_equal:
Daniel Veillard4ddaa562005-04-06 14:09:08 +00007122 if (theLang != NULL)
7123 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007124 xmlXPathFreeObject(val);
7125 valuePush(ctxt, xmlXPathNewBoolean(ret));
7126}
7127
7128/**
7129 * xmlXPathNumberFunction:
7130 * @ctxt: the XPath Parser context
7131 * @nargs: the number of arguments
7132 *
7133 * Implement the number() XPath function
7134 * number number(object?)
7135 */
7136void
7137xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7138 xmlXPathObjectPtr cur;
7139 double res;
7140
Daniel Veillarda82b1822004-11-08 16:24:57 +00007141 if (ctxt == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00007142 if (nargs == 0) {
7143 if (ctxt->context->node == NULL) {
7144 valuePush(ctxt, xmlXPathNewFloat(0.0));
7145 } else {
7146 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7147
7148 res = xmlXPathStringEvalNumber(content);
7149 valuePush(ctxt, xmlXPathNewFloat(res));
7150 xmlFree(content);
7151 }
7152 return;
7153 }
7154
7155 CHECK_ARITY(1);
7156 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007157 cur = xmlXPathConvertNumber(cur);
7158 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007159}
7160
7161/**
7162 * xmlXPathSumFunction:
7163 * @ctxt: the XPath Parser context
7164 * @nargs: the number of arguments
7165 *
7166 * Implement the sum() XPath function
7167 * number sum(node-set)
7168 * The sum function returns the sum of the values of the nodes in
7169 * the argument node-set.
7170 */
7171void
7172xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7173 xmlXPathObjectPtr cur;
7174 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007175 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007176
7177 CHECK_ARITY(1);
7178 if ((ctxt->value == NULL) ||
7179 ((ctxt->value->type != XPATH_NODESET) &&
7180 (ctxt->value->type != XPATH_XSLT_TREE)))
7181 XP_ERROR(XPATH_INVALID_TYPE);
7182 cur = valuePop(ctxt);
7183
William M. Brack08171912003-12-29 02:52:11 +00007184 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007185 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7186 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007187 }
7188 }
William M. Brack08171912003-12-29 02:52:11 +00007189 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007190 xmlXPathFreeObject(cur);
7191}
7192
William M. Brack3d426662005-04-19 14:40:28 +00007193/*
7194 * To assure working code on multiple platforms, we want to only depend
7195 * upon the characteristic truncation of converting a floating point value
7196 * to an integer. Unfortunately, because of the different storage sizes
7197 * of our internal floating point value (double) and integer (int), we
7198 * can't directly convert (see bug 301162). This macro is a messy
7199 * 'workaround'
7200 */
7201#define XTRUNC(f, v) \
7202 f = fmod((v), INT_MAX); \
7203 f = (v) - (f) + (double)((int)(f));
7204
Owen Taylor3473f882001-02-23 17:55:21 +00007205/**
7206 * xmlXPathFloorFunction:
7207 * @ctxt: the XPath Parser context
7208 * @nargs: the number of arguments
7209 *
7210 * Implement the floor() XPath function
7211 * number floor(number)
7212 * The floor function returns the largest (closest to positive infinity)
7213 * number that is not greater than the argument and that is an integer.
7214 */
7215void
7216xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007217 double f;
7218
Owen Taylor3473f882001-02-23 17:55:21 +00007219 CHECK_ARITY(1);
7220 CAST_TO_NUMBER;
7221 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007222
William M. Brack3d426662005-04-19 14:40:28 +00007223 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007224 if (f != ctxt->value->floatval) {
7225 if (ctxt->value->floatval > 0)
7226 ctxt->value->floatval = f;
7227 else
7228 ctxt->value->floatval = f - 1;
7229 }
Owen Taylor3473f882001-02-23 17:55:21 +00007230}
7231
7232/**
7233 * xmlXPathCeilingFunction:
7234 * @ctxt: the XPath Parser context
7235 * @nargs: the number of arguments
7236 *
7237 * Implement the ceiling() XPath function
7238 * number ceiling(number)
7239 * The ceiling function returns the smallest (closest to negative infinity)
7240 * number that is not less than the argument and that is an integer.
7241 */
7242void
7243xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7244 double f;
7245
7246 CHECK_ARITY(1);
7247 CAST_TO_NUMBER;
7248 CHECK_TYPE(XPATH_NUMBER);
7249
7250#if 0
7251 ctxt->value->floatval = ceil(ctxt->value->floatval);
7252#else
William M. Brack3d426662005-04-19 14:40:28 +00007253 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007254 if (f != ctxt->value->floatval) {
7255 if (ctxt->value->floatval > 0)
7256 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007257 else {
7258 if (ctxt->value->floatval < 0 && f == 0)
7259 ctxt->value->floatval = xmlXPathNZERO;
7260 else
7261 ctxt->value->floatval = f;
7262 }
7263
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007264 }
Owen Taylor3473f882001-02-23 17:55:21 +00007265#endif
7266}
7267
7268/**
7269 * xmlXPathRoundFunction:
7270 * @ctxt: the XPath Parser context
7271 * @nargs: the number of arguments
7272 *
7273 * Implement the round() XPath function
7274 * number round(number)
7275 * The round function returns the number that is closest to the
7276 * argument and that is an integer. If there are two such numbers,
7277 * then the one that is even is returned.
7278 */
7279void
7280xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7281 double f;
7282
7283 CHECK_ARITY(1);
7284 CAST_TO_NUMBER;
7285 CHECK_TYPE(XPATH_NUMBER);
7286
Daniel Veillardcda96922001-08-21 10:56:31 +00007287 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7288 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7289 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007290 (ctxt->value->floatval == 0.0))
7291 return;
7292
William M. Brack3d426662005-04-19 14:40:28 +00007293 XTRUNC(f, ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007294 if (ctxt->value->floatval < 0) {
7295 if (ctxt->value->floatval < f - 0.5)
7296 ctxt->value->floatval = f - 1;
7297 else
7298 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007299 if (ctxt->value->floatval == 0)
7300 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007301 } else {
7302 if (ctxt->value->floatval < f + 0.5)
7303 ctxt->value->floatval = f;
7304 else
7305 ctxt->value->floatval = f + 1;
7306 }
Owen Taylor3473f882001-02-23 17:55:21 +00007307}
7308
7309/************************************************************************
7310 * *
7311 * The Parser *
7312 * *
7313 ************************************************************************/
7314
7315/*
William M. Brack08171912003-12-29 02:52:11 +00007316 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007317 * implementation.
7318 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007319static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007320static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007321static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007322static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007323static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7324 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007325
7326/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007327 * xmlXPathCurrentChar:
7328 * @ctxt: the XPath parser context
7329 * @cur: pointer to the beginning of the char
7330 * @len: pointer to the length of the char read
7331 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007332 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007333 * bytes in the input buffer.
7334 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007335 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007336 */
7337
7338static int
7339xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7340 unsigned char c;
7341 unsigned int val;
7342 const xmlChar *cur;
7343
7344 if (ctxt == NULL)
7345 return(0);
7346 cur = ctxt->cur;
7347
7348 /*
7349 * We are supposed to handle UTF8, check it's valid
7350 * From rfc2044: encoding of the Unicode values on UTF-8:
7351 *
7352 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7353 * 0000 0000-0000 007F 0xxxxxxx
7354 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7355 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7356 *
7357 * Check for the 0x110000 limit too
7358 */
7359 c = *cur;
7360 if (c & 0x80) {
7361 if ((cur[1] & 0xc0) != 0x80)
7362 goto encoding_error;
7363 if ((c & 0xe0) == 0xe0) {
7364
7365 if ((cur[2] & 0xc0) != 0x80)
7366 goto encoding_error;
7367 if ((c & 0xf0) == 0xf0) {
7368 if (((c & 0xf8) != 0xf0) ||
7369 ((cur[3] & 0xc0) != 0x80))
7370 goto encoding_error;
7371 /* 4-byte code */
7372 *len = 4;
7373 val = (cur[0] & 0x7) << 18;
7374 val |= (cur[1] & 0x3f) << 12;
7375 val |= (cur[2] & 0x3f) << 6;
7376 val |= cur[3] & 0x3f;
7377 } else {
7378 /* 3-byte code */
7379 *len = 3;
7380 val = (cur[0] & 0xf) << 12;
7381 val |= (cur[1] & 0x3f) << 6;
7382 val |= cur[2] & 0x3f;
7383 }
7384 } else {
7385 /* 2-byte code */
7386 *len = 2;
7387 val = (cur[0] & 0x1f) << 6;
7388 val |= cur[1] & 0x3f;
7389 }
7390 if (!IS_CHAR(val)) {
7391 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7392 }
7393 return(val);
7394 } else {
7395 /* 1-byte code */
7396 *len = 1;
7397 return((int) *cur);
7398 }
7399encoding_error:
7400 /*
William M. Brack08171912003-12-29 02:52:11 +00007401 * If we detect an UTF8 error that probably means that the
7402 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007403 * declaration header. Report the error and switch the encoding
7404 * to ISO-Latin-1 (if you don't like this policy, just declare the
7405 * encoding !)
7406 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007407 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007408 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007409}
7410
7411/**
Owen Taylor3473f882001-02-23 17:55:21 +00007412 * xmlXPathParseNCName:
7413 * @ctxt: the XPath Parser context
7414 *
7415 * parse an XML namespace non qualified name.
7416 *
7417 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7418 *
7419 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7420 * CombiningChar | Extender
7421 *
7422 * Returns the namespace name or NULL
7423 */
7424
7425xmlChar *
7426xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007427 const xmlChar *in;
7428 xmlChar *ret;
7429 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007430
Daniel Veillarda82b1822004-11-08 16:24:57 +00007431 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard2156a562001-04-28 12:24:34 +00007432 /*
7433 * Accelerator for simple ASCII names
7434 */
7435 in = ctxt->cur;
7436 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7437 ((*in >= 0x41) && (*in <= 0x5A)) ||
7438 (*in == '_')) {
7439 in++;
7440 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7441 ((*in >= 0x41) && (*in <= 0x5A)) ||
7442 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007443 (*in == '_') || (*in == '.') ||
7444 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007445 in++;
7446 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7447 (*in == '[') || (*in == ']') || (*in == ':') ||
7448 (*in == '@') || (*in == '*')) {
7449 count = in - ctxt->cur;
7450 if (count == 0)
7451 return(NULL);
7452 ret = xmlStrndup(ctxt->cur, count);
7453 ctxt->cur = in;
7454 return(ret);
7455 }
7456 }
7457 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007458}
7459
Daniel Veillard2156a562001-04-28 12:24:34 +00007460
Owen Taylor3473f882001-02-23 17:55:21 +00007461/**
7462 * xmlXPathParseQName:
7463 * @ctxt: the XPath Parser context
7464 * @prefix: a xmlChar **
7465 *
7466 * parse an XML qualified name
7467 *
7468 * [NS 5] QName ::= (Prefix ':')? LocalPart
7469 *
7470 * [NS 6] Prefix ::= NCName
7471 *
7472 * [NS 7] LocalPart ::= NCName
7473 *
7474 * Returns the function returns the local part, and prefix is updated
7475 * to get the Prefix if any.
7476 */
7477
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007478static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007479xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7480 xmlChar *ret = NULL;
7481
7482 *prefix = NULL;
7483 ret = xmlXPathParseNCName(ctxt);
7484 if (CUR == ':') {
7485 *prefix = ret;
7486 NEXT;
7487 ret = xmlXPathParseNCName(ctxt);
7488 }
7489 return(ret);
7490}
7491
7492/**
7493 * xmlXPathParseName:
7494 * @ctxt: the XPath Parser context
7495 *
7496 * parse an XML name
7497 *
7498 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7499 * CombiningChar | Extender
7500 *
7501 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7502 *
7503 * Returns the namespace name or NULL
7504 */
7505
7506xmlChar *
7507xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007508 const xmlChar *in;
7509 xmlChar *ret;
7510 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007511
Daniel Veillarda82b1822004-11-08 16:24:57 +00007512 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007513 /*
7514 * Accelerator for simple ASCII names
7515 */
7516 in = ctxt->cur;
7517 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7518 ((*in >= 0x41) && (*in <= 0x5A)) ||
7519 (*in == '_') || (*in == ':')) {
7520 in++;
7521 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7522 ((*in >= 0x41) && (*in <= 0x5A)) ||
7523 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007524 (*in == '_') || (*in == '-') ||
7525 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007526 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007527 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007528 count = in - ctxt->cur;
7529 ret = xmlStrndup(ctxt->cur, count);
7530 ctxt->cur = in;
7531 return(ret);
7532 }
7533 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007534 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007535}
7536
Daniel Veillard61d80a22001-04-27 17:13:01 +00007537static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007538xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007539 xmlChar buf[XML_MAX_NAMELEN + 5];
7540 int len = 0, l;
7541 int c;
7542
7543 /*
7544 * Handler for more complex cases
7545 */
7546 c = CUR_CHAR(l);
7547 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007548 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7549 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007550 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007551 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007552 return(NULL);
7553 }
7554
7555 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7556 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7557 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007558 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007559 (IS_COMBINING(c)) ||
7560 (IS_EXTENDER(c)))) {
7561 COPY_BUF(l,buf,len,c);
7562 NEXTL(l);
7563 c = CUR_CHAR(l);
7564 if (len >= XML_MAX_NAMELEN) {
7565 /*
7566 * Okay someone managed to make a huge name, so he's ready to pay
7567 * for the processing speed.
7568 */
7569 xmlChar *buffer;
7570 int max = len * 2;
7571
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007572 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007573 if (buffer == NULL) {
7574 XP_ERROR0(XPATH_MEMORY_ERROR);
7575 }
7576 memcpy(buffer, buf, len);
7577 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7578 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007579 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007580 (IS_COMBINING(c)) ||
7581 (IS_EXTENDER(c))) {
7582 if (len + 10 > max) {
7583 max *= 2;
7584 buffer = (xmlChar *) xmlRealloc(buffer,
7585 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007586 if (buffer == NULL) {
7587 XP_ERROR0(XPATH_MEMORY_ERROR);
7588 }
7589 }
7590 COPY_BUF(l,buffer,len,c);
7591 NEXTL(l);
7592 c = CUR_CHAR(l);
7593 }
7594 buffer[len] = 0;
7595 return(buffer);
7596 }
7597 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007598 if (len == 0)
7599 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007600 return(xmlStrndup(buf, len));
7601}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007602
7603#define MAX_FRAC 20
7604
William M. Brack372a4452004-02-17 13:09:23 +00007605/*
7606 * These are used as divisors for the fractional part of a number.
7607 * Since the table includes 1.0 (representing '0' fractional digits),
7608 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7609 */
7610static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007611 1.0, 10.0, 100.0, 1000.0, 10000.0,
7612 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7613 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7614 100000000000000.0,
7615 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007616 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007617};
7618
Owen Taylor3473f882001-02-23 17:55:21 +00007619/**
7620 * xmlXPathStringEvalNumber:
7621 * @str: A string to scan
7622 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007623 * [30a] Float ::= Number ('e' Digits?)?
7624 *
Owen Taylor3473f882001-02-23 17:55:21 +00007625 * [30] Number ::= Digits ('.' Digits?)?
7626 * | '.' Digits
7627 * [31] Digits ::= [0-9]+
7628 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007629 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007630 * In complement of the Number expression, this function also handles
7631 * negative values : '-' Number.
7632 *
7633 * Returns the double value.
7634 */
7635double
7636xmlXPathStringEvalNumber(const xmlChar *str) {
7637 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007638 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007639 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007640 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007641 int exponent = 0;
7642 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007643#ifdef __GNUC__
7644 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007645 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007646#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007647 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007648 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007649 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7650 return(xmlXPathNAN);
7651 }
7652 if (*cur == '-') {
7653 isneg = 1;
7654 cur++;
7655 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007656
7657#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007658 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007659 * tmp/temp is a workaround against a gcc compiler bug
7660 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007661 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007662 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007663 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007664 ret = ret * 10;
7665 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007666 ok = 1;
7667 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007668 temp = (double) tmp;
7669 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007670 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007671#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007672 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007673 while ((*cur >= '0') && (*cur <= '9')) {
7674 ret = ret * 10 + (*cur - '0');
7675 ok = 1;
7676 cur++;
7677 }
7678#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007679
Owen Taylor3473f882001-02-23 17:55:21 +00007680 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007681 int v, frac = 0;
7682 double fraction = 0;
7683
Owen Taylor3473f882001-02-23 17:55:21 +00007684 cur++;
7685 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7686 return(xmlXPathNAN);
7687 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007688 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7689 v = (*cur - '0');
7690 fraction = fraction * 10 + v;
7691 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007692 cur++;
7693 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007694 fraction /= my_pow10[frac];
7695 ret = ret + fraction;
7696 while ((*cur >= '0') && (*cur <= '9'))
7697 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007698 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007699 if ((*cur == 'e') || (*cur == 'E')) {
7700 cur++;
7701 if (*cur == '-') {
7702 is_exponent_negative = 1;
7703 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007704 } else if (*cur == '+') {
7705 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007706 }
7707 while ((*cur >= '0') && (*cur <= '9')) {
7708 exponent = exponent * 10 + (*cur - '0');
7709 cur++;
7710 }
7711 }
William M. Brack76e95df2003-10-18 16:20:14 +00007712 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007713 if (*cur != 0) return(xmlXPathNAN);
7714 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007715 if (is_exponent_negative) exponent = -exponent;
7716 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007717 return(ret);
7718}
7719
7720/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007721 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007722 * @ctxt: the XPath Parser context
7723 *
7724 * [30] Number ::= Digits ('.' Digits?)?
7725 * | '.' Digits
7726 * [31] Digits ::= [0-9]+
7727 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007728 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007729 *
7730 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007731static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007732xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7733{
Owen Taylor3473f882001-02-23 17:55:21 +00007734 double ret = 0.0;
7735 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007736 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007737 int exponent = 0;
7738 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007739#ifdef __GNUC__
7740 unsigned long tmp = 0;
7741 double temp;
7742#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007743
7744 CHECK_ERROR;
7745 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7746 XP_ERROR(XPATH_NUMBER_ERROR);
7747 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007748#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007749 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007750 * tmp/temp is a workaround against a gcc compiler bug
7751 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007752 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007753 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007754 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007755 ret = ret * 10;
7756 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007757 ok = 1;
7758 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007759 temp = (double) tmp;
7760 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007761 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007762#else
7763 ret = 0;
7764 while ((CUR >= '0') && (CUR <= '9')) {
7765 ret = ret * 10 + (CUR - '0');
7766 ok = 1;
7767 NEXT;
7768 }
7769#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007770 if (CUR == '.') {
7771 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007772 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7773 XP_ERROR(XPATH_NUMBER_ERROR);
7774 }
7775 while ((CUR >= '0') && (CUR <= '9')) {
7776 mult /= 10;
7777 ret = ret + (CUR - '0') * mult;
7778 NEXT;
7779 }
Owen Taylor3473f882001-02-23 17:55:21 +00007780 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007781 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007782 NEXT;
7783 if (CUR == '-') {
7784 is_exponent_negative = 1;
7785 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007786 } else if (CUR == '+') {
7787 NEXT;
7788 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007789 while ((CUR >= '0') && (CUR <= '9')) {
7790 exponent = exponent * 10 + (CUR - '0');
7791 NEXT;
7792 }
7793 if (is_exponent_negative)
7794 exponent = -exponent;
7795 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007796 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007797 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007798 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007799}
7800
7801/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007802 * xmlXPathParseLiteral:
7803 * @ctxt: the XPath Parser context
7804 *
7805 * Parse a Literal
7806 *
7807 * [29] Literal ::= '"' [^"]* '"'
7808 * | "'" [^']* "'"
7809 *
7810 * Returns the value found or NULL in case of error
7811 */
7812static xmlChar *
7813xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7814 const xmlChar *q;
7815 xmlChar *ret = NULL;
7816
7817 if (CUR == '"') {
7818 NEXT;
7819 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007820 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007821 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007822 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007823 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7824 } else {
7825 ret = xmlStrndup(q, CUR_PTR - q);
7826 NEXT;
7827 }
7828 } else if (CUR == '\'') {
7829 NEXT;
7830 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007831 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007832 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007833 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007834 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7835 } else {
7836 ret = xmlStrndup(q, CUR_PTR - q);
7837 NEXT;
7838 }
7839 } else {
7840 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7841 }
7842 return(ret);
7843}
7844
7845/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007846 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007847 * @ctxt: the XPath Parser context
7848 *
7849 * Parse a Literal and push it on the stack.
7850 *
7851 * [29] Literal ::= '"' [^"]* '"'
7852 * | "'" [^']* "'"
7853 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007854 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007855 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007856static void
7857xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007858 const xmlChar *q;
7859 xmlChar *ret = NULL;
7860
7861 if (CUR == '"') {
7862 NEXT;
7863 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007864 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007865 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007866 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007867 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7868 } else {
7869 ret = xmlStrndup(q, CUR_PTR - q);
7870 NEXT;
7871 }
7872 } else if (CUR == '\'') {
7873 NEXT;
7874 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007875 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007876 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007877 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007878 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7879 } else {
7880 ret = xmlStrndup(q, CUR_PTR - q);
7881 NEXT;
7882 }
7883 } else {
7884 XP_ERROR(XPATH_START_LITERAL_ERROR);
7885 }
7886 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007887 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7888 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007889 xmlFree(ret);
7890}
7891
7892/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007893 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007894 * @ctxt: the XPath Parser context
7895 *
7896 * Parse a VariableReference, evaluate it and push it on the stack.
7897 *
7898 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007899 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007900 * of any of the types that are possible for the value of an expression,
7901 * and may also be of additional types not specified here.
7902 *
7903 * Early evaluation is possible since:
7904 * The variable bindings [...] used to evaluate a subexpression are
7905 * always the same as those used to evaluate the containing expression.
7906 *
7907 * [36] VariableReference ::= '$' QName
7908 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007909static void
7910xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007911 xmlChar *name;
7912 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007913
7914 SKIP_BLANKS;
7915 if (CUR != '$') {
7916 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7917 }
7918 NEXT;
7919 name = xmlXPathParseQName(ctxt, &prefix);
7920 if (name == NULL) {
7921 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7922 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007923 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007924 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7925 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007926 SKIP_BLANKS;
7927}
7928
7929/**
7930 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007931 * @name: a name string
7932 *
7933 * Is the name given a NodeType one.
7934 *
7935 * [38] NodeType ::= 'comment'
7936 * | 'text'
7937 * | 'processing-instruction'
7938 * | 'node'
7939 *
7940 * Returns 1 if true 0 otherwise
7941 */
7942int
7943xmlXPathIsNodeType(const xmlChar *name) {
7944 if (name == NULL)
7945 return(0);
7946
Daniel Veillard1971ee22002-01-31 20:29:19 +00007947 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007948 return(1);
7949 if (xmlStrEqual(name, BAD_CAST "text"))
7950 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007951 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007952 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007953 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007954 return(1);
7955 return(0);
7956}
7957
7958/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007959 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007960 * @ctxt: the XPath Parser context
7961 *
7962 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7963 * [17] Argument ::= Expr
7964 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007965 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007966 * pushed on the stack
7967 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007968static void
7969xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007970 xmlChar *name;
7971 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007972 int nbargs = 0;
7973
7974 name = xmlXPathParseQName(ctxt, &prefix);
7975 if (name == NULL) {
7976 XP_ERROR(XPATH_EXPR_ERROR);
7977 }
7978 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007979#ifdef DEBUG_EXPR
7980 if (prefix == NULL)
7981 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7982 name);
7983 else
7984 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7985 prefix, name);
7986#endif
7987
Owen Taylor3473f882001-02-23 17:55:21 +00007988 if (CUR != '(') {
7989 XP_ERROR(XPATH_EXPR_ERROR);
7990 }
7991 NEXT;
7992 SKIP_BLANKS;
7993
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007994 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007995 if (CUR != ')') {
7996 while (CUR != 0) {
7997 int op1 = ctxt->comp->last;
7998 ctxt->comp->last = -1;
7999 xmlXPathCompileExpr(ctxt);
8000 CHECK_ERROR;
8001 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8002 nbargs++;
8003 if (CUR == ')') break;
8004 if (CUR != ',') {
8005 XP_ERROR(XPATH_EXPR_ERROR);
8006 }
8007 NEXT;
8008 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008009 }
Owen Taylor3473f882001-02-23 17:55:21 +00008010 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008011 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
8012 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00008013 NEXT;
8014 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00008015}
8016
8017/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008018 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008019 * @ctxt: the XPath Parser context
8020 *
8021 * [15] PrimaryExpr ::= VariableReference
8022 * | '(' Expr ')'
8023 * | Literal
8024 * | Number
8025 * | FunctionCall
8026 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008027 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008028 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008029static void
8030xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008031 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008032 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008033 else if (CUR == '(') {
8034 NEXT;
8035 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008036 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00008037 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00008038 if (CUR != ')') {
8039 XP_ERROR(XPATH_EXPR_ERROR);
8040 }
8041 NEXT;
8042 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008043 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008044 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008045 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008046 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008047 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008048 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008049 }
8050 SKIP_BLANKS;
8051}
8052
8053/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008054 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008055 * @ctxt: the XPath Parser context
8056 *
8057 * [20] FilterExpr ::= PrimaryExpr
8058 * | FilterExpr Predicate
8059 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008060 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008061 * Square brackets are used to filter expressions in the same way that
8062 * they are used in location paths. It is an error if the expression to
8063 * be filtered does not evaluate to a node-set. The context node list
8064 * used for evaluating the expression in square brackets is the node-set
8065 * to be filtered listed in document order.
8066 */
8067
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008068static void
8069xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8070 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008071 CHECK_ERROR;
8072 SKIP_BLANKS;
8073
8074 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008075 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00008076 SKIP_BLANKS;
8077 }
8078
8079
8080}
8081
8082/**
8083 * xmlXPathScanName:
8084 * @ctxt: the XPath Parser context
8085 *
8086 * Trickery: parse an XML name but without consuming the input flow
8087 * Needed to avoid insanity in the parser state.
8088 *
8089 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8090 * CombiningChar | Extender
8091 *
8092 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8093 *
8094 * [6] Names ::= Name (S Name)*
8095 *
8096 * Returns the Name parsed or NULL
8097 */
8098
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008099static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008100xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard03226812004-11-01 14:55:21 +00008101 int len = 0, l;
8102 int c;
Daniel Veillard03226812004-11-01 14:55:21 +00008103 const xmlChar *cur;
8104 xmlChar *ret;
Owen Taylor3473f882001-02-23 17:55:21 +00008105
Daniel Veillard03226812004-11-01 14:55:21 +00008106 cur = ctxt->cur;
8107
8108 c = CUR_CHAR(l);
8109 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8110 (!IS_LETTER(c) && (c != '_') &&
8111 (c != ':'))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008112 return(NULL);
8113 }
8114
Daniel Veillard03226812004-11-01 14:55:21 +00008115 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8116 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8117 (c == '.') || (c == '-') ||
8118 (c == '_') || (c == ':') ||
8119 (IS_COMBINING(c)) ||
8120 (IS_EXTENDER(c)))) {
8121 len += l;
8122 NEXTL(l);
8123 c = CUR_CHAR(l);
Owen Taylor3473f882001-02-23 17:55:21 +00008124 }
Daniel Veillard03226812004-11-01 14:55:21 +00008125 ret = xmlStrndup(cur, ctxt->cur - cur);
8126 ctxt->cur = cur;
8127 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00008128}
8129
8130/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008131 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008132 * @ctxt: the XPath Parser context
8133 *
8134 * [19] PathExpr ::= LocationPath
8135 * | FilterExpr
8136 * | FilterExpr '/' RelativeLocationPath
8137 * | FilterExpr '//' RelativeLocationPath
8138 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008139 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008140 * The / operator and // operators combine an arbitrary expression
8141 * and a relative location path. It is an error if the expression
8142 * does not evaluate to a node-set.
8143 * The / operator does composition in the same way as when / is
8144 * used in a location path. As in location paths, // is short for
8145 * /descendant-or-self::node()/.
8146 */
8147
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008148static void
8149xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008150 int lc = 1; /* Should we branch to LocationPath ? */
8151 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8152
8153 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008154 if ((CUR == '$') || (CUR == '(') ||
8155 (IS_ASCII_DIGIT(CUR)) ||
8156 (CUR == '\'') || (CUR == '"') ||
8157 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008158 lc = 0;
8159 } else if (CUR == '*') {
8160 /* relative or absolute location path */
8161 lc = 1;
8162 } else if (CUR == '/') {
8163 /* relative or absolute location path */
8164 lc = 1;
8165 } else if (CUR == '@') {
8166 /* relative abbreviated attribute location path */
8167 lc = 1;
8168 } else if (CUR == '.') {
8169 /* relative abbreviated attribute location path */
8170 lc = 1;
8171 } else {
8172 /*
8173 * Problem is finding if we have a name here whether it's:
8174 * - a nodetype
8175 * - a function call in which case it's followed by '('
8176 * - an axis in which case it's followed by ':'
8177 * - a element name
8178 * We do an a priori analysis here rather than having to
8179 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008180 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008181 * read/write/debug.
8182 */
8183 SKIP_BLANKS;
8184 name = xmlXPathScanName(ctxt);
8185 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8186#ifdef DEBUG_STEP
8187 xmlGenericError(xmlGenericErrorContext,
8188 "PathExpr: Axis\n");
8189#endif
8190 lc = 1;
8191 xmlFree(name);
8192 } else if (name != NULL) {
8193 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008194
8195
8196 while (NXT(len) != 0) {
8197 if (NXT(len) == '/') {
8198 /* element name */
8199#ifdef DEBUG_STEP
8200 xmlGenericError(xmlGenericErrorContext,
8201 "PathExpr: AbbrRelLocation\n");
8202#endif
8203 lc = 1;
8204 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008205 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008206 /* ignore blanks */
8207 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008208 } else if (NXT(len) == ':') {
8209#ifdef DEBUG_STEP
8210 xmlGenericError(xmlGenericErrorContext,
8211 "PathExpr: AbbrRelLocation\n");
8212#endif
8213 lc = 1;
8214 break;
8215 } else if ((NXT(len) == '(')) {
8216 /* Note Type or Function */
8217 if (xmlXPathIsNodeType(name)) {
8218#ifdef DEBUG_STEP
8219 xmlGenericError(xmlGenericErrorContext,
8220 "PathExpr: Type search\n");
8221#endif
8222 lc = 1;
8223 } else {
8224#ifdef DEBUG_STEP
8225 xmlGenericError(xmlGenericErrorContext,
8226 "PathExpr: function call\n");
8227#endif
8228 lc = 0;
8229 }
8230 break;
8231 } else if ((NXT(len) == '[')) {
8232 /* element name */
8233#ifdef DEBUG_STEP
8234 xmlGenericError(xmlGenericErrorContext,
8235 "PathExpr: AbbrRelLocation\n");
8236#endif
8237 lc = 1;
8238 break;
8239 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8240 (NXT(len) == '=')) {
8241 lc = 1;
8242 break;
8243 } else {
8244 lc = 1;
8245 break;
8246 }
8247 len++;
8248 }
8249 if (NXT(len) == 0) {
8250#ifdef DEBUG_STEP
8251 xmlGenericError(xmlGenericErrorContext,
8252 "PathExpr: AbbrRelLocation\n");
8253#endif
8254 /* element name */
8255 lc = 1;
8256 }
8257 xmlFree(name);
8258 } else {
William M. Brack08171912003-12-29 02:52:11 +00008259 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008260 XP_ERROR(XPATH_EXPR_ERROR);
8261 }
8262 }
8263
8264 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008265 if (CUR == '/') {
8266 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8267 } else {
8268 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008269 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008270 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008271 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008272 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008273 CHECK_ERROR;
8274 if ((CUR == '/') && (NXT(1) == '/')) {
8275 SKIP(2);
8276 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008277
8278 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8279 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8280 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8281
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008282 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008283 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008284 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008285 }
8286 }
8287 SKIP_BLANKS;
8288}
8289
8290/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008291 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008292 * @ctxt: the XPath Parser context
8293 *
8294 * [18] UnionExpr ::= PathExpr
8295 * | UnionExpr '|' PathExpr
8296 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008297 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008298 */
8299
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008300static void
8301xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8302 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008303 CHECK_ERROR;
8304 SKIP_BLANKS;
8305 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008306 int op1 = ctxt->comp->last;
8307 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008308
8309 NEXT;
8310 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008311 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008312
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008313 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8314
Owen Taylor3473f882001-02-23 17:55:21 +00008315 SKIP_BLANKS;
8316 }
Owen Taylor3473f882001-02-23 17:55:21 +00008317}
8318
8319/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008320 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008321 * @ctxt: the XPath Parser context
8322 *
8323 * [27] UnaryExpr ::= UnionExpr
8324 * | '-' UnaryExpr
8325 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008326 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008327 */
8328
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008329static void
8330xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008331 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008332 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008333
8334 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008335 while (CUR == '-') {
8336 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008337 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008338 NEXT;
8339 SKIP_BLANKS;
8340 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008341
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008342 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008343 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008344 if (found) {
8345 if (minus)
8346 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8347 else
8348 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008349 }
8350}
8351
8352/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008353 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008354 * @ctxt: the XPath Parser context
8355 *
8356 * [26] MultiplicativeExpr ::= UnaryExpr
8357 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8358 * | MultiplicativeExpr 'div' UnaryExpr
8359 * | MultiplicativeExpr 'mod' UnaryExpr
8360 * [34] MultiplyOperator ::= '*'
8361 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008362 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008363 */
8364
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008365static void
8366xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8367 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008368 CHECK_ERROR;
8369 SKIP_BLANKS;
8370 while ((CUR == '*') ||
8371 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8372 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8373 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008374 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008375
8376 if (CUR == '*') {
8377 op = 0;
8378 NEXT;
8379 } else if (CUR == 'd') {
8380 op = 1;
8381 SKIP(3);
8382 } else if (CUR == 'm') {
8383 op = 2;
8384 SKIP(3);
8385 }
8386 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008387 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008388 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008389 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008390 SKIP_BLANKS;
8391 }
8392}
8393
8394/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008395 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008396 * @ctxt: the XPath Parser context
8397 *
8398 * [25] AdditiveExpr ::= MultiplicativeExpr
8399 * | AdditiveExpr '+' MultiplicativeExpr
8400 * | AdditiveExpr '-' MultiplicativeExpr
8401 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008402 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008403 */
8404
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008405static void
8406xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008407
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008408 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008409 CHECK_ERROR;
8410 SKIP_BLANKS;
8411 while ((CUR == '+') || (CUR == '-')) {
8412 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008413 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008414
8415 if (CUR == '+') plus = 1;
8416 else plus = 0;
8417 NEXT;
8418 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008419 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008420 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008421 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008422 SKIP_BLANKS;
8423 }
8424}
8425
8426/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008427 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008428 * @ctxt: the XPath Parser context
8429 *
8430 * [24] RelationalExpr ::= AdditiveExpr
8431 * | RelationalExpr '<' AdditiveExpr
8432 * | RelationalExpr '>' AdditiveExpr
8433 * | RelationalExpr '<=' AdditiveExpr
8434 * | RelationalExpr '>=' AdditiveExpr
8435 *
8436 * A <= B > C is allowed ? Answer from James, yes with
8437 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8438 * which is basically what got implemented.
8439 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008440 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008441 * on the stack
8442 */
8443
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008444static void
8445xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8446 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008447 CHECK_ERROR;
8448 SKIP_BLANKS;
8449 while ((CUR == '<') ||
8450 (CUR == '>') ||
8451 ((CUR == '<') && (NXT(1) == '=')) ||
8452 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008453 int inf, strict;
8454 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008455
8456 if (CUR == '<') inf = 1;
8457 else inf = 0;
8458 if (NXT(1) == '=') strict = 0;
8459 else strict = 1;
8460 NEXT;
8461 if (!strict) NEXT;
8462 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008463 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008464 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008465 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008466 SKIP_BLANKS;
8467 }
8468}
8469
8470/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008471 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008472 * @ctxt: the XPath Parser context
8473 *
8474 * [23] EqualityExpr ::= RelationalExpr
8475 * | EqualityExpr '=' RelationalExpr
8476 * | EqualityExpr '!=' RelationalExpr
8477 *
8478 * A != B != C is allowed ? Answer from James, yes with
8479 * (RelationalExpr = RelationalExpr) = RelationalExpr
8480 * (RelationalExpr != RelationalExpr) != RelationalExpr
8481 * which is basically what got implemented.
8482 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008483 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008484 *
8485 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008486static void
8487xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8488 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008489 CHECK_ERROR;
8490 SKIP_BLANKS;
8491 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008492 int eq;
8493 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008494
8495 if (CUR == '=') eq = 1;
8496 else eq = 0;
8497 NEXT;
8498 if (!eq) NEXT;
8499 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008500 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008501 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008502 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008503 SKIP_BLANKS;
8504 }
8505}
8506
8507/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008508 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008509 * @ctxt: the XPath Parser context
8510 *
8511 * [22] AndExpr ::= EqualityExpr
8512 * | AndExpr 'and' EqualityExpr
8513 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008514 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008515 *
8516 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008517static void
8518xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8519 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008520 CHECK_ERROR;
8521 SKIP_BLANKS;
8522 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008523 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008524 SKIP(3);
8525 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008526 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008527 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008528 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008529 SKIP_BLANKS;
8530 }
8531}
8532
8533/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008534 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008535 * @ctxt: the XPath Parser context
8536 *
8537 * [14] Expr ::= OrExpr
8538 * [21] OrExpr ::= AndExpr
8539 * | OrExpr 'or' AndExpr
8540 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008541 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008542 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008543static void
8544xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8545 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008546 CHECK_ERROR;
8547 SKIP_BLANKS;
8548 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008549 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008550 SKIP(2);
8551 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008552 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008553 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008554 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8555 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008556 SKIP_BLANKS;
8557 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008558 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8559 /* more ops could be optimized too */
8560 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8561 }
Owen Taylor3473f882001-02-23 17:55:21 +00008562}
8563
8564/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008565 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008566 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008567 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008568 *
8569 * [8] Predicate ::= '[' PredicateExpr ']'
8570 * [9] PredicateExpr ::= Expr
8571 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008572 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008573 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008574static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008575xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008576 int op1 = ctxt->comp->last;
8577
8578 SKIP_BLANKS;
8579 if (CUR != '[') {
8580 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8581 }
8582 NEXT;
8583 SKIP_BLANKS;
8584
8585 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008586 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008587 CHECK_ERROR;
8588
8589 if (CUR != ']') {
8590 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8591 }
8592
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008593 if (filter)
8594 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8595 else
8596 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008597
8598 NEXT;
8599 SKIP_BLANKS;
8600}
8601
8602/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008603 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008604 * @ctxt: the XPath Parser context
8605 * @test: pointer to a xmlXPathTestVal
8606 * @type: pointer to a xmlXPathTypeVal
8607 * @prefix: placeholder for a possible name prefix
8608 *
8609 * [7] NodeTest ::= NameTest
8610 * | NodeType '(' ')'
8611 * | 'processing-instruction' '(' Literal ')'
8612 *
8613 * [37] NameTest ::= '*'
8614 * | NCName ':' '*'
8615 * | QName
8616 * [38] NodeType ::= 'comment'
8617 * | 'text'
8618 * | 'processing-instruction'
8619 * | 'node'
8620 *
William M. Brack08171912003-12-29 02:52:11 +00008621 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008622 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008623static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008624xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8625 xmlXPathTypeVal *type, const xmlChar **prefix,
8626 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008627 int blanks;
8628
8629 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8630 STRANGE;
8631 return(NULL);
8632 }
William M. Brack78637da2003-07-31 14:47:38 +00008633 *type = (xmlXPathTypeVal) 0;
8634 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008635 *prefix = NULL;
8636 SKIP_BLANKS;
8637
8638 if ((name == NULL) && (CUR == '*')) {
8639 /*
8640 * All elements
8641 */
8642 NEXT;
8643 *test = NODE_TEST_ALL;
8644 return(NULL);
8645 }
8646
8647 if (name == NULL)
8648 name = xmlXPathParseNCName(ctxt);
8649 if (name == NULL) {
8650 XP_ERROR0(XPATH_EXPR_ERROR);
8651 }
8652
William M. Brack76e95df2003-10-18 16:20:14 +00008653 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008654 SKIP_BLANKS;
8655 if (CUR == '(') {
8656 NEXT;
8657 /*
8658 * NodeType or PI search
8659 */
8660 if (xmlStrEqual(name, BAD_CAST "comment"))
8661 *type = NODE_TYPE_COMMENT;
8662 else if (xmlStrEqual(name, BAD_CAST "node"))
8663 *type = NODE_TYPE_NODE;
8664 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8665 *type = NODE_TYPE_PI;
8666 else if (xmlStrEqual(name, BAD_CAST "text"))
8667 *type = NODE_TYPE_TEXT;
8668 else {
8669 if (name != NULL)
8670 xmlFree(name);
8671 XP_ERROR0(XPATH_EXPR_ERROR);
8672 }
8673
8674 *test = NODE_TEST_TYPE;
8675
8676 SKIP_BLANKS;
8677 if (*type == NODE_TYPE_PI) {
8678 /*
8679 * Specific case: search a PI by name.
8680 */
Owen Taylor3473f882001-02-23 17:55:21 +00008681 if (name != NULL)
8682 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008683 name = NULL;
8684 if (CUR != ')') {
8685 name = xmlXPathParseLiteral(ctxt);
8686 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008687 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008688 SKIP_BLANKS;
8689 }
Owen Taylor3473f882001-02-23 17:55:21 +00008690 }
8691 if (CUR != ')') {
8692 if (name != NULL)
8693 xmlFree(name);
8694 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8695 }
8696 NEXT;
8697 return(name);
8698 }
8699 *test = NODE_TEST_NAME;
8700 if ((!blanks) && (CUR == ':')) {
8701 NEXT;
8702
8703 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008704 * Since currently the parser context don't have a
8705 * namespace list associated:
8706 * The namespace name for this prefix can be computed
8707 * only at evaluation time. The compilation is done
8708 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008709 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008710#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008711 *prefix = xmlXPathNsLookup(ctxt->context, name);
8712 if (name != NULL)
8713 xmlFree(name);
8714 if (*prefix == NULL) {
8715 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8716 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008717#else
8718 *prefix = name;
8719#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008720
8721 if (CUR == '*') {
8722 /*
8723 * All elements
8724 */
8725 NEXT;
8726 *test = NODE_TEST_ALL;
8727 return(NULL);
8728 }
8729
8730 name = xmlXPathParseNCName(ctxt);
8731 if (name == NULL) {
8732 XP_ERROR0(XPATH_EXPR_ERROR);
8733 }
8734 }
8735 return(name);
8736}
8737
8738/**
8739 * xmlXPathIsAxisName:
8740 * @name: a preparsed name token
8741 *
8742 * [6] AxisName ::= 'ancestor'
8743 * | 'ancestor-or-self'
8744 * | 'attribute'
8745 * | 'child'
8746 * | 'descendant'
8747 * | 'descendant-or-self'
8748 * | 'following'
8749 * | 'following-sibling'
8750 * | 'namespace'
8751 * | 'parent'
8752 * | 'preceding'
8753 * | 'preceding-sibling'
8754 * | 'self'
8755 *
8756 * Returns the axis or 0
8757 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008758static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008759xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008760 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008761 switch (name[0]) {
8762 case 'a':
8763 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8764 ret = AXIS_ANCESTOR;
8765 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8766 ret = AXIS_ANCESTOR_OR_SELF;
8767 if (xmlStrEqual(name, BAD_CAST "attribute"))
8768 ret = AXIS_ATTRIBUTE;
8769 break;
8770 case 'c':
8771 if (xmlStrEqual(name, BAD_CAST "child"))
8772 ret = AXIS_CHILD;
8773 break;
8774 case 'd':
8775 if (xmlStrEqual(name, BAD_CAST "descendant"))
8776 ret = AXIS_DESCENDANT;
8777 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8778 ret = AXIS_DESCENDANT_OR_SELF;
8779 break;
8780 case 'f':
8781 if (xmlStrEqual(name, BAD_CAST "following"))
8782 ret = AXIS_FOLLOWING;
8783 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8784 ret = AXIS_FOLLOWING_SIBLING;
8785 break;
8786 case 'n':
8787 if (xmlStrEqual(name, BAD_CAST "namespace"))
8788 ret = AXIS_NAMESPACE;
8789 break;
8790 case 'p':
8791 if (xmlStrEqual(name, BAD_CAST "parent"))
8792 ret = AXIS_PARENT;
8793 if (xmlStrEqual(name, BAD_CAST "preceding"))
8794 ret = AXIS_PRECEDING;
8795 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8796 ret = AXIS_PRECEDING_SIBLING;
8797 break;
8798 case 's':
8799 if (xmlStrEqual(name, BAD_CAST "self"))
8800 ret = AXIS_SELF;
8801 break;
8802 }
8803 return(ret);
8804}
8805
8806/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008807 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008808 * @ctxt: the XPath Parser context
8809 *
8810 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8811 * | AbbreviatedStep
8812 *
8813 * [12] AbbreviatedStep ::= '.' | '..'
8814 *
8815 * [5] AxisSpecifier ::= AxisName '::'
8816 * | AbbreviatedAxisSpecifier
8817 *
8818 * [13] AbbreviatedAxisSpecifier ::= '@'?
8819 *
8820 * Modified for XPtr range support as:
8821 *
8822 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8823 * | AbbreviatedStep
8824 * | 'range-to' '(' Expr ')' Predicate*
8825 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008826 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008827 * A location step of . is short for self::node(). This is
8828 * particularly useful in conjunction with //. For example, the
8829 * location path .//para is short for
8830 * self::node()/descendant-or-self::node()/child::para
8831 * and so will select all para descendant elements of the context
8832 * node.
8833 * Similarly, a location step of .. is short for parent::node().
8834 * For example, ../title is short for parent::node()/child::title
8835 * and so will select the title children of the parent of the context
8836 * node.
8837 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008838static void
8839xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008840#ifdef LIBXML_XPTR_ENABLED
8841 int rangeto = 0;
8842 int op2 = -1;
8843#endif
8844
Owen Taylor3473f882001-02-23 17:55:21 +00008845 SKIP_BLANKS;
8846 if ((CUR == '.') && (NXT(1) == '.')) {
8847 SKIP(2);
8848 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008849 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8850 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008851 } else if (CUR == '.') {
8852 NEXT;
8853 SKIP_BLANKS;
8854 } else {
8855 xmlChar *name = NULL;
8856 const xmlChar *prefix = NULL;
8857 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008858 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008859 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008860 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008861
8862 /*
8863 * The modification needed for XPointer change to the production
8864 */
8865#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008866 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008867 name = xmlXPathParseNCName(ctxt);
8868 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008869 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008870 xmlFree(name);
8871 SKIP_BLANKS;
8872 if (CUR != '(') {
8873 XP_ERROR(XPATH_EXPR_ERROR);
8874 }
8875 NEXT;
8876 SKIP_BLANKS;
8877
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008878 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008879 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008880 CHECK_ERROR;
8881
8882 SKIP_BLANKS;
8883 if (CUR != ')') {
8884 XP_ERROR(XPATH_EXPR_ERROR);
8885 }
8886 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008887 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008888 goto eval_predicates;
8889 }
8890 }
8891#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008892 if (CUR == '*') {
8893 axis = AXIS_CHILD;
8894 } else {
8895 if (name == NULL)
8896 name = xmlXPathParseNCName(ctxt);
8897 if (name != NULL) {
8898 axis = xmlXPathIsAxisName(name);
8899 if (axis != 0) {
8900 SKIP_BLANKS;
8901 if ((CUR == ':') && (NXT(1) == ':')) {
8902 SKIP(2);
8903 xmlFree(name);
8904 name = NULL;
8905 } else {
8906 /* an element name can conflict with an axis one :-\ */
8907 axis = AXIS_CHILD;
8908 }
Owen Taylor3473f882001-02-23 17:55:21 +00008909 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008910 axis = AXIS_CHILD;
8911 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008912 } else if (CUR == '@') {
8913 NEXT;
8914 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008915 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008916 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008917 }
Owen Taylor3473f882001-02-23 17:55:21 +00008918 }
8919
8920 CHECK_ERROR;
8921
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008922 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008923 if (test == 0)
8924 return;
8925
8926#ifdef DEBUG_STEP
8927 xmlGenericError(xmlGenericErrorContext,
8928 "Basis : computing new set\n");
8929#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008930
Owen Taylor3473f882001-02-23 17:55:21 +00008931#ifdef DEBUG_STEP
8932 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008933 if (ctxt->value == NULL)
8934 xmlGenericError(xmlGenericErrorContext, "no value\n");
8935 else if (ctxt->value->nodesetval == NULL)
8936 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8937 else
8938 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008939#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008940
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008941#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008942eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008943#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008944 op1 = ctxt->comp->last;
8945 ctxt->comp->last = -1;
8946
Owen Taylor3473f882001-02-23 17:55:21 +00008947 SKIP_BLANKS;
8948 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008949 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008950 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008951
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008952#ifdef LIBXML_XPTR_ENABLED
8953 if (rangeto) {
8954 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8955 } else
8956#endif
8957 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8958 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008959
Owen Taylor3473f882001-02-23 17:55:21 +00008960 }
8961#ifdef DEBUG_STEP
8962 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008963 if (ctxt->value == NULL)
8964 xmlGenericError(xmlGenericErrorContext, "no value\n");
8965 else if (ctxt->value->nodesetval == NULL)
8966 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8967 else
8968 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8969 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008970#endif
8971}
8972
8973/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008974 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008975 * @ctxt: the XPath Parser context
8976 *
8977 * [3] RelativeLocationPath ::= Step
8978 * | RelativeLocationPath '/' Step
8979 * | AbbreviatedRelativeLocationPath
8980 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8981 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008982 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008983 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008984static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008985xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008986(xmlXPathParserContextPtr ctxt) {
8987 SKIP_BLANKS;
8988 if ((CUR == '/') && (NXT(1) == '/')) {
8989 SKIP(2);
8990 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008991 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8992 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008993 } else if (CUR == '/') {
8994 NEXT;
8995 SKIP_BLANKS;
8996 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008997 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008998 SKIP_BLANKS;
8999 while (CUR == '/') {
9000 if ((CUR == '/') && (NXT(1) == '/')) {
9001 SKIP(2);
9002 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009003 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00009004 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009005 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009006 } else if (CUR == '/') {
9007 NEXT;
9008 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009009 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009010 }
9011 SKIP_BLANKS;
9012 }
9013}
9014
9015/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009016 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00009017 * @ctxt: the XPath Parser context
9018 *
9019 * [1] LocationPath ::= RelativeLocationPath
9020 * | AbsoluteLocationPath
9021 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
9022 * | AbbreviatedAbsoluteLocationPath
9023 * [10] AbbreviatedAbsoluteLocationPath ::=
9024 * '//' RelativeLocationPath
9025 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009026 * Compile a location path
9027 *
Owen Taylor3473f882001-02-23 17:55:21 +00009028 * // is short for /descendant-or-self::node()/. For example,
9029 * //para is short for /descendant-or-self::node()/child::para and
9030 * so will select any para element in the document (even a para element
9031 * that is a document element will be selected by //para since the
9032 * document element node is a child of the root node); div//para is
9033 * short for div/descendant-or-self::node()/child::para and so will
9034 * select all para descendants of div children.
9035 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009036static void
9037xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00009038 SKIP_BLANKS;
9039 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009040 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009041 } else {
9042 while (CUR == '/') {
9043 if ((CUR == '/') && (NXT(1) == '/')) {
9044 SKIP(2);
9045 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009046 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9047 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009048 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009049 } else if (CUR == '/') {
9050 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00009051 SKIP_BLANKS;
9052 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00009053 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00009054 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00009055 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00009056 }
9057 }
9058 }
9059}
9060
Daniel Veillard9e7160d2001-03-18 23:17:47 +00009061/************************************************************************
9062 * *
9063 * XPath precompiled expression evaluation *
9064 * *
9065 ************************************************************************/
9066
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009068xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9069
9070/**
9071 * xmlXPathNodeCollectAndTest:
9072 * @ctxt: the XPath Parser context
9073 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 * @first: pointer to the first element in document order
9075 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009076 *
9077 * This is the function implementing a step: based on the current list
9078 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009079 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009080 *
9081 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00009082 *
William M. Brack08171912003-12-29 02:52:11 +00009083 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009085static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009087 xmlXPathStepOpPtr op,
9088 xmlNodePtr * first, xmlNodePtr * last)
9089{
William M. Brack78637da2003-07-31 14:47:38 +00009090 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9091 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9092 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093 const xmlChar *prefix = op->value4;
9094 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009095 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009096
9097#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009099#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009101 xmlNodeSetPtr ret, list;
9102 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009104 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009105 xmlNodePtr cur = NULL;
9106 xmlXPathObjectPtr obj;
9107 xmlNodeSetPtr nodelist;
9108 xmlNodePtr tmp;
9109
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111 obj = valuePop(ctxt);
9112 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009113 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009114 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009115 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009116 if (URI == NULL) {
9117 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009118 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009119 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00009120 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009121#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009122 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009123#endif
9124 switch (axis) {
9125 case AXIS_ANCESTOR:
9126#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009128#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 first = NULL;
9130 next = xmlXPathNextAncestor;
9131 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132 case AXIS_ANCESTOR_OR_SELF:
9133#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 xmlGenericError(xmlGenericErrorContext,
9135 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009136#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009137 first = NULL;
9138 next = xmlXPathNextAncestorOrSelf;
9139 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009140 case AXIS_ATTRIBUTE:
9141#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009142 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009143#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009144 first = NULL;
9145 last = NULL;
9146 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009147 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009149 case AXIS_CHILD:
9150#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009151 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009152#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009153 last = NULL;
9154 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009155 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009156 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009157 case AXIS_DESCENDANT:
9158#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009159 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009160#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009161 last = NULL;
9162 next = xmlXPathNextDescendant;
9163 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009164 case AXIS_DESCENDANT_OR_SELF:
9165#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009166 xmlGenericError(xmlGenericErrorContext,
9167 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009168#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009169 last = NULL;
9170 next = xmlXPathNextDescendantOrSelf;
9171 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009172 case AXIS_FOLLOWING:
9173#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009174 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009175#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009176 last = NULL;
9177 next = xmlXPathNextFollowing;
9178 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009179 case AXIS_FOLLOWING_SIBLING:
9180#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009181 xmlGenericError(xmlGenericErrorContext,
9182 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009183#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009184 last = NULL;
9185 next = xmlXPathNextFollowingSibling;
9186 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009187 case AXIS_NAMESPACE:
9188#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009189 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009190#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009191 first = NULL;
9192 last = NULL;
9193 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009194 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009195 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009196 case AXIS_PARENT:
9197#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009198 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009199#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009200 first = NULL;
9201 next = xmlXPathNextParent;
9202 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009203 case AXIS_PRECEDING:
9204#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009205 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009206#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009207 first = NULL;
9208 next = xmlXPathNextPrecedingInternal;
9209 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009210 case AXIS_PRECEDING_SIBLING:
9211#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009212 xmlGenericError(xmlGenericErrorContext,
9213 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009214#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 first = NULL;
9216 next = xmlXPathNextPrecedingSibling;
9217 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009218 case AXIS_SELF:
9219#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009221#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009222 first = NULL;
9223 last = NULL;
9224 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009225 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009227 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009228 if (next == NULL) {
9229 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009230 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009231 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009232
9233 nodelist = obj->nodesetval;
9234 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009235 xmlXPathFreeObject(obj);
9236 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9237 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009238 }
9239 addNode = xmlXPathNodeSetAddUnique;
9240 ret = NULL;
9241#ifdef DEBUG_STEP
9242 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009243 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009244 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009245 case NODE_TEST_NONE:
9246 xmlGenericError(xmlGenericErrorContext,
9247 " searching for none !!!\n");
9248 break;
9249 case NODE_TEST_TYPE:
9250 xmlGenericError(xmlGenericErrorContext,
9251 " searching for type %d\n", type);
9252 break;
9253 case NODE_TEST_PI:
9254 xmlGenericError(xmlGenericErrorContext,
9255 " searching for PI !!!\n");
9256 break;
9257 case NODE_TEST_ALL:
9258 xmlGenericError(xmlGenericErrorContext,
9259 " searching for *\n");
9260 break;
9261 case NODE_TEST_NS:
9262 xmlGenericError(xmlGenericErrorContext,
9263 " searching for namespace %s\n",
9264 prefix);
9265 break;
9266 case NODE_TEST_NAME:
9267 xmlGenericError(xmlGenericErrorContext,
9268 " searching for name %s\n", name);
9269 if (prefix != NULL)
9270 xmlGenericError(xmlGenericErrorContext,
9271 " with namespace %s\n", prefix);
9272 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009273 }
9274 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9275#endif
9276 /*
9277 * 2.3 Node Tests
9278 * - For the attribute axis, the principal node type is attribute.
9279 * - For the namespace axis, the principal node type is namespace.
9280 * - For other axes, the principal node type is element.
9281 *
9282 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009283 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009284 * select all element children of the context node
9285 */
9286 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009287 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009288 ctxt->context->node = nodelist->nodeTab[i];
9289
Daniel Veillardf06307e2001-07-03 10:35:50 +00009290 cur = NULL;
9291 list = xmlXPathNodeSetCreate(NULL);
9292 do {
9293 cur = next(ctxt, cur);
9294 if (cur == NULL)
9295 break;
9296 if ((first != NULL) && (*first == cur))
9297 break;
9298 if (((t % 256) == 0) &&
9299 (first != NULL) && (*first != NULL) &&
9300 (xmlXPathCmpNodes(*first, cur) >= 0))
9301 break;
9302 if ((last != NULL) && (*last == cur))
9303 break;
9304 if (((t % 256) == 0) &&
9305 (last != NULL) && (*last != NULL) &&
9306 (xmlXPathCmpNodes(cur, *last) >= 0))
9307 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009308 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009309#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009310 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9311#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009313 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 ctxt->context->node = tmp;
William M. Brack2c19a7b2005-04-10 01:03:23 +00009315 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009316 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009317 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009318 if ((cur->type == type) ||
9319 ((type == NODE_TYPE_NODE) &&
9320 ((cur->type == XML_DOCUMENT_NODE) ||
9321 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9322 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009323 (cur->type == XML_NAMESPACE_DECL) ||
9324 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009325 (cur->type == XML_PI_NODE) ||
9326 (cur->type == XML_COMMENT_NODE) ||
9327 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009328 (cur->type == XML_TEXT_NODE))) ||
9329 ((type == NODE_TYPE_TEXT) &&
9330 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009331#ifdef DEBUG_STEP
9332 n++;
9333#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009334 addNode(list, cur);
9335 }
9336 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009337 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009338 if (cur->type == XML_PI_NODE) {
9339 if ((name != NULL) &&
9340 (!xmlStrEqual(name, cur->name)))
9341 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009342#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009343 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009344#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009345 addNode(list, cur);
9346 }
9347 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009348 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009349 if (axis == AXIS_ATTRIBUTE) {
9350 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009351#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009352 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009353#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009354 addNode(list, cur);
9355 }
9356 } else if (axis == AXIS_NAMESPACE) {
9357 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009358#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009359 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009360#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009361 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9362 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009363 }
9364 } else {
9365 if (cur->type == XML_ELEMENT_NODE) {
9366 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009367#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009368 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009369#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009370 addNode(list, cur);
9371 } else if ((cur->ns != NULL) &&
9372 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009373#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009374 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009375#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009376 addNode(list, cur);
9377 }
9378 }
9379 }
9380 break;
9381 case NODE_TEST_NS:{
9382 TODO;
9383 break;
9384 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009385 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009386 switch (cur->type) {
9387 case XML_ELEMENT_NODE:
9388 if (xmlStrEqual(name, cur->name)) {
9389 if (prefix == NULL) {
9390 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009391#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009392 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009393#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009394 addNode(list, cur);
9395 }
9396 } else {
9397 if ((cur->ns != NULL) &&
9398 (xmlStrEqual(URI,
9399 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009400#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009401 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009402#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009403 addNode(list, cur);
9404 }
9405 }
9406 }
9407 break;
9408 case XML_ATTRIBUTE_NODE:{
9409 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009410
Daniel Veillardf06307e2001-07-03 10:35:50 +00009411 if (xmlStrEqual(name, attr->name)) {
9412 if (prefix == NULL) {
9413 if ((attr->ns == NULL) ||
9414 (attr->ns->prefix == NULL)) {
9415#ifdef DEBUG_STEP
9416 n++;
9417#endif
9418 addNode(list,
9419 (xmlNodePtr) attr);
9420 }
9421 } else {
9422 if ((attr->ns != NULL) &&
9423 (xmlStrEqual(URI,
9424 attr->ns->
9425 href))) {
9426#ifdef DEBUG_STEP
9427 n++;
9428#endif
9429 addNode(list,
9430 (xmlNodePtr) attr);
9431 }
9432 }
9433 }
9434 break;
9435 }
9436 case XML_NAMESPACE_DECL:
9437 if (cur->type == XML_NAMESPACE_DECL) {
9438 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009439
Daniel Veillardf06307e2001-07-03 10:35:50 +00009440 if ((ns->prefix != NULL) && (name != NULL)
9441 && (xmlStrEqual(ns->prefix, name))) {
9442#ifdef DEBUG_STEP
9443 n++;
9444#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009445 xmlXPathNodeSetAddNs(list,
9446 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009447 }
9448 }
9449 break;
9450 default:
9451 break;
9452 }
9453 break;
9454 break;
9455 }
9456 } while (cur != NULL);
9457
9458 /*
9459 * If there is some predicate filtering do it now
9460 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009461 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009462 xmlXPathObjectPtr obj2;
9463
9464 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9465 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9466 CHECK_TYPE0(XPATH_NODESET);
9467 obj2 = valuePop(ctxt);
9468 list = obj2->nodesetval;
9469 obj2->nodesetval = NULL;
9470 xmlXPathFreeObject(obj2);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009471 if (ctxt->error != XPATH_EXPRESSION_OK) {
9472 xmlXPathFreeObject(obj);
9473 xmlXPathFreeNodeSet(list);
9474 return(0);
9475 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009476 }
9477 if (ret == NULL) {
9478 ret = list;
9479 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009480 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009481 xmlXPathFreeNodeSet(list);
9482 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009483 }
9484 ctxt->context->node = tmp;
9485#ifdef DEBUG_STEP
9486 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009487 "\nExamined %d nodes, found %d nodes at that step\n",
9488 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009489#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009490 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009491 if ((obj->boolval) && (obj->user != NULL)) {
9492 ctxt->value->boolval = 1;
9493 ctxt->value->user = obj->user;
9494 obj->user = NULL;
9495 obj->boolval = 0;
9496 }
9497 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009498 return(t);
9499}
9500
9501/**
9502 * xmlXPathNodeCollectAndTestNth:
9503 * @ctxt: the XPath Parser context
9504 * @op: the XPath precompiled step operation
9505 * @indx: the index to collect
9506 * @first: pointer to the first element in document order
9507 * @last: pointer to the last element in document order
9508 *
9509 * This is the function implementing a step: based on the current list
9510 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009511 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009512 *
9513 * Pushes the new NodeSet resulting from the search.
9514 * Returns the number of node traversed
9515 */
9516static int
9517xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9518 xmlXPathStepOpPtr op, int indx,
9519 xmlNodePtr * first, xmlNodePtr * last)
9520{
William M. Brack78637da2003-07-31 14:47:38 +00009521 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9522 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9523 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009524 const xmlChar *prefix = op->value4;
9525 const xmlChar *name = op->value5;
9526 const xmlChar *URI = NULL;
9527 int n = 0, t = 0;
9528
9529 int i;
9530 xmlNodeSetPtr list;
9531 xmlXPathTraversalFunction next = NULL;
9532 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9533 xmlNodePtr cur = NULL;
9534 xmlXPathObjectPtr obj;
9535 xmlNodeSetPtr nodelist;
9536 xmlNodePtr tmp;
9537
9538 CHECK_TYPE0(XPATH_NODESET);
9539 obj = valuePop(ctxt);
9540 addNode = xmlXPathNodeSetAdd;
9541 if (prefix != NULL) {
9542 URI = xmlXPathNsLookup(ctxt->context, prefix);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009543 if (URI == NULL) {
9544 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009545 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009546 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009547 }
9548#ifdef DEBUG_STEP_NTH
9549 xmlGenericError(xmlGenericErrorContext, "new step : ");
9550 if (first != NULL) {
9551 if (*first != NULL)
9552 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9553 (*first)->name);
9554 else
9555 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9556 }
9557 if (last != NULL) {
9558 if (*last != NULL)
9559 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9560 (*last)->name);
9561 else
9562 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9563 }
9564#endif
9565 switch (axis) {
9566 case AXIS_ANCESTOR:
9567#ifdef DEBUG_STEP_NTH
9568 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9569#endif
9570 first = NULL;
9571 next = xmlXPathNextAncestor;
9572 break;
9573 case AXIS_ANCESTOR_OR_SELF:
9574#ifdef DEBUG_STEP_NTH
9575 xmlGenericError(xmlGenericErrorContext,
9576 "axis 'ancestors-or-self' ");
9577#endif
9578 first = NULL;
9579 next = xmlXPathNextAncestorOrSelf;
9580 break;
9581 case AXIS_ATTRIBUTE:
9582#ifdef DEBUG_STEP_NTH
9583 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9584#endif
9585 first = NULL;
9586 last = NULL;
9587 next = xmlXPathNextAttribute;
9588 break;
9589 case AXIS_CHILD:
9590#ifdef DEBUG_STEP_NTH
9591 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9592#endif
9593 last = NULL;
9594 next = xmlXPathNextChild;
9595 break;
9596 case AXIS_DESCENDANT:
9597#ifdef DEBUG_STEP_NTH
9598 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9599#endif
9600 last = NULL;
9601 next = xmlXPathNextDescendant;
9602 break;
9603 case AXIS_DESCENDANT_OR_SELF:
9604#ifdef DEBUG_STEP_NTH
9605 xmlGenericError(xmlGenericErrorContext,
9606 "axis 'descendant-or-self' ");
9607#endif
9608 last = NULL;
9609 next = xmlXPathNextDescendantOrSelf;
9610 break;
9611 case AXIS_FOLLOWING:
9612#ifdef DEBUG_STEP_NTH
9613 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9614#endif
9615 last = NULL;
9616 next = xmlXPathNextFollowing;
9617 break;
9618 case AXIS_FOLLOWING_SIBLING:
9619#ifdef DEBUG_STEP_NTH
9620 xmlGenericError(xmlGenericErrorContext,
9621 "axis 'following-siblings' ");
9622#endif
9623 last = NULL;
9624 next = xmlXPathNextFollowingSibling;
9625 break;
9626 case AXIS_NAMESPACE:
9627#ifdef DEBUG_STEP_NTH
9628 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9629#endif
9630 last = NULL;
9631 first = NULL;
9632 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9633 break;
9634 case AXIS_PARENT:
9635#ifdef DEBUG_STEP_NTH
9636 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9637#endif
9638 first = NULL;
9639 next = xmlXPathNextParent;
9640 break;
9641 case AXIS_PRECEDING:
9642#ifdef DEBUG_STEP_NTH
9643 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9644#endif
9645 first = NULL;
9646 next = xmlXPathNextPrecedingInternal;
9647 break;
9648 case AXIS_PRECEDING_SIBLING:
9649#ifdef DEBUG_STEP_NTH
9650 xmlGenericError(xmlGenericErrorContext,
9651 "axis 'preceding-sibling' ");
9652#endif
9653 first = NULL;
9654 next = xmlXPathNextPrecedingSibling;
9655 break;
9656 case AXIS_SELF:
9657#ifdef DEBUG_STEP_NTH
9658 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9659#endif
9660 first = NULL;
9661 last = NULL;
9662 next = xmlXPathNextSelf;
9663 break;
9664 }
William M. Brack2c19a7b2005-04-10 01:03:23 +00009665 if (next == NULL) {
9666 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009667 return(0);
William M. Brack2c19a7b2005-04-10 01:03:23 +00009668 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00009669
9670 nodelist = obj->nodesetval;
9671 if (nodelist == NULL) {
9672 xmlXPathFreeObject(obj);
9673 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9674 return(0);
9675 }
9676 addNode = xmlXPathNodeSetAddUnique;
9677#ifdef DEBUG_STEP_NTH
9678 xmlGenericError(xmlGenericErrorContext,
9679 " context contains %d nodes\n", nodelist->nodeNr);
9680 switch (test) {
9681 case NODE_TEST_NONE:
9682 xmlGenericError(xmlGenericErrorContext,
9683 " searching for none !!!\n");
9684 break;
9685 case NODE_TEST_TYPE:
9686 xmlGenericError(xmlGenericErrorContext,
9687 " searching for type %d\n", type);
9688 break;
9689 case NODE_TEST_PI:
9690 xmlGenericError(xmlGenericErrorContext,
9691 " searching for PI !!!\n");
9692 break;
9693 case NODE_TEST_ALL:
9694 xmlGenericError(xmlGenericErrorContext,
9695 " searching for *\n");
9696 break;
9697 case NODE_TEST_NS:
9698 xmlGenericError(xmlGenericErrorContext,
9699 " searching for namespace %s\n",
9700 prefix);
9701 break;
9702 case NODE_TEST_NAME:
9703 xmlGenericError(xmlGenericErrorContext,
9704 " searching for name %s\n", name);
9705 if (prefix != NULL)
9706 xmlGenericError(xmlGenericErrorContext,
9707 " with namespace %s\n", prefix);
9708 break;
9709 }
9710 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9711#endif
9712 /*
9713 * 2.3 Node Tests
9714 * - For the attribute axis, the principal node type is attribute.
9715 * - For the namespace axis, the principal node type is namespace.
9716 * - For other axes, the principal node type is element.
9717 *
9718 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009719 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009720 * select all element children of the context node
9721 */
9722 tmp = ctxt->context->node;
9723 list = xmlXPathNodeSetCreate(NULL);
9724 for (i = 0; i < nodelist->nodeNr; i++) {
9725 ctxt->context->node = nodelist->nodeTab[i];
9726
9727 cur = NULL;
9728 n = 0;
9729 do {
9730 cur = next(ctxt, cur);
9731 if (cur == NULL)
9732 break;
9733 if ((first != NULL) && (*first == cur))
9734 break;
9735 if (((t % 256) == 0) &&
9736 (first != NULL) && (*first != NULL) &&
9737 (xmlXPathCmpNodes(*first, cur) >= 0))
9738 break;
9739 if ((last != NULL) && (*last == cur))
9740 break;
9741 if (((t % 256) == 0) &&
9742 (last != NULL) && (*last != NULL) &&
9743 (xmlXPathCmpNodes(cur, *last) >= 0))
9744 break;
9745 t++;
9746 switch (test) {
9747 case NODE_TEST_NONE:
9748 ctxt->context->node = tmp;
9749 STRANGE return(0);
9750 case NODE_TEST_TYPE:
9751 if ((cur->type == type) ||
9752 ((type == NODE_TYPE_NODE) &&
9753 ((cur->type == XML_DOCUMENT_NODE) ||
9754 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9755 (cur->type == XML_ELEMENT_NODE) ||
9756 (cur->type == XML_PI_NODE) ||
9757 (cur->type == XML_COMMENT_NODE) ||
9758 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009759 (cur->type == XML_TEXT_NODE))) ||
9760 ((type == NODE_TYPE_TEXT) &&
9761 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009762 n++;
9763 if (n == indx)
9764 addNode(list, cur);
9765 }
9766 break;
9767 case NODE_TEST_PI:
9768 if (cur->type == XML_PI_NODE) {
9769 if ((name != NULL) &&
9770 (!xmlStrEqual(name, cur->name)))
9771 break;
9772 n++;
9773 if (n == indx)
9774 addNode(list, cur);
9775 }
9776 break;
9777 case NODE_TEST_ALL:
9778 if (axis == AXIS_ATTRIBUTE) {
9779 if (cur->type == XML_ATTRIBUTE_NODE) {
9780 n++;
9781 if (n == indx)
9782 addNode(list, cur);
9783 }
9784 } else if (axis == AXIS_NAMESPACE) {
9785 if (cur->type == XML_NAMESPACE_DECL) {
9786 n++;
9787 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009788 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9789 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009790 }
9791 } else {
9792 if (cur->type == XML_ELEMENT_NODE) {
9793 if (prefix == NULL) {
9794 n++;
9795 if (n == indx)
9796 addNode(list, cur);
9797 } else if ((cur->ns != NULL) &&
9798 (xmlStrEqual(URI, cur->ns->href))) {
9799 n++;
9800 if (n == indx)
9801 addNode(list, cur);
9802 }
9803 }
9804 }
9805 break;
9806 case NODE_TEST_NS:{
9807 TODO;
9808 break;
9809 }
9810 case NODE_TEST_NAME:
9811 switch (cur->type) {
9812 case XML_ELEMENT_NODE:
9813 if (xmlStrEqual(name, cur->name)) {
9814 if (prefix == NULL) {
9815 if (cur->ns == NULL) {
9816 n++;
9817 if (n == indx)
9818 addNode(list, cur);
9819 }
9820 } else {
9821 if ((cur->ns != NULL) &&
9822 (xmlStrEqual(URI,
9823 cur->ns->href))) {
9824 n++;
9825 if (n == indx)
9826 addNode(list, cur);
9827 }
9828 }
9829 }
9830 break;
9831 case XML_ATTRIBUTE_NODE:{
9832 xmlAttrPtr attr = (xmlAttrPtr) cur;
9833
9834 if (xmlStrEqual(name, attr->name)) {
9835 if (prefix == NULL) {
9836 if ((attr->ns == NULL) ||
9837 (attr->ns->prefix == NULL)) {
9838 n++;
9839 if (n == indx)
9840 addNode(list, cur);
9841 }
9842 } else {
9843 if ((attr->ns != NULL) &&
9844 (xmlStrEqual(URI,
9845 attr->ns->
9846 href))) {
9847 n++;
9848 if (n == indx)
9849 addNode(list, cur);
9850 }
9851 }
9852 }
9853 break;
9854 }
9855 case XML_NAMESPACE_DECL:
9856 if (cur->type == XML_NAMESPACE_DECL) {
9857 xmlNsPtr ns = (xmlNsPtr) cur;
9858
9859 if ((ns->prefix != NULL) && (name != NULL)
9860 && (xmlStrEqual(ns->prefix, name))) {
9861 n++;
9862 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009863 xmlXPathNodeSetAddNs(list,
9864 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009865 }
9866 }
9867 break;
9868 default:
9869 break;
9870 }
9871 break;
9872 break;
9873 }
9874 } while (n < indx);
9875 }
9876 ctxt->context->node = tmp;
9877#ifdef DEBUG_STEP_NTH
9878 xmlGenericError(xmlGenericErrorContext,
9879 "\nExamined %d nodes, found %d nodes at that step\n",
9880 t, list->nodeNr);
9881#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009882 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009883 if ((obj->boolval) && (obj->user != NULL)) {
9884 ctxt->value->boolval = 1;
9885 ctxt->value->user = obj->user;
9886 obj->user = NULL;
9887 obj->boolval = 0;
9888 }
9889 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009890 return(t);
9891}
9892
9893/**
9894 * xmlXPathCompOpEvalFirst:
9895 * @ctxt: the XPath parser context with the compiled expression
9896 * @op: an XPath compiled operation
9897 * @first: the first elem found so far
9898 *
9899 * Evaluate the Precompiled XPath operation searching only the first
9900 * element in document order
9901 *
9902 * Returns the number of examined objects.
9903 */
9904static int
9905xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9906 xmlXPathStepOpPtr op, xmlNodePtr * first)
9907{
9908 int total = 0, cur;
9909 xmlXPathCompExprPtr comp;
9910 xmlXPathObjectPtr arg1, arg2;
9911
Daniel Veillard556c6682001-10-06 09:59:51 +00009912 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009913 comp = ctxt->comp;
9914 switch (op->op) {
9915 case XPATH_OP_END:
9916 return (0);
9917 case XPATH_OP_UNION:
9918 total =
9919 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9920 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009921 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009922 if ((ctxt->value != NULL)
9923 && (ctxt->value->type == XPATH_NODESET)
9924 && (ctxt->value->nodesetval != NULL)
9925 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9926 /*
9927 * limit tree traversing to first node in the result
9928 */
9929 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9930 *first = ctxt->value->nodesetval->nodeTab[0];
9931 }
9932 cur =
9933 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9934 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009935 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009936 CHECK_TYPE0(XPATH_NODESET);
9937 arg2 = valuePop(ctxt);
9938
9939 CHECK_TYPE0(XPATH_NODESET);
9940 arg1 = valuePop(ctxt);
9941
9942 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9943 arg2->nodesetval);
9944 valuePush(ctxt, arg1);
9945 xmlXPathFreeObject(arg2);
9946 /* optimizer */
9947 if (total > cur)
9948 xmlXPathCompSwap(op);
9949 return (total + cur);
9950 case XPATH_OP_ROOT:
9951 xmlXPathRoot(ctxt);
9952 return (0);
9953 case XPATH_OP_NODE:
9954 if (op->ch1 != -1)
9955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009956 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009957 if (op->ch2 != -1)
9958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009959 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009960 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9961 return (total);
9962 case XPATH_OP_RESET:
9963 if (op->ch1 != -1)
9964 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009965 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009966 if (op->ch2 != -1)
9967 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009968 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 ctxt->context->node = NULL;
9970 return (total);
9971 case XPATH_OP_COLLECT:{
9972 if (op->ch1 == -1)
9973 return (total);
9974
9975 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009976 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009977
9978 /*
9979 * Optimization for [n] selection where n is a number
9980 */
9981 if ((op->ch2 != -1) &&
9982 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9983 (comp->steps[op->ch2].ch1 == -1) &&
9984 (comp->steps[op->ch2].ch2 != -1) &&
9985 (comp->steps[comp->steps[op->ch2].ch2].op ==
9986 XPATH_OP_VALUE)) {
9987 xmlXPathObjectPtr val;
9988
9989 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9990 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9991 int indx = (int) val->floatval;
9992
9993 if (val->floatval == (float) indx) {
9994 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9995 first, NULL);
9996 return (total);
9997 }
9998 }
9999 }
10000 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
10001 return (total);
10002 }
10003 case XPATH_OP_VALUE:
10004 valuePush(ctxt,
10005 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10006 return (0);
10007 case XPATH_OP_SORT:
10008 if (op->ch1 != -1)
10009 total +=
10010 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10011 first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010012 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010013 if ((ctxt->value != NULL)
10014 && (ctxt->value->type == XPATH_NODESET)
10015 && (ctxt->value->nodesetval != NULL))
10016 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10017 return (total);
10018 default:
10019 return (xmlXPathCompOpEval(ctxt, op));
10020 }
10021}
10022
10023/**
10024 * xmlXPathCompOpEvalLast:
10025 * @ctxt: the XPath parser context with the compiled expression
10026 * @op: an XPath compiled operation
10027 * @last: the last elem found so far
10028 *
10029 * Evaluate the Precompiled XPath operation searching only the last
10030 * element in document order
10031 *
William M. Brack08171912003-12-29 02:52:11 +000010032 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +000010033 */
10034static int
10035xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10036 xmlNodePtr * last)
10037{
10038 int total = 0, cur;
10039 xmlXPathCompExprPtr comp;
10040 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +000010041 xmlNodePtr bak;
10042 xmlDocPtr bakd;
10043 int pp;
10044 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010045
Daniel Veillard556c6682001-10-06 09:59:51 +000010046 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010047 comp = ctxt->comp;
10048 switch (op->op) {
10049 case XPATH_OP_END:
10050 return (0);
10051 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +000010052 bakd = ctxt->context->doc;
10053 bak = ctxt->context->node;
10054 pp = ctxt->context->proximityPosition;
10055 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 total =
10057 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010058 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010059 if ((ctxt->value != NULL)
10060 && (ctxt->value->type == XPATH_NODESET)
10061 && (ctxt->value->nodesetval != NULL)
10062 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10063 /*
10064 * limit tree traversing to first node in the result
10065 */
10066 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10067 *last =
10068 ctxt->value->nodesetval->nodeTab[ctxt->value->
10069 nodesetval->nodeNr -
10070 1];
10071 }
William M. Brackce4fc562004-01-22 02:47:18 +000010072 ctxt->context->doc = bakd;
10073 ctxt->context->node = bak;
10074 ctxt->context->proximityPosition = pp;
10075 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010076 cur =
10077 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010078 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010079 if ((ctxt->value != NULL)
10080 && (ctxt->value->type == XPATH_NODESET)
10081 && (ctxt->value->nodesetval != NULL)
10082 && (ctxt->value->nodesetval->nodeNr >= 1)) {
10083 }
10084 CHECK_TYPE0(XPATH_NODESET);
10085 arg2 = valuePop(ctxt);
10086
10087 CHECK_TYPE0(XPATH_NODESET);
10088 arg1 = valuePop(ctxt);
10089
10090 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10091 arg2->nodesetval);
10092 valuePush(ctxt, arg1);
10093 xmlXPathFreeObject(arg2);
10094 /* optimizer */
10095 if (total > cur)
10096 xmlXPathCompSwap(op);
10097 return (total + cur);
10098 case XPATH_OP_ROOT:
10099 xmlXPathRoot(ctxt);
10100 return (0);
10101 case XPATH_OP_NODE:
10102 if (op->ch1 != -1)
10103 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010104 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 if (op->ch2 != -1)
10106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010107 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010108 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10109 return (total);
10110 case XPATH_OP_RESET:
10111 if (op->ch1 != -1)
10112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010113 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010114 if (op->ch2 != -1)
10115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010116 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010117 ctxt->context->node = NULL;
10118 return (total);
10119 case XPATH_OP_COLLECT:{
10120 if (op->ch1 == -1)
10121 return (0);
10122
10123 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010124 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010125
10126 /*
10127 * Optimization for [n] selection where n is a number
10128 */
10129 if ((op->ch2 != -1) &&
10130 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10131 (comp->steps[op->ch2].ch1 == -1) &&
10132 (comp->steps[op->ch2].ch2 != -1) &&
10133 (comp->steps[comp->steps[op->ch2].ch2].op ==
10134 XPATH_OP_VALUE)) {
10135 xmlXPathObjectPtr val;
10136
10137 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10138 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10139 int indx = (int) val->floatval;
10140
10141 if (val->floatval == (float) indx) {
10142 total +=
10143 xmlXPathNodeCollectAndTestNth(ctxt, op,
10144 indx, NULL,
10145 last);
10146 return (total);
10147 }
10148 }
10149 }
10150 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10151 return (total);
10152 }
10153 case XPATH_OP_VALUE:
10154 valuePush(ctxt,
10155 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10156 return (0);
10157 case XPATH_OP_SORT:
10158 if (op->ch1 != -1)
10159 total +=
10160 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10161 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010162 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163 if ((ctxt->value != NULL)
10164 && (ctxt->value->type == XPATH_NODESET)
10165 && (ctxt->value->nodesetval != NULL))
10166 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10167 return (total);
10168 default:
10169 return (xmlXPathCompOpEval(ctxt, op));
10170 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010171}
10172
Owen Taylor3473f882001-02-23 17:55:21 +000010173/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010174 * xmlXPathCompOpEval:
10175 * @ctxt: the XPath parser context with the compiled expression
10176 * @op: an XPath compiled operation
10177 *
10178 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010179 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010180 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010181static int
10182xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10183{
10184 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010185 int equal, ret;
10186 xmlXPathCompExprPtr comp;
10187 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010188 xmlNodePtr bak;
10189 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010190 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010191 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010192
Daniel Veillard556c6682001-10-06 09:59:51 +000010193 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010194 comp = ctxt->comp;
10195 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010196 case XPATH_OP_END:
10197 return (0);
10198 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010199 bakd = ctxt->context->doc;
10200 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010201 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010202 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010203 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010204 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010205 xmlXPathBooleanFunction(ctxt, 1);
10206 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10207 return (total);
10208 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010209 ctxt->context->doc = bakd;
10210 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010211 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010212 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010213 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010214 if (ctxt->error) {
10215 xmlXPathFreeObject(arg2);
10216 return(0);
10217 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010218 xmlXPathBooleanFunction(ctxt, 1);
10219 arg1 = valuePop(ctxt);
10220 arg1->boolval &= arg2->boolval;
10221 valuePush(ctxt, arg1);
10222 xmlXPathFreeObject(arg2);
10223 return (total);
10224 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010225 bakd = ctxt->context->doc;
10226 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010227 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010228 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010231 xmlXPathBooleanFunction(ctxt, 1);
10232 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10233 return (total);
10234 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010235 ctxt->context->doc = bakd;
10236 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010237 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010238 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010239 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010240 if (ctxt->error) {
10241 xmlXPathFreeObject(arg2);
10242 return(0);
10243 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010244 xmlXPathBooleanFunction(ctxt, 1);
10245 arg1 = valuePop(ctxt);
10246 arg1->boolval |= arg2->boolval;
10247 valuePush(ctxt, arg1);
10248 xmlXPathFreeObject(arg2);
10249 return (total);
10250 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010251 bakd = ctxt->context->doc;
10252 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010253 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010254 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010256 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010257 ctxt->context->doc = bakd;
10258 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010259 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010260 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010261 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010262 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010263 if (op->value)
10264 equal = xmlXPathEqualValues(ctxt);
10265 else
10266 equal = xmlXPathNotEqualValues(ctxt);
10267 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010268 return (total);
10269 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010270 bakd = ctxt->context->doc;
10271 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010272 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010273 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010274 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010275 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010276 ctxt->context->doc = bakd;
10277 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010278 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010279 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010280 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010281 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10283 valuePush(ctxt, xmlXPathNewBoolean(ret));
10284 return (total);
10285 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010286 bakd = ctxt->context->doc;
10287 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010288 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010289 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010290 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010291 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010292 if (op->ch2 != -1) {
10293 ctxt->context->doc = bakd;
10294 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010295 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010296 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010297 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010298 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010299 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 if (op->value == 0)
10301 xmlXPathSubValues(ctxt);
10302 else if (op->value == 1)
10303 xmlXPathAddValues(ctxt);
10304 else if (op->value == 2)
10305 xmlXPathValueFlipSign(ctxt);
10306 else if (op->value == 3) {
10307 CAST_TO_NUMBER;
10308 CHECK_TYPE0(XPATH_NUMBER);
10309 }
10310 return (total);
10311 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010312 bakd = ctxt->context->doc;
10313 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010314 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010315 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010316 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010317 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010318 ctxt->context->doc = bakd;
10319 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010320 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010321 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010322 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010323 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010324 if (op->value == 0)
10325 xmlXPathMultValues(ctxt);
10326 else if (op->value == 1)
10327 xmlXPathDivValues(ctxt);
10328 else if (op->value == 2)
10329 xmlXPathModValues(ctxt);
10330 return (total);
10331 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010332 bakd = ctxt->context->doc;
10333 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010334 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010335 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010337 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010338 ctxt->context->doc = bakd;
10339 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010340 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010341 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010342 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010343 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010344 CHECK_TYPE0(XPATH_NODESET);
10345 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010346
Daniel Veillardf06307e2001-07-03 10:35:50 +000010347 CHECK_TYPE0(XPATH_NODESET);
10348 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010349
Daniel Veillardf06307e2001-07-03 10:35:50 +000010350 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10351 arg2->nodesetval);
10352 valuePush(ctxt, arg1);
10353 xmlXPathFreeObject(arg2);
10354 return (total);
10355 case XPATH_OP_ROOT:
10356 xmlXPathRoot(ctxt);
10357 return (total);
10358 case XPATH_OP_NODE:
10359 if (op->ch1 != -1)
10360 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010361 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010362 if (op->ch2 != -1)
10363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010364 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010365 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10366 return (total);
10367 case XPATH_OP_RESET:
10368 if (op->ch1 != -1)
10369 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010370 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010371 if (op->ch2 != -1)
10372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010373 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010374 ctxt->context->node = NULL;
10375 return (total);
10376 case XPATH_OP_COLLECT:{
10377 if (op->ch1 == -1)
10378 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010379
Daniel Veillardf06307e2001-07-03 10:35:50 +000010380 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010381 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010382
Daniel Veillardf06307e2001-07-03 10:35:50 +000010383 /*
10384 * Optimization for [n] selection where n is a number
10385 */
10386 if ((op->ch2 != -1) &&
10387 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10388 (comp->steps[op->ch2].ch1 == -1) &&
10389 (comp->steps[op->ch2].ch2 != -1) &&
10390 (comp->steps[comp->steps[op->ch2].ch2].op ==
10391 XPATH_OP_VALUE)) {
10392 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010393
Daniel Veillardf06307e2001-07-03 10:35:50 +000010394 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10395 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10396 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010397
Daniel Veillardf06307e2001-07-03 10:35:50 +000010398 if (val->floatval == (float) indx) {
10399 total +=
10400 xmlXPathNodeCollectAndTestNth(ctxt, op,
10401 indx, NULL,
10402 NULL);
10403 return (total);
10404 }
10405 }
10406 }
10407 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10408 return (total);
10409 }
10410 case XPATH_OP_VALUE:
10411 valuePush(ctxt,
10412 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10413 return (total);
10414 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010415 xmlXPathObjectPtr val;
10416
Daniel Veillardf06307e2001-07-03 10:35:50 +000010417 if (op->ch1 != -1)
10418 total +=
10419 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010420 if (op->value5 == NULL) {
10421 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10422 if (val == NULL) {
10423 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10424 return(0);
10425 }
10426 valuePush(ctxt, val);
10427 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010428 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010429
Daniel Veillardf06307e2001-07-03 10:35:50 +000010430 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10431 if (URI == NULL) {
10432 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010433 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010434 op->value4, op->value5);
10435 return (total);
10436 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010437 val = xmlXPathVariableLookupNS(ctxt->context,
10438 op->value4, URI);
10439 if (val == NULL) {
10440 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10441 return(0);
10442 }
10443 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010444 }
10445 return (total);
10446 }
10447 case XPATH_OP_FUNCTION:{
10448 xmlXPathFunction func;
10449 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010450 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010451
10452 if (op->ch1 != -1)
10453 total +=
10454 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010455 if (ctxt->valueNr < op->value) {
10456 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010457 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010458 ctxt->error = XPATH_INVALID_OPERAND;
10459 return (total);
10460 }
10461 for (i = 0; i < op->value; i++)
10462 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10463 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010464 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010465 ctxt->error = XPATH_INVALID_OPERAND;
10466 return (total);
10467 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010468 if (op->cache != NULL)
William M. Brackad0e67c2004-12-01 14:35:10 +000010469 XML_CAST_FPTR(func) = op->cache;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010470 else {
10471 const xmlChar *URI = NULL;
10472
10473 if (op->value5 == NULL)
10474 func =
10475 xmlXPathFunctionLookup(ctxt->context,
10476 op->value4);
10477 else {
10478 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10479 if (URI == NULL) {
10480 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010481 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010482 op->value4, op->value5);
10483 return (total);
10484 }
10485 func = xmlXPathFunctionLookupNS(ctxt->context,
10486 op->value4, URI);
10487 }
10488 if (func == NULL) {
10489 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010490 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010491 op->value4);
10492 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010493 }
William M. Brackad0e67c2004-12-01 14:35:10 +000010494 op->cache = XML_CAST_FPTR(func);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010495 op->cacheURI = (void *) URI;
10496 }
10497 oldFunc = ctxt->context->function;
10498 oldFuncURI = ctxt->context->functionURI;
10499 ctxt->context->function = op->value4;
10500 ctxt->context->functionURI = op->cacheURI;
10501 func(ctxt, op->value);
10502 ctxt->context->function = oldFunc;
10503 ctxt->context->functionURI = oldFuncURI;
10504 return (total);
10505 }
10506 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010507 bakd = ctxt->context->doc;
10508 bak = ctxt->context->node;
William M. Brack645a9242004-11-09 12:20:42 +000010509 pp = ctxt->context->proximityPosition;
10510 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010511 if (op->ch1 != -1)
10512 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
William M. Brack645a9242004-11-09 12:20:42 +000010513 ctxt->context->contextSize = cs;
10514 ctxt->context->proximityPosition = pp;
Daniel Veillard088bf112002-05-14 11:03:59 +000010515 ctxt->context->node = bak;
William M. Brack645a9242004-11-09 12:20:42 +000010516 ctxt->context->doc = bakd;
Daniel Veillard556c6682001-10-06 09:59:51 +000010517 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010518 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010519 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010520 ctxt->context->doc = bakd;
10521 ctxt->context->node = bak;
10522 CHECK_ERROR0;
10523 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010524 return (total);
10525 case XPATH_OP_PREDICATE:
10526 case XPATH_OP_FILTER:{
10527 xmlXPathObjectPtr res;
10528 xmlXPathObjectPtr obj, tmp;
10529 xmlNodeSetPtr newset = NULL;
10530 xmlNodeSetPtr oldset;
10531 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010532 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010533 int i;
10534
10535 /*
10536 * Optimization for ()[1] selection i.e. the first elem
10537 */
10538 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10539 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10540 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10541 xmlXPathObjectPtr val;
10542
10543 val = comp->steps[op->ch2].value4;
10544 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10545 (val->floatval == 1.0)) {
10546 xmlNodePtr first = NULL;
10547
10548 total +=
10549 xmlXPathCompOpEvalFirst(ctxt,
10550 &comp->steps[op->ch1],
10551 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010552 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010553 /*
10554 * The nodeset should be in document order,
10555 * Keep only the first value
10556 */
10557 if ((ctxt->value != NULL) &&
10558 (ctxt->value->type == XPATH_NODESET) &&
10559 (ctxt->value->nodesetval != NULL) &&
10560 (ctxt->value->nodesetval->nodeNr > 1))
10561 ctxt->value->nodesetval->nodeNr = 1;
10562 return (total);
10563 }
10564 }
10565 /*
10566 * Optimization for ()[last()] selection i.e. the last elem
10567 */
10568 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10569 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10570 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10571 int f = comp->steps[op->ch2].ch1;
10572
10573 if ((f != -1) &&
10574 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10575 (comp->steps[f].value5 == NULL) &&
10576 (comp->steps[f].value == 0) &&
10577 (comp->steps[f].value4 != NULL) &&
10578 (xmlStrEqual
10579 (comp->steps[f].value4, BAD_CAST "last"))) {
10580 xmlNodePtr last = NULL;
10581
10582 total +=
10583 xmlXPathCompOpEvalLast(ctxt,
10584 &comp->steps[op->ch1],
10585 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010586 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010587 /*
10588 * The nodeset should be in document order,
10589 * Keep only the last value
10590 */
10591 if ((ctxt->value != NULL) &&
10592 (ctxt->value->type == XPATH_NODESET) &&
10593 (ctxt->value->nodesetval != NULL) &&
10594 (ctxt->value->nodesetval->nodeTab != NULL) &&
10595 (ctxt->value->nodesetval->nodeNr > 1)) {
10596 ctxt->value->nodesetval->nodeTab[0] =
10597 ctxt->value->nodesetval->nodeTab[ctxt->
10598 value->
10599 nodesetval->
10600 nodeNr -
10601 1];
10602 ctxt->value->nodesetval->nodeNr = 1;
10603 }
10604 return (total);
10605 }
10606 }
10607
10608 if (op->ch1 != -1)
10609 total +=
10610 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010611 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010612 if (op->ch2 == -1)
10613 return (total);
10614 if (ctxt->value == NULL)
10615 return (total);
10616
10617 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010618
10619#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010620 /*
10621 * Hum are we filtering the result of an XPointer expression
10622 */
10623 if (ctxt->value->type == XPATH_LOCATIONSET) {
10624 xmlLocationSetPtr newlocset = NULL;
10625 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010626
Daniel Veillardf06307e2001-07-03 10:35:50 +000010627 /*
10628 * Extract the old locset, and then evaluate the result of the
10629 * expression for all the element in the locset. use it to grow
10630 * up a new locset.
10631 */
10632 CHECK_TYPE0(XPATH_LOCATIONSET);
10633 obj = valuePop(ctxt);
10634 oldlocset = obj->user;
10635 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010636
Daniel Veillardf06307e2001-07-03 10:35:50 +000010637 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10638 ctxt->context->contextSize = 0;
10639 ctxt->context->proximityPosition = 0;
10640 if (op->ch2 != -1)
10641 total +=
10642 xmlXPathCompOpEval(ctxt,
10643 &comp->steps[op->ch2]);
10644 res = valuePop(ctxt);
10645 if (res != NULL)
10646 xmlXPathFreeObject(res);
10647 valuePush(ctxt, obj);
10648 CHECK_ERROR0;
10649 return (total);
10650 }
10651 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652
Daniel Veillardf06307e2001-07-03 10:35:50 +000010653 for (i = 0; i < oldlocset->locNr; i++) {
10654 /*
10655 * Run the evaluation with a node list made of a
10656 * single item in the nodelocset.
10657 */
10658 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010659 ctxt->context->contextSize = oldlocset->locNr;
10660 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010661 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10662 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010663
Daniel Veillardf06307e2001-07-03 10:35:50 +000010664 if (op->ch2 != -1)
10665 total +=
10666 xmlXPathCompOpEval(ctxt,
10667 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010668 if (ctxt->error != XPATH_EXPRESSION_OK) {
10669 xmlXPathFreeObject(obj);
10670 return(0);
10671 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010672
Daniel Veillardf06307e2001-07-03 10:35:50 +000010673 /*
10674 * The result of the evaluation need to be tested to
10675 * decided whether the filter succeeded or not
10676 */
10677 res = valuePop(ctxt);
10678 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10679 xmlXPtrLocationSetAdd(newlocset,
10680 xmlXPathObjectCopy
10681 (oldlocset->locTab[i]));
10682 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010683
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 /*
10685 * Cleanup
10686 */
10687 if (res != NULL)
10688 xmlXPathFreeObject(res);
10689 if (ctxt->value == tmp) {
10690 res = valuePop(ctxt);
10691 xmlXPathFreeObject(res);
10692 }
10693
10694 ctxt->context->node = NULL;
10695 }
10696
10697 /*
10698 * The result is used as the new evaluation locset.
10699 */
10700 xmlXPathFreeObject(obj);
10701 ctxt->context->node = NULL;
10702 ctxt->context->contextSize = -1;
10703 ctxt->context->proximityPosition = -1;
10704 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10705 ctxt->context->node = oldnode;
10706 return (total);
10707 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010708#endif /* LIBXML_XPTR_ENABLED */
10709
Daniel Veillardf06307e2001-07-03 10:35:50 +000010710 /*
10711 * Extract the old set, and then evaluate the result of the
10712 * expression for all the element in the set. use it to grow
10713 * up a new set.
10714 */
10715 CHECK_TYPE0(XPATH_NODESET);
10716 obj = valuePop(ctxt);
10717 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010718
Daniel Veillardf06307e2001-07-03 10:35:50 +000010719 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010720 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010721 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722
Daniel Veillardf06307e2001-07-03 10:35:50 +000010723 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10724 ctxt->context->contextSize = 0;
10725 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010726/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010727 if (op->ch2 != -1)
10728 total +=
10729 xmlXPathCompOpEval(ctxt,
10730 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010731 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010732 res = valuePop(ctxt);
10733 if (res != NULL)
10734 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010735*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010736 valuePush(ctxt, obj);
10737 ctxt->context->node = oldnode;
10738 CHECK_ERROR0;
10739 } else {
10740 /*
10741 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010742 * Also set the xpath document in case things like
10743 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010744 */
10745 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746
Daniel Veillardf06307e2001-07-03 10:35:50 +000010747 for (i = 0; i < oldset->nodeNr; i++) {
10748 /*
10749 * Run the evaluation with a node list made of
10750 * a single item in the nodeset.
10751 */
10752 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010753 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10754 (oldset->nodeTab[i]->doc != NULL))
10755 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010756 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10757 valuePush(ctxt, tmp);
10758 ctxt->context->contextSize = oldset->nodeNr;
10759 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010760
Daniel Veillardf06307e2001-07-03 10:35:50 +000010761 if (op->ch2 != -1)
10762 total +=
10763 xmlXPathCompOpEval(ctxt,
10764 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010765 if (ctxt->error != XPATH_EXPRESSION_OK) {
10766 xmlXPathFreeNodeSet(newset);
10767 xmlXPathFreeObject(obj);
10768 return(0);
10769 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010770
Daniel Veillardf06307e2001-07-03 10:35:50 +000010771 /*
William M. Brack08171912003-12-29 02:52:11 +000010772 * The result of the evaluation needs to be tested to
10773 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010774 */
10775 res = valuePop(ctxt);
10776 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10777 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10778 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010779
Daniel Veillardf06307e2001-07-03 10:35:50 +000010780 /*
10781 * Cleanup
10782 */
10783 if (res != NULL)
10784 xmlXPathFreeObject(res);
10785 if (ctxt->value == tmp) {
10786 res = valuePop(ctxt);
10787 xmlXPathFreeObject(res);
10788 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010789
Daniel Veillardf06307e2001-07-03 10:35:50 +000010790 ctxt->context->node = NULL;
10791 }
10792
10793 /*
10794 * The result is used as the new evaluation set.
10795 */
10796 xmlXPathFreeObject(obj);
10797 ctxt->context->node = NULL;
10798 ctxt->context->contextSize = -1;
10799 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010800 /* may want to move this past the '}' later */
10801 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010802 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10803 }
10804 ctxt->context->node = oldnode;
10805 return (total);
10806 }
10807 case XPATH_OP_SORT:
10808 if (op->ch1 != -1)
10809 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010810 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010811 if ((ctxt->value != NULL) &&
10812 (ctxt->value->type == XPATH_NODESET) &&
10813 (ctxt->value->nodesetval != NULL))
10814 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10815 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010816#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010817 case XPATH_OP_RANGETO:{
10818 xmlXPathObjectPtr range;
10819 xmlXPathObjectPtr res, obj;
10820 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010821 xmlLocationSetPtr newlocset = NULL;
10822 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010823 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010824 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010825
Daniel Veillardf06307e2001-07-03 10:35:50 +000010826 if (op->ch1 != -1)
10827 total +=
10828 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10829 if (op->ch2 == -1)
10830 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010831
William M. Brack08171912003-12-29 02:52:11 +000010832 if (ctxt->value->type == XPATH_LOCATIONSET) {
10833 /*
10834 * Extract the old locset, and then evaluate the result of the
10835 * expression for all the element in the locset. use it to grow
10836 * up a new locset.
10837 */
10838 CHECK_TYPE0(XPATH_LOCATIONSET);
10839 obj = valuePop(ctxt);
10840 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010841
William M. Brack08171912003-12-29 02:52:11 +000010842 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010843 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010844 ctxt->context->contextSize = 0;
10845 ctxt->context->proximityPosition = 0;
10846 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10847 res = valuePop(ctxt);
10848 if (res != NULL)
10849 xmlXPathFreeObject(res);
10850 valuePush(ctxt, obj);
10851 CHECK_ERROR0;
10852 return (total);
10853 }
10854 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010855
William M. Brack08171912003-12-29 02:52:11 +000010856 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010857 /*
William M. Brack08171912003-12-29 02:52:11 +000010858 * Run the evaluation with a node list made of a
10859 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010860 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010861 ctxt->context->node = oldlocset->locTab[i]->user;
10862 ctxt->context->contextSize = oldlocset->locNr;
10863 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010864 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10865 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010866
Daniel Veillardf06307e2001-07-03 10:35:50 +000010867 if (op->ch2 != -1)
10868 total +=
10869 xmlXPathCompOpEval(ctxt,
10870 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010871 if (ctxt->error != XPATH_EXPRESSION_OK) {
10872 xmlXPathFreeObject(obj);
10873 return(0);
10874 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010875
Daniel Veillardf06307e2001-07-03 10:35:50 +000010876 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010877 if (res->type == XPATH_LOCATIONSET) {
10878 xmlLocationSetPtr rloc =
10879 (xmlLocationSetPtr)res->user;
10880 for (j=0; j<rloc->locNr; j++) {
10881 range = xmlXPtrNewRange(
10882 oldlocset->locTab[i]->user,
10883 oldlocset->locTab[i]->index,
10884 rloc->locTab[j]->user2,
10885 rloc->locTab[j]->index2);
10886 if (range != NULL) {
10887 xmlXPtrLocationSetAdd(newlocset, range);
10888 }
10889 }
10890 } else {
10891 range = xmlXPtrNewRangeNodeObject(
10892 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10893 if (range != NULL) {
10894 xmlXPtrLocationSetAdd(newlocset,range);
10895 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010896 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010897
Daniel Veillardf06307e2001-07-03 10:35:50 +000010898 /*
10899 * Cleanup
10900 */
10901 if (res != NULL)
10902 xmlXPathFreeObject(res);
10903 if (ctxt->value == tmp) {
10904 res = valuePop(ctxt);
10905 xmlXPathFreeObject(res);
10906 }
10907
10908 ctxt->context->node = NULL;
10909 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010910 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010911 CHECK_TYPE0(XPATH_NODESET);
10912 obj = valuePop(ctxt);
10913 oldset = obj->nodesetval;
10914 ctxt->context->node = NULL;
10915
10916 newlocset = xmlXPtrLocationSetCreate(NULL);
10917
10918 if (oldset != NULL) {
10919 for (i = 0; i < oldset->nodeNr; i++) {
10920 /*
10921 * Run the evaluation with a node list made of a single item
10922 * in the nodeset.
10923 */
10924 ctxt->context->node = oldset->nodeTab[i];
10925 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10926 valuePush(ctxt, tmp);
10927
10928 if (op->ch2 != -1)
10929 total +=
10930 xmlXPathCompOpEval(ctxt,
10931 &comp->steps[op->ch2]);
William M. Brack2c19a7b2005-04-10 01:03:23 +000010932 if (ctxt->error != XPATH_EXPRESSION_OK) {
10933 xmlXPathFreeObject(obj);
10934 return(0);
10935 }
William M. Brack08171912003-12-29 02:52:11 +000010936
William M. Brack08171912003-12-29 02:52:11 +000010937 res = valuePop(ctxt);
10938 range =
10939 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10940 res);
10941 if (range != NULL) {
10942 xmlXPtrLocationSetAdd(newlocset, range);
10943 }
10944
10945 /*
10946 * Cleanup
10947 */
10948 if (res != NULL)
10949 xmlXPathFreeObject(res);
10950 if (ctxt->value == tmp) {
10951 res = valuePop(ctxt);
10952 xmlXPathFreeObject(res);
10953 }
10954
10955 ctxt->context->node = NULL;
10956 }
10957 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010958 }
10959
10960 /*
10961 * The result is used as the new evaluation set.
10962 */
10963 xmlXPathFreeObject(obj);
10964 ctxt->context->node = NULL;
10965 ctxt->context->contextSize = -1;
10966 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010967 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010968 return (total);
10969 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010970#endif /* LIBXML_XPTR_ENABLED */
10971 }
10972 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010973 "XPath: unknown precompiled operation %d\n", op->op);
10974 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010975}
10976
Daniel Veillard56de87e2005-02-16 00:22:29 +000010977#ifdef XPATH_STREAMING
10978/**
10979 * xmlXPathRunStreamEval:
10980 * @ctxt: the XPath parser context with the compiled expression
10981 *
10982 * Evaluate the Precompiled Streamable XPath expression in the given context.
10983 */
10984static xmlXPathObjectPtr
10985xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp) {
10986 int max_depth;
10987 int from_root;
10988 int ret, depth;
William M. Brack12d37ab2005-02-21 13:54:07 +000010989 xmlNodePtr cur = NULL, limit = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000010990 xmlXPathObjectPtr retval;
10991 xmlStreamCtxtPtr patstream;
10992
10993 int nb_nodes = 0;
10994
10995 if ((ctxt == NULL) || (comp == NULL))
10996 return(NULL);
10997 max_depth = xmlPatternMaxDepth(comp);
10998 if (max_depth == -1)
10999 return(NULL);
11000 if (max_depth == -2)
11001 max_depth = 10000;
11002 from_root = xmlPatternFromRoot(comp);
11003 if (from_root < 0)
11004 return(NULL);
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011005#if 0
11006 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
11007#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011008
11009 retval = xmlXPathNewNodeSet(NULL);
11010 if (retval == NULL)
11011 return(NULL);
11012
Daniel Veillard56de87e2005-02-16 00:22:29 +000011013 if ((from_root) && (max_depth == 0)) {
11014 xmlXPathNodeSetAddUnique(retval->nodesetval, (xmlNodePtr) ctxt->doc);
11015 return(retval);
11016 } else if (max_depth == 0) {
11017 xmlXPathNodeSetAddUnique(retval->nodesetval, ctxt->node);
11018 return(retval);
11019 }
11020 if (from_root) {
William M. Brack12d37ab2005-02-21 13:54:07 +000011021 cur = (xmlNodePtr)ctxt->doc;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011022 } else if (ctxt->node != NULL) {
11023 switch (ctxt->node->type) {
11024 case XML_ELEMENT_NODE:
11025 case XML_DOCUMENT_NODE:
11026 case XML_DOCUMENT_FRAG_NODE:
11027 case XML_HTML_DOCUMENT_NODE:
11028#ifdef LIBXML_DOCB_ENABLED
11029 case XML_DOCB_DOCUMENT_NODE:
11030#endif
11031 cur = ctxt->node;
11032 break;
11033 case XML_ATTRIBUTE_NODE:
11034 case XML_TEXT_NODE:
11035 case XML_CDATA_SECTION_NODE:
11036 case XML_ENTITY_REF_NODE:
11037 case XML_ENTITY_NODE:
11038 case XML_PI_NODE:
11039 case XML_COMMENT_NODE:
11040 case XML_NOTATION_NODE:
11041 case XML_DTD_NODE:
11042 case XML_DOCUMENT_TYPE_NODE:
11043 case XML_ELEMENT_DECL:
11044 case XML_ATTRIBUTE_DECL:
11045 case XML_ENTITY_DECL:
11046 case XML_NAMESPACE_DECL:
11047 case XML_XINCLUDE_START:
11048 case XML_XINCLUDE_END:
Daniel Veillard56de87e2005-02-16 00:22:29 +000011049 break;
11050 }
11051 limit = cur;
11052 }
11053 if (cur == NULL)
11054 return(retval);
11055
11056 patstream = xmlPatternGetStreamCtxt(comp);
11057 if (patstream == NULL) {
11058 return(retval);
11059 }
11060
11061 if (from_root) {
11062 ret = xmlStreamPush(patstream, NULL, NULL);
11063 if (ret < 0) {
11064 } else if (ret == 1) {
11065 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11066 }
11067 }
11068
11069 depth = 0;
11070 goto scan_children;
11071 do {
11072next_node:
11073 nb_nodes++;
11074 if (cur->type == XML_ELEMENT_NODE) {
11075 ret = xmlStreamPush(patstream, cur->name,
11076 (cur->ns ? cur->ns->href : NULL));
11077 if (ret < 0) {
11078 } else if (ret == 1) {
11079 xmlXPathNodeSetAddUnique(retval->nodesetval, cur);
11080 }
11081 if ((cur->children == NULL) || (depth >= max_depth)) {
11082 ret = xmlStreamPop(patstream);
William M. Brackfbb619f2005-06-06 13:49:18 +000011083 while (cur->next != NULL) {
11084 cur = cur->next;
11085 if ((cur->type != XML_ENTITY_DECL) &&
11086 (cur->type != XML_DTD_NODE))
11087 goto next_node;
11088 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011089 }
11090 }
11091
11092scan_children:
11093 if ((cur->children != NULL) && (depth < max_depth)) {
11094 /*
11095 * Do not descend on entities declarations
11096 */
11097 if (cur->children->type != XML_ENTITY_DECL) {
11098 cur = cur->children;
11099 depth++;
11100 /*
11101 * Skip DTDs
11102 */
11103 if (cur->type != XML_DTD_NODE)
11104 continue;
11105 }
11106 }
11107
11108 if (cur == limit)
11109 break;
11110
11111 while (cur->next != NULL) {
11112 cur = cur->next;
11113 if ((cur->type != XML_ENTITY_DECL) &&
11114 (cur->type != XML_DTD_NODE))
11115 goto next_node;
11116 }
11117
11118 do {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011119 cur = cur->parent;
11120 depth--;
11121 if ((cur == NULL) || (cur == limit))
11122 goto done;
William M. Brackfbb619f2005-06-06 13:49:18 +000011123 if (cur->type == XML_ELEMENT_NODE)
11124 ret = xmlStreamPop(patstream);
Daniel Veillard56de87e2005-02-16 00:22:29 +000011125 if (cur->next != NULL) {
11126 cur = cur->next;
11127 break;
11128 }
11129 } while (cur != NULL);
11130
11131 } while ((cur != NULL) && (depth >= 0));
11132done:
Daniel Veillardfa1f77f2005-02-21 10:44:36 +000011133#if 0
11134 printf("stream eval: checked %d nodes selected %d\n",
11135 nb_nodes, retval->nodesetval->nodeNr);
11136#endif
Daniel Veillard56de87e2005-02-16 00:22:29 +000011137 xmlFreeStreamCtxt(patstream);
11138 return(retval);
11139}
11140#endif /* XPATH_STREAMING */
11141
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011142/**
11143 * xmlXPathRunEval:
11144 * @ctxt: the XPath parser context with the compiled expression
11145 *
11146 * Evaluate the Precompiled XPath expression in the given context.
11147 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011148static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011149xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
11150 xmlXPathCompExprPtr comp;
11151
11152 if ((ctxt == NULL) || (ctxt->comp == NULL))
11153 return;
11154
11155 if (ctxt->valueTab == NULL) {
11156 /* Allocate the value stack */
11157 ctxt->valueTab = (xmlXPathObjectPtr *)
11158 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
11159 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000011160 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011161 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011162 }
11163 ctxt->valueNr = 0;
11164 ctxt->valueMax = 10;
11165 ctxt->value = NULL;
11166 }
Daniel Veillard56de87e2005-02-16 00:22:29 +000011167#ifdef XPATH_STREAMING
11168 if (ctxt->comp->stream) {
11169 xmlXPathObjectPtr ret;
11170 ret = xmlXPathRunStreamEval(ctxt->context, ctxt->comp->stream);
11171 if (ret != NULL) {
11172 valuePush(ctxt, ret);
11173 return;
11174 }
11175 }
11176#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011177 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000011178 if(comp->last < 0) {
11179 xmlGenericError(xmlGenericErrorContext,
11180 "xmlXPathRunEval: last is less than zero\n");
11181 return;
11182 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011183 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11184}
11185
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011186/************************************************************************
11187 * *
11188 * Public interfaces *
11189 * *
11190 ************************************************************************/
11191
11192/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011193 * xmlXPathEvalPredicate:
11194 * @ctxt: the XPath context
11195 * @res: the Predicate Expression evaluation result
11196 *
11197 * Evaluate a predicate result for the current node.
11198 * A PredicateExpr is evaluated by evaluating the Expr and converting
11199 * the result to a boolean. If the result is a number, the result will
11200 * be converted to true if the number is equal to the position of the
11201 * context node in the context node list (as returned by the position
11202 * function) and will be converted to false otherwise; if the result
11203 * is not a number, then the result will be converted as if by a call
11204 * to the boolean function.
11205 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011206 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011207 */
11208int
11209xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011210 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011211 switch (res->type) {
11212 case XPATH_BOOLEAN:
11213 return(res->boolval);
11214 case XPATH_NUMBER:
11215 return(res->floatval == ctxt->proximityPosition);
11216 case XPATH_NODESET:
11217 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000011218 if (res->nodesetval == NULL)
11219 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000011220 return(res->nodesetval->nodeNr != 0);
11221 case XPATH_STRING:
11222 return((res->stringval != NULL) &&
11223 (xmlStrlen(res->stringval) != 0));
11224 default:
11225 STRANGE
11226 }
11227 return(0);
11228}
11229
11230/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011231 * xmlXPathEvaluatePredicateResult:
11232 * @ctxt: the XPath Parser context
11233 * @res: the Predicate Expression evaluation result
11234 *
11235 * Evaluate a predicate result for the current node.
11236 * A PredicateExpr is evaluated by evaluating the Expr and converting
11237 * the result to a boolean. If the result is a number, the result will
11238 * be converted to true if the number is equal to the position of the
11239 * context node in the context node list (as returned by the position
11240 * function) and will be converted to false otherwise; if the result
11241 * is not a number, then the result will be converted as if by a call
11242 * to the boolean function.
11243 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011244 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011245 */
11246int
11247xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
11248 xmlXPathObjectPtr res) {
Daniel Veillardce682bc2004-11-05 17:22:25 +000011249 if ((ctxt == NULL) || (res == NULL)) return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011250 switch (res->type) {
11251 case XPATH_BOOLEAN:
11252 return(res->boolval);
11253 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000011254#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000011255 return((res->floatval == ctxt->context->proximityPosition) &&
11256 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000011257#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011258 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000011259#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011260 case XPATH_NODESET:
11261 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000011262 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000011263 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011264 return(res->nodesetval->nodeNr != 0);
11265 case XPATH_STRING:
11266 return((res->stringval != NULL) &&
11267 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000011268#ifdef LIBXML_XPTR_ENABLED
11269 case XPATH_LOCATIONSET:{
11270 xmlLocationSetPtr ptr = res->user;
11271 if (ptr == NULL)
11272 return(0);
11273 return (ptr->locNr != 0);
11274 }
11275#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011276 default:
11277 STRANGE
11278 }
11279 return(0);
11280}
11281
Daniel Veillard56de87e2005-02-16 00:22:29 +000011282#ifdef XPATH_STREAMING
11283/**
11284 * xmlXPathTryStreamCompile:
11285 * @ctxt: an XPath context
11286 * @str: the XPath expression
11287 *
11288 * Try to compile the XPath expression as a streamable subset.
11289 *
11290 * Returns the compiled expression or NULL if failed to compile.
11291 */
11292static xmlXPathCompExprPtr
11293xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11294 /*
11295 * Optimization: use streaming patterns when the XPath expression can
11296 * be compiled to a stream lookup
11297 */
11298 xmlPatternPtr stream;
11299 xmlXPathCompExprPtr comp;
11300 xmlDictPtr dict = NULL;
11301 const xmlChar **namespaces = NULL;
11302 xmlNsPtr ns;
11303 int i, j;
11304
11305 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11306 (!xmlStrchr(str, '@'))) {
11307 if (ctxt != NULL) {
11308 dict = ctxt->dict;
11309 if (ctxt->nsNr > 0) {
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000011310 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
Daniel Veillard56de87e2005-02-16 00:22:29 +000011311 if (namespaces == NULL) {
11312 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
11313 return(NULL);
11314 }
11315 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11316 ns = ctxt->namespaces[j];
11317 namespaces[i++] = ns->href;
11318 namespaces[i++] = ns->prefix;
11319 }
11320 namespaces[i++] = NULL;
11321 namespaces[i++] = NULL;
11322 }
11323 }
11324
11325 stream = xmlPatterncompile(str, dict, 0, &namespaces[0]);
11326 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11327 comp = xmlXPathNewCompExpr();
11328 if (comp == NULL) {
11329 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
11330 return(NULL);
11331 }
11332 comp->stream = stream;
11333 comp->dict = dict;
11334 if (comp->dict)
11335 xmlDictReference(comp->dict);
11336 return(comp);
11337 }
11338 xmlFreePattern(stream);
11339 }
11340 return(NULL);
11341}
11342#endif /* XPATH_STREAMING */
11343
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011344/**
Daniel Veillard4773df22004-01-23 13:15:13 +000011345 * xmlXPathCtxtCompile:
11346 * @ctxt: an XPath context
11347 * @str: the XPath expression
11348 *
11349 * Compile an XPath expression
11350 *
11351 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11352 * the caller has to free the object.
11353 */
11354xmlXPathCompExprPtr
11355xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11356 xmlXPathParserContextPtr pctxt;
11357 xmlXPathCompExprPtr comp;
11358
Daniel Veillard56de87e2005-02-16 00:22:29 +000011359#ifdef XPATH_STREAMING
11360 comp = xmlXPathTryStreamCompile(ctxt, str);
11361 if (comp != NULL)
11362 return(comp);
11363#endif
11364
Daniel Veillard4773df22004-01-23 13:15:13 +000011365 xmlXPathInit();
11366
11367 pctxt = xmlXPathNewParserContext(str, ctxt);
11368 xmlXPathCompileExpr(pctxt);
11369
11370 if( pctxt->error != XPATH_EXPRESSION_OK )
11371 {
11372 xmlXPathFreeParserContext(pctxt);
11373 return (0);
11374 }
11375
11376 if (*pctxt->cur != 0) {
11377 /*
11378 * aleksey: in some cases this line prints *second* error message
11379 * (see bug #78858) and probably this should be fixed.
11380 * However, we are not sure that all error messages are printed
11381 * out in other places. It's not critical so we leave it as-is for now
11382 */
11383 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11384 comp = NULL;
11385 } else {
11386 comp = pctxt->comp;
11387 pctxt->comp = NULL;
11388 }
11389 xmlXPathFreeParserContext(pctxt);
11390 if (comp != NULL) {
11391 comp->expr = xmlStrdup(str);
11392#ifdef DEBUG_EVAL_COUNTS
11393 comp->string = xmlStrdup(str);
11394 comp->nb = 0;
11395#endif
11396 }
11397 return(comp);
11398}
11399
11400/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011401 * xmlXPathCompile:
11402 * @str: the XPath expression
11403 *
11404 * Compile an XPath expression
11405 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011406 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011407 * the caller has to free the object.
11408 */
11409xmlXPathCompExprPtr
11410xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011411 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011412}
11413
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011414/**
11415 * xmlXPathCompiledEval:
11416 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011417 * @ctx: the XPath context
11418 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011419 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011420 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011421 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011422 * the caller has to free the object.
11423 */
11424xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011425xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011426 xmlXPathParserContextPtr ctxt;
11427 xmlXPathObjectPtr res, tmp, init = NULL;
11428 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011429#ifndef LIBXML_THREAD_ENABLED
11430 static int reentance = 0;
11431#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011432
William M. Brackf13f77f2004-11-12 16:03:48 +000011433 CHECK_CTXT(ctx)
11434
11435 if (comp == NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011436 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011437 xmlXPathInit();
11438
Daniel Veillard81463942001-10-16 12:34:39 +000011439#ifndef LIBXML_THREAD_ENABLED
11440 reentance++;
11441 if (reentance > 1)
11442 xmlXPathDisableOptimizer = 1;
11443#endif
11444
Daniel Veillardf06307e2001-07-03 10:35:50 +000011445#ifdef DEBUG_EVAL_COUNTS
11446 comp->nb++;
11447 if ((comp->string != NULL) && (comp->nb > 100)) {
11448 fprintf(stderr, "100 x %s\n", comp->string);
11449 comp->nb = 0;
11450 }
11451#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011452 ctxt = xmlXPathCompParserContext(comp, ctx);
11453 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011454
11455 if (ctxt->value == NULL) {
11456 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011457 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011458 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011459 } else {
11460 res = valuePop(ctxt);
11461 }
11462
Daniel Veillardf06307e2001-07-03 10:35:50 +000011463
Owen Taylor3473f882001-02-23 17:55:21 +000011464 do {
11465 tmp = valuePop(ctxt);
11466 if (tmp != NULL) {
11467 if (tmp != init)
11468 stack++;
11469 xmlXPathFreeObject(tmp);
11470 }
11471 } while (tmp != NULL);
11472 if ((stack != 0) && (res != NULL)) {
11473 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011474 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011475 stack);
11476 }
11477 if (ctxt->error != XPATH_EXPRESSION_OK) {
11478 xmlXPathFreeObject(res);
11479 res = NULL;
11480 }
11481
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011482
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011483 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011484 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011485#ifndef LIBXML_THREAD_ENABLED
11486 reentance--;
11487#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011488 return(res);
11489}
11490
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011491/**
11492 * xmlXPathEvalExpr:
11493 * @ctxt: the XPath Parser context
11494 *
11495 * Parse and evaluate an XPath expression in the given context,
11496 * then push the result on the context stack
11497 */
11498void
11499xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard56de87e2005-02-16 00:22:29 +000011500#ifdef XPATH_STREAMING
11501 xmlXPathCompExprPtr comp;
11502#endif
11503
Daniel Veillarda82b1822004-11-08 16:24:57 +000011504 if (ctxt == NULL) return;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011505
11506#ifdef XPATH_STREAMING
11507 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11508 if (comp != NULL) {
11509 if (ctxt->comp != NULL)
11510 xmlXPathFreeCompExpr(ctxt->comp);
11511 ctxt->comp = comp;
11512 if (ctxt->cur != NULL)
11513 while (*ctxt->cur != 0) ctxt->cur++;
11514 } else
11515#endif
11516 {
11517 xmlXPathCompileExpr(ctxt);
11518 }
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011519 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011520 xmlXPathRunEval(ctxt);
11521}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011522
11523/**
11524 * xmlXPathEval:
11525 * @str: the XPath expression
11526 * @ctx: the XPath context
11527 *
11528 * Evaluate the XPath Location Path in the given context.
11529 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011530 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011531 * the caller has to free the object.
11532 */
11533xmlXPathObjectPtr
11534xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11535 xmlXPathParserContextPtr ctxt;
11536 xmlXPathObjectPtr res, tmp, init = NULL;
11537 int stack = 0;
11538
William M. Brackf13f77f2004-11-12 16:03:48 +000011539 CHECK_CTXT(ctx)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011540
William M. Brackf13f77f2004-11-12 16:03:48 +000011541 xmlXPathInit();
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011542
11543 ctxt = xmlXPathNewParserContext(str, ctx);
11544 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011545
11546 if (ctxt->value == NULL) {
11547 xmlGenericError(xmlGenericErrorContext,
11548 "xmlXPathEval: evaluation failed\n");
11549 res = NULL;
Daniel Veillard56de87e2005-02-16 00:22:29 +000011550 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
11551#ifdef XPATH_STREAMING
11552 && (ctxt->comp->stream == NULL)
11553#endif
11554 ) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011555 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11556 res = NULL;
11557 } else {
11558 res = valuePop(ctxt);
11559 }
11560
11561 do {
11562 tmp = valuePop(ctxt);
11563 if (tmp != NULL) {
11564 if (tmp != init)
11565 stack++;
11566 xmlXPathFreeObject(tmp);
11567 }
11568 } while (tmp != NULL);
11569 if ((stack != 0) && (res != NULL)) {
11570 xmlGenericError(xmlGenericErrorContext,
11571 "xmlXPathEval: %d object left on the stack\n",
11572 stack);
11573 }
11574 if (ctxt->error != XPATH_EXPRESSION_OK) {
11575 xmlXPathFreeObject(res);
11576 res = NULL;
11577 }
11578
Owen Taylor3473f882001-02-23 17:55:21 +000011579 xmlXPathFreeParserContext(ctxt);
11580 return(res);
11581}
11582
11583/**
11584 * xmlXPathEvalExpression:
11585 * @str: the XPath expression
11586 * @ctxt: the XPath context
11587 *
11588 * Evaluate the XPath expression in the given context.
11589 *
11590 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11591 * the caller has to free the object.
11592 */
11593xmlXPathObjectPtr
11594xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11595 xmlXPathParserContextPtr pctxt;
11596 xmlXPathObjectPtr res, tmp;
11597 int stack = 0;
11598
William M. Brackf13f77f2004-11-12 16:03:48 +000011599 CHECK_CTXT(ctxt)
Owen Taylor3473f882001-02-23 17:55:21 +000011600
William M. Brackf13f77f2004-11-12 16:03:48 +000011601 xmlXPathInit();
Owen Taylor3473f882001-02-23 17:55:21 +000011602
11603 pctxt = xmlXPathNewParserContext(str, ctxt);
11604 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011605
11606 if (*pctxt->cur != 0) {
11607 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11608 res = NULL;
11609 } else {
11610 res = valuePop(pctxt);
11611 }
11612 do {
11613 tmp = valuePop(pctxt);
11614 if (tmp != NULL) {
11615 xmlXPathFreeObject(tmp);
11616 stack++;
11617 }
11618 } while (tmp != NULL);
11619 if ((stack != 0) && (res != NULL)) {
11620 xmlGenericError(xmlGenericErrorContext,
11621 "xmlXPathEvalExpression: %d object left on the stack\n",
11622 stack);
11623 }
11624 xmlXPathFreeParserContext(pctxt);
11625 return(res);
11626}
11627
Daniel Veillard42766c02002-08-22 20:52:17 +000011628/************************************************************************
11629 * *
11630 * Extra functions not pertaining to the XPath spec *
11631 * *
11632 ************************************************************************/
11633/**
11634 * xmlXPathEscapeUriFunction:
11635 * @ctxt: the XPath Parser context
11636 * @nargs: the number of arguments
11637 *
11638 * Implement the escape-uri() XPath function
11639 * string escape-uri(string $str, bool $escape-reserved)
11640 *
11641 * This function applies the URI escaping rules defined in section 2 of [RFC
11642 * 2396] to the string supplied as $uri-part, which typically represents all
11643 * or part of a URI. The effect of the function is to replace any special
11644 * character in the string by an escape sequence of the form %xx%yy...,
11645 * where xxyy... is the hexadecimal representation of the octets used to
11646 * represent the character in UTF-8.
11647 *
11648 * The set of characters that are escaped depends on the setting of the
11649 * boolean argument $escape-reserved.
11650 *
11651 * If $escape-reserved is true, all characters are escaped other than lower
11652 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11653 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11654 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11655 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11656 * A-F).
11657 *
11658 * If $escape-reserved is false, the behavior differs in that characters
11659 * referred to in [RFC 2396] as reserved characters are not escaped. These
11660 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11661 *
11662 * [RFC 2396] does not define whether escaped URIs should use lower case or
11663 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11664 * compared using string comparison functions, this function must always use
11665 * the upper-case letters A-F.
11666 *
11667 * Generally, $escape-reserved should be set to true when escaping a string
11668 * that is to form a single part of a URI, and to false when escaping an
11669 * entire URI or URI reference.
11670 *
11671 * In the case of non-ascii characters, the string is encoded according to
11672 * utf-8 and then converted according to RFC 2396.
11673 *
11674 * Examples
11675 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11676 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11677 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11678 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11679 *
11680 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011681static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011682xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11683 xmlXPathObjectPtr str;
11684 int escape_reserved;
11685 xmlBufferPtr target;
11686 xmlChar *cptr;
11687 xmlChar escape[4];
11688
11689 CHECK_ARITY(2);
11690
11691 escape_reserved = xmlXPathPopBoolean(ctxt);
11692
11693 CAST_TO_STRING;
11694 str = valuePop(ctxt);
11695
11696 target = xmlBufferCreate();
11697
11698 escape[0] = '%';
11699 escape[3] = 0;
11700
11701 if (target) {
11702 for (cptr = str->stringval; *cptr; cptr++) {
11703 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11704 (*cptr >= 'a' && *cptr <= 'z') ||
11705 (*cptr >= '0' && *cptr <= '9') ||
11706 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11707 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11708 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11709 (*cptr == '%' &&
11710 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11711 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11712 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11713 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11714 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11715 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11716 (!escape_reserved &&
11717 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11718 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11719 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11720 *cptr == ','))) {
11721 xmlBufferAdd(target, cptr, 1);
11722 } else {
11723 if ((*cptr >> 4) < 10)
11724 escape[1] = '0' + (*cptr >> 4);
11725 else
11726 escape[1] = 'A' - 10 + (*cptr >> 4);
11727 if ((*cptr & 0xF) < 10)
11728 escape[2] = '0' + (*cptr & 0xF);
11729 else
11730 escape[2] = 'A' - 10 + (*cptr & 0xF);
11731
11732 xmlBufferAdd(target, &escape[0], 3);
11733 }
11734 }
11735 }
11736 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11737 xmlBufferFree(target);
11738 xmlXPathFreeObject(str);
11739}
11740
Owen Taylor3473f882001-02-23 17:55:21 +000011741/**
11742 * xmlXPathRegisterAllFunctions:
11743 * @ctxt: the XPath context
11744 *
11745 * Registers all default XPath functions in this context
11746 */
11747void
11748xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11749{
11750 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11751 xmlXPathBooleanFunction);
11752 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11753 xmlXPathCeilingFunction);
11754 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11755 xmlXPathCountFunction);
11756 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11757 xmlXPathConcatFunction);
11758 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11759 xmlXPathContainsFunction);
11760 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11761 xmlXPathIdFunction);
11762 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11763 xmlXPathFalseFunction);
11764 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11765 xmlXPathFloorFunction);
11766 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11767 xmlXPathLastFunction);
11768 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11769 xmlXPathLangFunction);
11770 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11771 xmlXPathLocalNameFunction);
11772 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11773 xmlXPathNotFunction);
11774 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11775 xmlXPathNameFunction);
11776 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11777 xmlXPathNamespaceURIFunction);
11778 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11779 xmlXPathNormalizeFunction);
11780 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11781 xmlXPathNumberFunction);
11782 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11783 xmlXPathPositionFunction);
11784 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11785 xmlXPathRoundFunction);
11786 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11787 xmlXPathStringFunction);
11788 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11789 xmlXPathStringLengthFunction);
11790 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11791 xmlXPathStartsWithFunction);
11792 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11793 xmlXPathSubstringFunction);
11794 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11795 xmlXPathSubstringBeforeFunction);
11796 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11797 xmlXPathSubstringAfterFunction);
11798 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11799 xmlXPathSumFunction);
11800 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11801 xmlXPathTrueFunction);
11802 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11803 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011804
11805 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11806 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11807 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011808}
11809
11810#endif /* LIBXML_XPATH_ENABLED */
Daniel Veillard5d4644e2005-04-01 13:11:58 +000011811#define bottom_xpath
11812#include "elfgcchack.h"