blob: 89a8e281c5aa860e76c5a7b8ca2db59a466ae6c6 [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>
Owen Taylor3473f882001-02-23 17:55:21 +000054
Daniel Veillardd96f6d32003-10-07 21:25:12 +000055#define TODO \
56 xmlGenericError(xmlGenericErrorContext, \
57 "Unimplemented block at %s:%d\n", \
58 __FILE__, __LINE__);
59
William M. Brackd1757ab2004-10-02 22:07:48 +000060/*
61 * TODO:
62 * There are a few spots where some tests are done which depend upon ascii
63 * data. These should be enhanced for full UTF8 support (see particularly
64 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
65 */
66
Daniel Veillard4432df22003-09-28 18:58:27 +000067#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000068/************************************************************************
69 * *
70 * Floating point stuff *
71 * *
72 ************************************************************************/
73
Daniel Veillardc0631a62001-09-20 13:56:06 +000074#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000075#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000076#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000077#include "trionan.c"
78
Owen Taylor3473f882001-02-23 17:55:21 +000079/*
Owen Taylor3473f882001-02-23 17:55:21 +000080 * The lack of portability of this section of the libc is annoying !
81 */
82double xmlXPathNAN = 0;
83double xmlXPathPINF = 1;
84double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000085double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000086static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000087
Owen Taylor3473f882001-02-23 17:55:21 +000088/**
89 * xmlXPathInit:
90 *
91 * Initialize the XPath environment
92 */
93void
94xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000096
Bjorn Reese45029602001-08-21 09:23:53 +000097 xmlXPathPINF = trio_pinf();
98 xmlXPathNINF = trio_ninf();
99 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000100 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +0000101
Daniel Veillard20ee8c02001-10-05 09:18:14 +0000102 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +0000103}
104
Daniel Veillardcda96922001-08-21 10:56:31 +0000105/**
106 * xmlXPathIsNaN:
107 * @val: a double value
108 *
109 * Provides a portable isnan() function to detect whether a double
110 * is a NotaNumber. Based on trio code
111 * http://sourceforge.net/projects/ctrio/
112 *
113 * Returns 1 if the value is a NaN, 0 otherwise
114 */
115int
116xmlXPathIsNaN(double val) {
117 return(trio_isnan(val));
118}
119
120/**
121 * xmlXPathIsInf:
122 * @val: a double value
123 *
124 * Provides a portable isinf() function to detect whether a double
125 * is a +Infinite or -Infinite. Based on trio code
126 * http://sourceforge.net/projects/ctrio/
127 *
128 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
129 */
130int
131xmlXPathIsInf(double val) {
132 return(trio_isinf(val));
133}
134
Daniel Veillard4432df22003-09-28 18:58:27 +0000135#endif /* SCHEMAS or XPATH */
136#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000137/**
138 * xmlXPathGetSign:
139 * @val: a double value
140 *
141 * Provides a portable function to detect the sign of a double
142 * Modified from trio code
143 * http://sourceforge.net/projects/ctrio/
144 *
145 * Returns 1 if the value is Negative, 0 if positive
146 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000147static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000148xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000149 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000150}
151
152
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000153/*
154 * TODO: when compatibility allows remove all "fake node libxslt" strings
155 * the test should just be name[0] = ' '
156 */
157/* #define DEBUG */
158/* #define DEBUG_STEP */
159/* #define DEBUG_STEP_NTH */
160/* #define DEBUG_EXPR */
161/* #define DEBUG_EVAL_COUNTS */
162
163static xmlNs xmlXPathXMLNamespaceStruct = {
164 NULL,
165 XML_NAMESPACE_DECL,
166 XML_XML_NAMESPACE,
167 BAD_CAST "xml",
168 NULL
169};
170static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
171#ifndef LIBXML_THREAD_ENABLED
172/*
173 * Optimizer is disabled only when threaded apps are detected while
174 * the library ain't compiled for thread safety.
175 */
176static int xmlXPathDisableOptimizer = 0;
177#endif
178
Owen Taylor3473f882001-02-23 17:55:21 +0000179/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000180 * *
181 * Error handling routines *
182 * *
183 ************************************************************************/
184
William M. Brack08171912003-12-29 02:52:11 +0000185/*
186 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
187 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000188static const char *xmlXPathErrorMessages[] = {
189 "Ok\n",
190 "Number encoding\n",
191 "Unfinished literal\n",
192 "Start of literal\n",
193 "Expected $ for variable reference\n",
194 "Undefined variable\n",
195 "Invalid predicate\n",
196 "Invalid expression\n",
197 "Missing closing curly brace\n",
198 "Unregistered function\n",
199 "Invalid operand\n",
200 "Invalid type\n",
201 "Invalid number of arguments\n",
202 "Invalid context size\n",
203 "Invalid context position\n",
204 "Memory allocation error\n",
205 "Syntax error\n",
206 "Resource error\n",
207 "Sub resource error\n",
208 "Undefined namespace prefix\n",
209 "Encoding error\n",
210 "Char out of XML range\n"
211};
212
213
214/**
215 * xmlXPathErrMemory:
216 * @ctxt: an XPath context
217 * @extra: extra informations
218 *
219 * Handle a redefinition of attribute error
220 */
221static void
222xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
223{
224 if (ctxt != NULL) {
225 if (extra) {
226 xmlChar buf[200];
227
228 xmlStrPrintf(buf, 200,
229 BAD_CAST "Memory allocation failed : %s\n",
230 extra);
231 ctxt->lastError.message = (char *) xmlStrdup(buf);
232 } else {
233 ctxt->lastError.message = (char *)
234 xmlStrdup(BAD_CAST "Memory allocation failed\n");
235 }
236 ctxt->lastError.domain = XML_FROM_XPATH;
237 ctxt->lastError.code = XML_ERR_NO_MEMORY;
238 if (ctxt->error != NULL)
239 ctxt->error(ctxt->userData, &ctxt->lastError);
240 } else {
241 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000242 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000243 NULL, NULL, XML_FROM_XPATH,
244 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
245 extra, NULL, NULL, 0, 0,
246 "Memory allocation failed : %s\n", extra);
247 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000248 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000249 NULL, NULL, XML_FROM_XPATH,
250 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
251 NULL, NULL, NULL, 0, 0,
252 "Memory allocation failed\n");
253 }
254}
255
256/**
Daniel Veillard8de5c0b2004-10-07 13:14:19 +0000257 * xmlXPathPErrMemory:
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000258 * @ctxt: an XPath parser context
259 * @extra: extra informations
260 *
261 * Handle a redefinition of attribute error
262 */
263static void
264xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
265{
266 ctxt->error = XPATH_MEMORY_ERROR;
267 if (ctxt == NULL)
268 xmlXPathErrMemory(NULL, extra);
269 else
270 xmlXPathErrMemory(ctxt->context, extra);
271}
272
273/**
274 * xmlXPathErr:
275 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000276 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000277 *
278 * Handle a Relax NG Parsing error
279 */
280void
281xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
282{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000283 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000284 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000285 NULL, NULL, XML_FROM_XPATH,
286 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
287 XML_ERR_ERROR, NULL, 0,
288 NULL, NULL, NULL, 0, 0,
289 xmlXPathErrorMessages[error]);
290 return;
291 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000292 ctxt->error = error;
293 if (ctxt->context == NULL) {
294 __xmlRaiseError(NULL, NULL, NULL,
295 NULL, NULL, XML_FROM_XPATH,
296 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
297 XML_ERR_ERROR, NULL, 0,
298 (const char *) ctxt->base, NULL, NULL,
299 ctxt->cur - ctxt->base, 0,
300 xmlXPathErrorMessages[error]);
301 return;
302 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000303 ctxt->context->lastError.domain = XML_FROM_XPATH;
304 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
305 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000306 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000307 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
308 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
309 ctxt->context->lastError.node = ctxt->context->debugNode;
310 if (ctxt->context->error != NULL) {
311 ctxt->context->error(ctxt->context->userData,
312 &ctxt->context->lastError);
313 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000314 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000315 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
316 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
317 XML_ERR_ERROR, NULL, 0,
318 (const char *) ctxt->base, NULL, NULL,
319 ctxt->cur - ctxt->base, 0,
320 xmlXPathErrorMessages[error]);
321 }
322
323}
324
325/**
326 * xmlXPatherror:
327 * @ctxt: the XPath Parser context
328 * @file: the file name
329 * @line: the line number
330 * @no: the error number
331 *
332 * Formats an error message.
333 */
334void
335xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
336 int line ATTRIBUTE_UNUSED, int no) {
337 xmlXPathErr(ctxt, no);
338}
339
340
341/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000342 * *
343 * Parser Types *
344 * *
345 ************************************************************************/
346
347/*
348 * Types are private:
349 */
350
351typedef enum {
352 XPATH_OP_END=0,
353 XPATH_OP_AND,
354 XPATH_OP_OR,
355 XPATH_OP_EQUAL,
356 XPATH_OP_CMP,
357 XPATH_OP_PLUS,
358 XPATH_OP_MULT,
359 XPATH_OP_UNION,
360 XPATH_OP_ROOT,
361 XPATH_OP_NODE,
362 XPATH_OP_RESET,
363 XPATH_OP_COLLECT,
364 XPATH_OP_VALUE,
365 XPATH_OP_VARIABLE,
366 XPATH_OP_FUNCTION,
367 XPATH_OP_ARG,
368 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000369 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000370 XPATH_OP_SORT
371#ifdef LIBXML_XPTR_ENABLED
372 ,XPATH_OP_RANGETO
373#endif
374} xmlXPathOp;
375
376typedef enum {
377 AXIS_ANCESTOR = 1,
378 AXIS_ANCESTOR_OR_SELF,
379 AXIS_ATTRIBUTE,
380 AXIS_CHILD,
381 AXIS_DESCENDANT,
382 AXIS_DESCENDANT_OR_SELF,
383 AXIS_FOLLOWING,
384 AXIS_FOLLOWING_SIBLING,
385 AXIS_NAMESPACE,
386 AXIS_PARENT,
387 AXIS_PRECEDING,
388 AXIS_PRECEDING_SIBLING,
389 AXIS_SELF
390} xmlXPathAxisVal;
391
392typedef enum {
393 NODE_TEST_NONE = 0,
394 NODE_TEST_TYPE = 1,
395 NODE_TEST_PI = 2,
396 NODE_TEST_ALL = 3,
397 NODE_TEST_NS = 4,
398 NODE_TEST_NAME = 5
399} xmlXPathTestVal;
400
401typedef enum {
402 NODE_TYPE_NODE = 0,
403 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
404 NODE_TYPE_TEXT = XML_TEXT_NODE,
405 NODE_TYPE_PI = XML_PI_NODE
406} xmlXPathTypeVal;
407
408
409typedef struct _xmlXPathStepOp xmlXPathStepOp;
410typedef xmlXPathStepOp *xmlXPathStepOpPtr;
411struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000412 xmlXPathOp op; /* The identifier of the operation */
413 int ch1; /* First child */
414 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000415 int value;
416 int value2;
417 int value3;
418 void *value4;
419 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000420 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000421 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000422};
423
424struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000425 int nbStep; /* Number of steps in this expression */
426 int maxStep; /* Maximum number of steps allocated */
427 xmlXPathStepOp *steps; /* ops for computation of this expression */
428 int last; /* index of last step in expression */
429 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000430 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000431#ifdef DEBUG_EVAL_COUNTS
432 int nb;
433 xmlChar *string;
434#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000435};
436
437/************************************************************************
438 * *
439 * Parser Type functions *
440 * *
441 ************************************************************************/
442
443/**
444 * xmlXPathNewCompExpr:
445 *
446 * Create a new Xpath component
447 *
448 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
449 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000450static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000451xmlXPathNewCompExpr(void) {
452 xmlXPathCompExprPtr cur;
453
454 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
455 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000456 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000457 return(NULL);
458 }
459 memset(cur, 0, sizeof(xmlXPathCompExpr));
460 cur->maxStep = 10;
461 cur->nbStep = 0;
462 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
463 sizeof(xmlXPathStepOp));
464 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000465 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000466 xmlFree(cur);
467 return(NULL);
468 }
469 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
470 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000471#ifdef DEBUG_EVAL_COUNTS
472 cur->nb = 0;
473#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000474 return(cur);
475}
476
477/**
478 * xmlXPathFreeCompExpr:
479 * @comp: an XPATH comp
480 *
481 * Free up the memory allocated by @comp
482 */
483void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000484xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
485{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000486 xmlXPathStepOpPtr op;
487 int i;
488
489 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000490 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000491 if (comp->dict == NULL) {
492 for (i = 0; i < comp->nbStep; i++) {
493 op = &comp->steps[i];
494 if (op->value4 != NULL) {
495 if (op->op == XPATH_OP_VALUE)
496 xmlXPathFreeObject(op->value4);
497 else
498 xmlFree(op->value4);
499 }
500 if (op->value5 != NULL)
501 xmlFree(op->value5);
502 }
503 } else {
504 for (i = 0; i < comp->nbStep; i++) {
505 op = &comp->steps[i];
506 if (op->value4 != NULL) {
507 if (op->op == XPATH_OP_VALUE)
508 xmlXPathFreeObject(op->value4);
509 }
510 }
511 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000512 }
513 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000514 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000515 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000516#ifdef DEBUG_EVAL_COUNTS
517 if (comp->string != NULL) {
518 xmlFree(comp->string);
519 }
520#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000521 if (comp->expr != NULL) {
522 xmlFree(comp->expr);
523 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000524
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000525 xmlFree(comp);
526}
527
528/**
529 * xmlXPathCompExprAdd:
530 * @comp: the compiled expression
531 * @ch1: first child index
532 * @ch2: second child index
533 * @op: an op
534 * @value: the first int value
535 * @value2: the second int value
536 * @value3: the third int value
537 * @value4: the first string value
538 * @value5: the second string value
539 *
William M. Brack08171912003-12-29 02:52:11 +0000540 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000541 *
542 * Returns -1 in case of failure, the index otherwise
543 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000544static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000545xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
546 xmlXPathOp op, int value,
547 int value2, int value3, void *value4, void *value5) {
548 if (comp->nbStep >= comp->maxStep) {
549 xmlXPathStepOp *real;
550
551 comp->maxStep *= 2;
552 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
553 comp->maxStep * sizeof(xmlXPathStepOp));
554 if (real == NULL) {
555 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000556 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000557 return(-1);
558 }
559 comp->steps = real;
560 }
561 comp->last = comp->nbStep;
562 comp->steps[comp->nbStep].ch1 = ch1;
563 comp->steps[comp->nbStep].ch2 = ch2;
564 comp->steps[comp->nbStep].op = op;
565 comp->steps[comp->nbStep].value = value;
566 comp->steps[comp->nbStep].value2 = value2;
567 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000568 if ((comp->dict != NULL) &&
569 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
570 (op == XPATH_OP_COLLECT))) {
571 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000572 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000573 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000574 xmlFree(value4);
575 } else
576 comp->steps[comp->nbStep].value4 = NULL;
577 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000578 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000579 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000580 xmlFree(value5);
581 } else
582 comp->steps[comp->nbStep].value5 = NULL;
583 } else {
584 comp->steps[comp->nbStep].value4 = value4;
585 comp->steps[comp->nbStep].value5 = value5;
586 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000587 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000588 return(comp->nbStep++);
589}
590
Daniel Veillardf06307e2001-07-03 10:35:50 +0000591/**
592 * xmlXPathCompSwap:
593 * @comp: the compiled expression
594 * @op: operation index
595 *
596 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000597 */
598static void
599xmlXPathCompSwap(xmlXPathStepOpPtr op) {
600 int tmp;
601
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000602#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000603 /*
604 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000605 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000606 * application
607 */
608 if (xmlXPathDisableOptimizer)
609 return;
610#endif
611
Daniel Veillardf06307e2001-07-03 10:35:50 +0000612 tmp = op->ch1;
613 op->ch1 = op->ch2;
614 op->ch2 = tmp;
615}
616
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000617#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
618 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
619 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000620#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
621 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
622 (op), (val), (val2), (val3), (val4), (val5))
623
624#define PUSH_LEAVE_EXPR(op, val, val2) \
625xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
626
627#define PUSH_UNARY_EXPR(op, ch, val, val2) \
628xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
629
630#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000631xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
632 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000633
634/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000635 * *
636 * Debugging related functions *
637 * *
638 ************************************************************************/
639
Owen Taylor3473f882001-02-23 17:55:21 +0000640#define STRANGE \
641 xmlGenericError(xmlGenericErrorContext, \
642 "Internal error at %s:%d\n", \
643 __FILE__, __LINE__);
644
645#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000646static void
647xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000648 int i;
649 char shift[100];
650
651 for (i = 0;((i < depth) && (i < 25));i++)
652 shift[2 * i] = shift[2 * i + 1] = ' ';
653 shift[2 * i] = shift[2 * i + 1] = 0;
654 if (cur == NULL) {
655 fprintf(output, shift);
656 fprintf(output, "Node is NULL !\n");
657 return;
658
659 }
660
661 if ((cur->type == XML_DOCUMENT_NODE) ||
662 (cur->type == XML_HTML_DOCUMENT_NODE)) {
663 fprintf(output, shift);
664 fprintf(output, " /\n");
665 } else if (cur->type == XML_ATTRIBUTE_NODE)
666 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
667 else
668 xmlDebugDumpOneNode(output, cur, depth);
669}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000670static void
671xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000672 xmlNodePtr tmp;
673 int i;
674 char shift[100];
675
676 for (i = 0;((i < depth) && (i < 25));i++)
677 shift[2 * i] = shift[2 * i + 1] = ' ';
678 shift[2 * i] = shift[2 * i + 1] = 0;
679 if (cur == NULL) {
680 fprintf(output, shift);
681 fprintf(output, "Node is NULL !\n");
682 return;
683
684 }
685
686 while (cur != NULL) {
687 tmp = cur;
688 cur = cur->next;
689 xmlDebugDumpOneNode(output, tmp, depth);
690 }
691}
Owen Taylor3473f882001-02-23 17:55:21 +0000692
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000693static void
694xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000695 int i;
696 char shift[100];
697
698 for (i = 0;((i < depth) && (i < 25));i++)
699 shift[2 * i] = shift[2 * i + 1] = ' ';
700 shift[2 * i] = shift[2 * i + 1] = 0;
701
702 if (cur == NULL) {
703 fprintf(output, shift);
704 fprintf(output, "NodeSet is NULL !\n");
705 return;
706
707 }
708
Daniel Veillard911f49a2001-04-07 15:39:35 +0000709 if (cur != NULL) {
710 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
711 for (i = 0;i < cur->nodeNr;i++) {
712 fprintf(output, shift);
713 fprintf(output, "%d", i + 1);
714 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
715 }
Owen Taylor3473f882001-02-23 17:55:21 +0000716 }
717}
718
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000719static void
720xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000721 int i;
722 char shift[100];
723
724 for (i = 0;((i < depth) && (i < 25));i++)
725 shift[2 * i] = shift[2 * i + 1] = ' ';
726 shift[2 * i] = shift[2 * i + 1] = 0;
727
728 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
729 fprintf(output, shift);
730 fprintf(output, "Value Tree is NULL !\n");
731 return;
732
733 }
734
735 fprintf(output, shift);
736 fprintf(output, "%d", i + 1);
737 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
738}
Owen Taylor3473f882001-02-23 17:55:21 +0000739#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000740static void
741xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000742 int i;
743 char shift[100];
744
745 for (i = 0;((i < depth) && (i < 25));i++)
746 shift[2 * i] = shift[2 * i + 1] = ' ';
747 shift[2 * i] = shift[2 * i + 1] = 0;
748
749 if (cur == NULL) {
750 fprintf(output, shift);
751 fprintf(output, "LocationSet is NULL !\n");
752 return;
753
754 }
755
756 for (i = 0;i < cur->locNr;i++) {
757 fprintf(output, shift);
758 fprintf(output, "%d : ", i + 1);
759 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
760 }
761}
Daniel Veillard017b1082001-06-21 11:20:21 +0000762#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000763
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000764/**
765 * xmlXPathDebugDumpObject:
766 * @output: the FILE * to dump the output
767 * @cur: the object to inspect
768 * @depth: indentation level
769 *
770 * Dump the content of the object for debugging purposes
771 */
772void
773xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000774 int i;
775 char shift[100];
776
777 for (i = 0;((i < depth) && (i < 25));i++)
778 shift[2 * i] = shift[2 * i + 1] = ' ';
779 shift[2 * i] = shift[2 * i + 1] = 0;
780
781 fprintf(output, shift);
782
783 if (cur == NULL) {
784 fprintf(output, "Object is empty (NULL)\n");
785 return;
786 }
787 switch(cur->type) {
788 case XPATH_UNDEFINED:
789 fprintf(output, "Object is uninitialized\n");
790 break;
791 case XPATH_NODESET:
792 fprintf(output, "Object is a Node Set :\n");
793 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
794 break;
795 case XPATH_XSLT_TREE:
796 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000797 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000798 break;
799 case XPATH_BOOLEAN:
800 fprintf(output, "Object is a Boolean : ");
801 if (cur->boolval) fprintf(output, "true\n");
802 else fprintf(output, "false\n");
803 break;
804 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000805 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000806 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000807 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000808 break;
809 case -1:
810 fprintf(output, "Object is a number : -Infinity\n");
811 break;
812 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000813 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000814 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000815 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
816 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000817 } else {
818 fprintf(output, "Object is a number : %0g\n", cur->floatval);
819 }
820 }
Owen Taylor3473f882001-02-23 17:55:21 +0000821 break;
822 case XPATH_STRING:
823 fprintf(output, "Object is a string : ");
824 xmlDebugDumpString(output, cur->stringval);
825 fprintf(output, "\n");
826 break;
827 case XPATH_POINT:
828 fprintf(output, "Object is a point : index %d in node", cur->index);
829 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
830 fprintf(output, "\n");
831 break;
832 case XPATH_RANGE:
833 if ((cur->user2 == NULL) ||
834 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
835 fprintf(output, "Object is a collapsed range :\n");
836 fprintf(output, shift);
837 if (cur->index >= 0)
838 fprintf(output, "index %d in ", cur->index);
839 fprintf(output, "node\n");
840 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
841 depth + 1);
842 } else {
843 fprintf(output, "Object is a range :\n");
844 fprintf(output, shift);
845 fprintf(output, "From ");
846 if (cur->index >= 0)
847 fprintf(output, "index %d in ", cur->index);
848 fprintf(output, "node\n");
849 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
850 depth + 1);
851 fprintf(output, shift);
852 fprintf(output, "To ");
853 if (cur->index2 >= 0)
854 fprintf(output, "index %d in ", cur->index2);
855 fprintf(output, "node\n");
856 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
857 depth + 1);
858 fprintf(output, "\n");
859 }
860 break;
861 case XPATH_LOCATIONSET:
862#if defined(LIBXML_XPTR_ENABLED)
863 fprintf(output, "Object is a Location Set:\n");
864 xmlXPathDebugDumpLocationSet(output,
865 (xmlLocationSetPtr) cur->user, depth);
866#endif
867 break;
868 case XPATH_USERS:
869 fprintf(output, "Object is user defined\n");
870 break;
871 }
872}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000873
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000874static void
875xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000876 xmlXPathStepOpPtr op, int depth) {
877 int i;
878 char shift[100];
879
880 for (i = 0;((i < depth) && (i < 25));i++)
881 shift[2 * i] = shift[2 * i + 1] = ' ';
882 shift[2 * i] = shift[2 * i + 1] = 0;
883
884 fprintf(output, shift);
885 if (op == NULL) {
886 fprintf(output, "Step is NULL\n");
887 return;
888 }
889 switch (op->op) {
890 case XPATH_OP_END:
891 fprintf(output, "END"); break;
892 case XPATH_OP_AND:
893 fprintf(output, "AND"); break;
894 case XPATH_OP_OR:
895 fprintf(output, "OR"); break;
896 case XPATH_OP_EQUAL:
897 if (op->value)
898 fprintf(output, "EQUAL =");
899 else
900 fprintf(output, "EQUAL !=");
901 break;
902 case XPATH_OP_CMP:
903 if (op->value)
904 fprintf(output, "CMP <");
905 else
906 fprintf(output, "CMP >");
907 if (!op->value2)
908 fprintf(output, "=");
909 break;
910 case XPATH_OP_PLUS:
911 if (op->value == 0)
912 fprintf(output, "PLUS -");
913 else if (op->value == 1)
914 fprintf(output, "PLUS +");
915 else if (op->value == 2)
916 fprintf(output, "PLUS unary -");
917 else if (op->value == 3)
918 fprintf(output, "PLUS unary - -");
919 break;
920 case XPATH_OP_MULT:
921 if (op->value == 0)
922 fprintf(output, "MULT *");
923 else if (op->value == 1)
924 fprintf(output, "MULT div");
925 else
926 fprintf(output, "MULT mod");
927 break;
928 case XPATH_OP_UNION:
929 fprintf(output, "UNION"); break;
930 case XPATH_OP_ROOT:
931 fprintf(output, "ROOT"); break;
932 case XPATH_OP_NODE:
933 fprintf(output, "NODE"); break;
934 case XPATH_OP_RESET:
935 fprintf(output, "RESET"); break;
936 case XPATH_OP_SORT:
937 fprintf(output, "SORT"); break;
938 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000939 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
940 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
941 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000942 const xmlChar *prefix = op->value4;
943 const xmlChar *name = op->value5;
944
945 fprintf(output, "COLLECT ");
946 switch (axis) {
947 case AXIS_ANCESTOR:
948 fprintf(output, " 'ancestors' "); break;
949 case AXIS_ANCESTOR_OR_SELF:
950 fprintf(output, " 'ancestors-or-self' "); break;
951 case AXIS_ATTRIBUTE:
952 fprintf(output, " 'attributes' "); break;
953 case AXIS_CHILD:
954 fprintf(output, " 'child' "); break;
955 case AXIS_DESCENDANT:
956 fprintf(output, " 'descendant' "); break;
957 case AXIS_DESCENDANT_OR_SELF:
958 fprintf(output, " 'descendant-or-self' "); break;
959 case AXIS_FOLLOWING:
960 fprintf(output, " 'following' "); break;
961 case AXIS_FOLLOWING_SIBLING:
962 fprintf(output, " 'following-siblings' "); break;
963 case AXIS_NAMESPACE:
964 fprintf(output, " 'namespace' "); break;
965 case AXIS_PARENT:
966 fprintf(output, " 'parent' "); break;
967 case AXIS_PRECEDING:
968 fprintf(output, " 'preceding' "); break;
969 case AXIS_PRECEDING_SIBLING:
970 fprintf(output, " 'preceding-sibling' "); break;
971 case AXIS_SELF:
972 fprintf(output, " 'self' "); break;
973 }
974 switch (test) {
975 case NODE_TEST_NONE:
976 fprintf(output, "'none' "); break;
977 case NODE_TEST_TYPE:
978 fprintf(output, "'type' "); break;
979 case NODE_TEST_PI:
980 fprintf(output, "'PI' "); break;
981 case NODE_TEST_ALL:
982 fprintf(output, "'all' "); break;
983 case NODE_TEST_NS:
984 fprintf(output, "'namespace' "); break;
985 case NODE_TEST_NAME:
986 fprintf(output, "'name' "); break;
987 }
988 switch (type) {
989 case NODE_TYPE_NODE:
990 fprintf(output, "'node' "); break;
991 case NODE_TYPE_COMMENT:
992 fprintf(output, "'comment' "); break;
993 case NODE_TYPE_TEXT:
994 fprintf(output, "'text' "); break;
995 case NODE_TYPE_PI:
996 fprintf(output, "'PI' "); break;
997 }
998 if (prefix != NULL)
999 fprintf(output, "%s:", prefix);
1000 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +00001001 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001002 break;
1003
1004 }
1005 case XPATH_OP_VALUE: {
1006 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1007
1008 fprintf(output, "ELEM ");
1009 xmlXPathDebugDumpObject(output, object, 0);
1010 goto finish;
1011 }
1012 case XPATH_OP_VARIABLE: {
1013 const xmlChar *prefix = op->value5;
1014 const xmlChar *name = op->value4;
1015
1016 if (prefix != NULL)
1017 fprintf(output, "VARIABLE %s:%s", prefix, name);
1018 else
1019 fprintf(output, "VARIABLE %s", name);
1020 break;
1021 }
1022 case XPATH_OP_FUNCTION: {
1023 int nbargs = op->value;
1024 const xmlChar *prefix = op->value5;
1025 const xmlChar *name = op->value4;
1026
1027 if (prefix != NULL)
1028 fprintf(output, "FUNCTION %s:%s(%d args)",
1029 prefix, name, nbargs);
1030 else
1031 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1032 break;
1033 }
1034 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1035 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001036 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001037#ifdef LIBXML_XPTR_ENABLED
1038 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1039#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001040 default:
1041 fprintf(output, "UNKNOWN %d\n", op->op); return;
1042 }
1043 fprintf(output, "\n");
1044finish:
1045 if (op->ch1 >= 0)
1046 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1047 if (op->ch2 >= 0)
1048 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1049}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001050
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001051/**
1052 * xmlXPathDebugDumpCompExpr:
1053 * @output: the FILE * for the output
1054 * @comp: the precompiled XPath expression
1055 * @depth: the indentation level.
1056 *
1057 * Dumps the tree of the compiled XPath expression.
1058 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001059void
1060xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1061 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001062 int i;
1063 char shift[100];
1064
1065 for (i = 0;((i < depth) && (i < 25));i++)
1066 shift[2 * i] = shift[2 * i + 1] = ' ';
1067 shift[2 * i] = shift[2 * i + 1] = 0;
1068
1069 fprintf(output, shift);
1070
1071 if (comp == NULL) {
1072 fprintf(output, "Compiled Expression is NULL\n");
1073 return;
1074 }
1075 fprintf(output, "Compiled Expression : %d elements\n",
1076 comp->nbStep);
1077 i = comp->last;
1078 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1079}
Daniel Veillard017b1082001-06-21 11:20:21 +00001080#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001081
1082/************************************************************************
1083 * *
1084 * Parser stacks related functions and macros *
1085 * *
1086 ************************************************************************/
1087
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001088/**
1089 * valuePop:
1090 * @ctxt: an XPath evaluation context
1091 *
1092 * Pops the top XPath object from the value stack
1093 *
1094 * Returns the XPath object just removed
1095 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001096extern xmlXPathObjectPtr
1097valuePop(xmlXPathParserContextPtr ctxt)
1098{
1099 xmlXPathObjectPtr ret;
1100
1101 if (ctxt->valueNr <= 0)
1102 return (0);
1103 ctxt->valueNr--;
1104 if (ctxt->valueNr > 0)
1105 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1106 else
1107 ctxt->value = NULL;
1108 ret = ctxt->valueTab[ctxt->valueNr];
1109 ctxt->valueTab[ctxt->valueNr] = 0;
1110 return (ret);
1111}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001112/**
1113 * valuePush:
1114 * @ctxt: an XPath evaluation context
1115 * @value: the XPath object
1116 *
1117 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001118 *
1119 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001120 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001121extern int
1122valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1123{
1124 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001125 xmlXPathObjectPtr *tmp;
1126
1127 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1128 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001129 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001130 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001131 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1132 return (0);
1133 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001134 ctxt->valueMax *= 2;
1135 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001136 }
1137 ctxt->valueTab[ctxt->valueNr] = value;
1138 ctxt->value = value;
1139 return (ctxt->valueNr++);
1140}
Owen Taylor3473f882001-02-23 17:55:21 +00001141
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001142/**
1143 * xmlXPathPopBoolean:
1144 * @ctxt: an XPath parser context
1145 *
1146 * Pops a boolean from the stack, handling conversion if needed.
1147 * Check error with #xmlXPathCheckError.
1148 *
1149 * Returns the boolean
1150 */
1151int
1152xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1153 xmlXPathObjectPtr obj;
1154 int ret;
1155
1156 obj = valuePop(ctxt);
1157 if (obj == NULL) {
1158 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1159 return(0);
1160 }
William M. Brack08171912003-12-29 02:52:11 +00001161 if (obj->type != XPATH_BOOLEAN)
1162 ret = xmlXPathCastToBoolean(obj);
1163 else
1164 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001165 xmlXPathFreeObject(obj);
1166 return(ret);
1167}
1168
1169/**
1170 * xmlXPathPopNumber:
1171 * @ctxt: an XPath parser context
1172 *
1173 * Pops a number from the stack, handling conversion if needed.
1174 * Check error with #xmlXPathCheckError.
1175 *
1176 * Returns the number
1177 */
1178double
1179xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1180 xmlXPathObjectPtr obj;
1181 double ret;
1182
1183 obj = valuePop(ctxt);
1184 if (obj == NULL) {
1185 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1186 return(0);
1187 }
William M. Brack08171912003-12-29 02:52:11 +00001188 if (obj->type != XPATH_NUMBER)
1189 ret = xmlXPathCastToNumber(obj);
1190 else
1191 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001192 xmlXPathFreeObject(obj);
1193 return(ret);
1194}
1195
1196/**
1197 * xmlXPathPopString:
1198 * @ctxt: an XPath parser context
1199 *
1200 * Pops a string from the stack, handling conversion if needed.
1201 * Check error with #xmlXPathCheckError.
1202 *
1203 * Returns the string
1204 */
1205xmlChar *
1206xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1207 xmlXPathObjectPtr obj;
1208 xmlChar * ret;
1209
1210 obj = valuePop(ctxt);
1211 if (obj == NULL) {
1212 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1213 return(NULL);
1214 }
William M. Brack08171912003-12-29 02:52:11 +00001215 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001216 /* TODO: needs refactoring somewhere else */
1217 if (obj->stringval == ret)
1218 obj->stringval = NULL;
1219 xmlXPathFreeObject(obj);
1220 return(ret);
1221}
1222
1223/**
1224 * xmlXPathPopNodeSet:
1225 * @ctxt: an XPath parser context
1226 *
1227 * Pops a node-set from the stack, handling conversion if needed.
1228 * Check error with #xmlXPathCheckError.
1229 *
1230 * Returns the node-set
1231 */
1232xmlNodeSetPtr
1233xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1234 xmlXPathObjectPtr obj;
1235 xmlNodeSetPtr ret;
1236
1237 if (ctxt->value == NULL) {
1238 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1239 return(NULL);
1240 }
1241 if (!xmlXPathStackIsNodeSet(ctxt)) {
1242 xmlXPathSetTypeError(ctxt);
1243 return(NULL);
1244 }
1245 obj = valuePop(ctxt);
1246 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001247#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001248 /* to fix memory leak of not clearing obj->user */
1249 if (obj->boolval && obj->user != NULL)
1250 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001251#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001252 xmlXPathFreeNodeSetList(obj);
1253 return(ret);
1254}
1255
1256/**
1257 * xmlXPathPopExternal:
1258 * @ctxt: an XPath parser context
1259 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001260 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001261 * Check error with #xmlXPathCheckError.
1262 *
1263 * Returns the object
1264 */
1265void *
1266xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1267 xmlXPathObjectPtr obj;
1268 void * ret;
1269
1270 if (ctxt->value == NULL) {
1271 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1272 return(NULL);
1273 }
1274 if (ctxt->value->type != XPATH_USERS) {
1275 xmlXPathSetTypeError(ctxt);
1276 return(NULL);
1277 }
1278 obj = valuePop(ctxt);
1279 ret = obj->user;
1280 xmlXPathFreeObject(obj);
1281 return(ret);
1282}
1283
Owen Taylor3473f882001-02-23 17:55:21 +00001284/*
1285 * Macros for accessing the content. Those should be used only by the parser,
1286 * and not exported.
1287 *
1288 * Dirty macros, i.e. one need to make assumption on the context to use them
1289 *
1290 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1291 * CUR returns the current xmlChar value, i.e. a 8 bit value
1292 * in ISO-Latin or UTF-8.
1293 * This should be used internally by the parser
1294 * only to compare to ASCII values otherwise it would break when
1295 * running with UTF-8 encoding.
1296 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1297 * to compare on ASCII based substring.
1298 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1299 * strings within the parser.
1300 * CURRENT Returns the current char value, with the full decoding of
1301 * UTF-8 if we are using this mode. It returns an int.
1302 * NEXT Skip to the next character, this does the proper decoding
1303 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1304 * It returns the pointer to the current xmlChar.
1305 */
1306
1307#define CUR (*ctxt->cur)
1308#define SKIP(val) ctxt->cur += (val)
1309#define NXT(val) ctxt->cur[(val)]
1310#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001311#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1312
1313#define COPY_BUF(l,b,i,v) \
1314 if (l == 1) b[i++] = (xmlChar) v; \
1315 else i += xmlCopyChar(l,&b[i],v)
1316
1317#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001318
1319#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001320 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001321
1322#define CURRENT (*ctxt->cur)
1323#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1324
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001325
1326#ifndef DBL_DIG
1327#define DBL_DIG 16
1328#endif
1329#ifndef DBL_EPSILON
1330#define DBL_EPSILON 1E-9
1331#endif
1332
1333#define UPPER_DOUBLE 1E9
1334#define LOWER_DOUBLE 1E-5
1335
1336#define INTEGER_DIGITS DBL_DIG
1337#define FRACTION_DIGITS (DBL_DIG + 1)
1338#define EXPONENT_DIGITS (3 + 2)
1339
1340/**
1341 * xmlXPathFormatNumber:
1342 * @number: number to format
1343 * @buffer: output buffer
1344 * @buffersize: size of output buffer
1345 *
1346 * Convert the number into a string representation.
1347 */
1348static void
1349xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1350{
Daniel Veillardcda96922001-08-21 10:56:31 +00001351 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001352 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001353 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001354 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001355 break;
1356 case -1:
1357 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001358 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001359 break;
1360 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001361 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001362 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001363 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001364 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001365 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001366 } else if (number == ((int) number)) {
1367 char work[30];
1368 char *ptr, *cur;
1369 int res, value = (int) number;
1370
1371 ptr = &buffer[0];
1372 if (value < 0) {
1373 *ptr++ = '-';
1374 value = -value;
1375 }
1376 if (value == 0) {
1377 *ptr++ = '0';
1378 } else {
1379 cur = &work[0];
1380 while (value != 0) {
1381 res = value % 10;
1382 value = value / 10;
1383 *cur++ = '0' + res;
1384 }
1385 cur--;
1386 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1387 *ptr++ = *cur--;
1388 }
1389 }
1390 if (ptr - buffer < buffersize) {
1391 *ptr = 0;
1392 } else if (buffersize > 0) {
1393 ptr--;
1394 *ptr = 0;
1395 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001396 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001397 /* 3 is sign, decimal point, and terminating zero */
1398 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1399 int integer_place, fraction_place;
1400 char *ptr;
1401 char *after_fraction;
1402 double absolute_value;
1403 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001404
Bjorn Reese70a9da52001-04-21 16:57:29 +00001405 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001406
Bjorn Reese70a9da52001-04-21 16:57:29 +00001407 /*
1408 * First choose format - scientific or regular floating point.
1409 * In either case, result is in work, and after_fraction points
1410 * just past the fractional part.
1411 */
1412 if ( ((absolute_value > UPPER_DOUBLE) ||
1413 (absolute_value < LOWER_DOUBLE)) &&
1414 (absolute_value != 0.0) ) {
1415 /* Use scientific notation */
1416 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1417 fraction_place = DBL_DIG - 1;
1418 snprintf(work, sizeof(work),"%*.*e",
1419 integer_place, fraction_place, number);
1420 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001421 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001422 else {
1423 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001424 if (absolute_value > 0.0)
1425 integer_place = 1 + (int)log10(absolute_value);
1426 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001427 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001428 fraction_place = (integer_place > 0)
1429 ? DBL_DIG - integer_place
1430 : DBL_DIG;
1431 size = snprintf(work, sizeof(work), "%0.*f",
1432 fraction_place, number);
1433 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001434 }
1435
Bjorn Reese70a9da52001-04-21 16:57:29 +00001436 /* Remove fractional trailing zeroes */
1437 ptr = after_fraction;
1438 while (*(--ptr) == '0')
1439 ;
1440 if (*ptr != '.')
1441 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001442 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001443
1444 /* Finally copy result back to caller */
1445 size = strlen(work) + 1;
1446 if (size > buffersize) {
1447 work[buffersize - 1] = 0;
1448 size = buffersize;
1449 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001450 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001451 }
1452 break;
1453 }
1454}
1455
Owen Taylor3473f882001-02-23 17:55:21 +00001456
1457/************************************************************************
1458 * *
1459 * Routines to handle NodeSets *
1460 * *
1461 ************************************************************************/
1462
1463/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001464 * xmlXPathOrderDocElems:
1465 * @doc: an input document
1466 *
1467 * Call this routine to speed up XPath computation on static documents.
1468 * This stamps all the element nodes with the document order
1469 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001470 * field, the value stored is actually - the node number (starting at -1)
1471 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001472 *
William M. Brack08171912003-12-29 02:52:11 +00001473 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001474 * of error.
1475 */
1476long
1477xmlXPathOrderDocElems(xmlDocPtr doc) {
1478 long count = 0;
1479 xmlNodePtr cur;
1480
1481 if (doc == NULL)
1482 return(-1);
1483 cur = doc->children;
1484 while (cur != NULL) {
1485 if (cur->type == XML_ELEMENT_NODE) {
1486 cur->content = (void *) (-(++count));
1487 if (cur->children != NULL) {
1488 cur = cur->children;
1489 continue;
1490 }
1491 }
1492 if (cur->next != NULL) {
1493 cur = cur->next;
1494 continue;
1495 }
1496 do {
1497 cur = cur->parent;
1498 if (cur == NULL)
1499 break;
1500 if (cur == (xmlNodePtr) doc) {
1501 cur = NULL;
1502 break;
1503 }
1504 if (cur->next != NULL) {
1505 cur = cur->next;
1506 break;
1507 }
1508 } while (cur != NULL);
1509 }
1510 return(count);
1511}
1512
1513/**
Owen Taylor3473f882001-02-23 17:55:21 +00001514 * xmlXPathCmpNodes:
1515 * @node1: the first node
1516 * @node2: the second node
1517 *
1518 * Compare two nodes w.r.t document order
1519 *
1520 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001521 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001522 */
1523int
1524xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1525 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001526 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001527 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001528 xmlNodePtr cur, root;
1529
1530 if ((node1 == NULL) || (node2 == NULL))
1531 return(-2);
1532 /*
1533 * a couple of optimizations which will avoid computations in most cases
1534 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001535 if (node1->type == XML_ATTRIBUTE_NODE) {
1536 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001537 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001538 node1 = node1->parent;
1539 }
1540 if (node2->type == XML_ATTRIBUTE_NODE) {
1541 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001542 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001543 node2 = node2->parent;
1544 }
1545 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001546 if (attr1 == attr2) {
1547 /* not required, but we keep attributes in order */
1548 if (attr1 != 0) {
1549 cur = attrNode2->prev;
1550 while (cur != NULL) {
1551 if (cur == attrNode1)
1552 return (1);
1553 cur = cur->prev;
1554 }
1555 return (-1);
1556 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001557 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001558 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001559 if (attr2 == 1)
1560 return(1);
1561 return(-1);
1562 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001563 if ((node1->type == XML_NAMESPACE_DECL) ||
1564 (node2->type == XML_NAMESPACE_DECL))
1565 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001566 if (node1 == node2->prev)
1567 return(1);
1568 if (node1 == node2->next)
1569 return(-1);
1570
1571 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001572 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001573 */
1574 if ((node1->type == XML_ELEMENT_NODE) &&
1575 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001576 (0 > (long) node1->content) &&
1577 (0 > (long) node2->content) &&
1578 (node1->doc == node2->doc)) {
1579 long l1, l2;
1580
1581 l1 = -((long) node1->content);
1582 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001583 if (l1 < l2)
1584 return(1);
1585 if (l1 > l2)
1586 return(-1);
1587 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001588
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001589 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001590 * compute depth to root
1591 */
1592 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1593 if (cur == node1)
1594 return(1);
1595 depth2++;
1596 }
1597 root = cur;
1598 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1599 if (cur == node2)
1600 return(-1);
1601 depth1++;
1602 }
1603 /*
1604 * Distinct document (or distinct entities :-( ) case.
1605 */
1606 if (root != cur) {
1607 return(-2);
1608 }
1609 /*
1610 * get the nearest common ancestor.
1611 */
1612 while (depth1 > depth2) {
1613 depth1--;
1614 node1 = node1->parent;
1615 }
1616 while (depth2 > depth1) {
1617 depth2--;
1618 node2 = node2->parent;
1619 }
1620 while (node1->parent != node2->parent) {
1621 node1 = node1->parent;
1622 node2 = node2->parent;
1623 /* should not happen but just in case ... */
1624 if ((node1 == NULL) || (node2 == NULL))
1625 return(-2);
1626 }
1627 /*
1628 * Find who's first.
1629 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001630 if (node1 == node2->prev)
1631 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001632 if (node1 == node2->next)
1633 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001634 /*
1635 * Speedup using document order if availble.
1636 */
1637 if ((node1->type == XML_ELEMENT_NODE) &&
1638 (node2->type == XML_ELEMENT_NODE) &&
1639 (0 > (long) node1->content) &&
1640 (0 > (long) node2->content) &&
1641 (node1->doc == node2->doc)) {
1642 long l1, l2;
1643
1644 l1 = -((long) node1->content);
1645 l2 = -((long) node2->content);
1646 if (l1 < l2)
1647 return(1);
1648 if (l1 > l2)
1649 return(-1);
1650 }
1651
Owen Taylor3473f882001-02-23 17:55:21 +00001652 for (cur = node1->next;cur != NULL;cur = cur->next)
1653 if (cur == node2)
1654 return(1);
1655 return(-1); /* assume there is no sibling list corruption */
1656}
1657
1658/**
1659 * xmlXPathNodeSetSort:
1660 * @set: the node set
1661 *
1662 * Sort the node set in document order
1663 */
1664void
1665xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001666 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001667 xmlNodePtr tmp;
1668
1669 if (set == NULL)
1670 return;
1671
1672 /* Use Shell's sort to sort the node-set */
1673 len = set->nodeNr;
1674 for (incr = len / 2; incr > 0; incr /= 2) {
1675 for (i = incr; i < len; i++) {
1676 j = i - incr;
1677 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001678 if (xmlXPathCmpNodes(set->nodeTab[j],
1679 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001680 tmp = set->nodeTab[j];
1681 set->nodeTab[j] = set->nodeTab[j + incr];
1682 set->nodeTab[j + incr] = tmp;
1683 j -= incr;
1684 } else
1685 break;
1686 }
1687 }
1688 }
1689}
1690
1691#define XML_NODESET_DEFAULT 10
1692/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001693 * xmlXPathNodeSetDupNs:
1694 * @node: the parent node of the namespace XPath node
1695 * @ns: the libxml namespace declaration node.
1696 *
1697 * Namespace node in libxml don't match the XPath semantic. In a node set
1698 * the namespace nodes are duplicated and the next pointer is set to the
1699 * parent node in the XPath semantic.
1700 *
1701 * Returns the newly created object.
1702 */
1703static xmlNodePtr
1704xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1705 xmlNsPtr cur;
1706
1707 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1708 return(NULL);
1709 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1710 return((xmlNodePtr) ns);
1711
1712 /*
1713 * Allocate a new Namespace and fill the fields.
1714 */
1715 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1716 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001717 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001718 return(NULL);
1719 }
1720 memset(cur, 0, sizeof(xmlNs));
1721 cur->type = XML_NAMESPACE_DECL;
1722 if (ns->href != NULL)
1723 cur->href = xmlStrdup(ns->href);
1724 if (ns->prefix != NULL)
1725 cur->prefix = xmlStrdup(ns->prefix);
1726 cur->next = (xmlNsPtr) node;
1727 return((xmlNodePtr) cur);
1728}
1729
1730/**
1731 * xmlXPathNodeSetFreeNs:
1732 * @ns: the XPath namespace node found in a nodeset.
1733 *
William M. Brack08171912003-12-29 02:52:11 +00001734 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001735 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001736 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001737 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001738void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001739xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1740 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1741 return;
1742
1743 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1744 if (ns->href != NULL)
1745 xmlFree((xmlChar *)ns->href);
1746 if (ns->prefix != NULL)
1747 xmlFree((xmlChar *)ns->prefix);
1748 xmlFree(ns);
1749 }
1750}
1751
1752/**
Owen Taylor3473f882001-02-23 17:55:21 +00001753 * xmlXPathNodeSetCreate:
1754 * @val: an initial xmlNodePtr, or NULL
1755 *
1756 * Create a new xmlNodeSetPtr of type double and of value @val
1757 *
1758 * Returns the newly created object.
1759 */
1760xmlNodeSetPtr
1761xmlXPathNodeSetCreate(xmlNodePtr val) {
1762 xmlNodeSetPtr ret;
1763
1764 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1765 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001766 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001767 return(NULL);
1768 }
1769 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1770 if (val != NULL) {
1771 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1772 sizeof(xmlNodePtr));
1773 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001774 xmlXPathErrMemory(NULL, "creating nodeset\n");
1775 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001776 return(NULL);
1777 }
1778 memset(ret->nodeTab, 0 ,
1779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1780 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001781 if (val->type == XML_NAMESPACE_DECL) {
1782 xmlNsPtr ns = (xmlNsPtr) val;
1783
1784 ret->nodeTab[ret->nodeNr++] =
1785 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1786 } else
1787 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001788 }
1789 return(ret);
1790}
1791
1792/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001793 * xmlXPathNodeSetContains:
1794 * @cur: the node-set
1795 * @val: the node
1796 *
1797 * checks whether @cur contains @val
1798 *
1799 * Returns true (1) if @cur contains @val, false (0) otherwise
1800 */
1801int
1802xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1803 int i;
1804
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001805 if (val->type == XML_NAMESPACE_DECL) {
1806 for (i = 0; i < cur->nodeNr; i++) {
1807 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1808 xmlNsPtr ns1, ns2;
1809
1810 ns1 = (xmlNsPtr) val;
1811 ns2 = (xmlNsPtr) cur->nodeTab[i];
1812 if (ns1 == ns2)
1813 return(1);
1814 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1815 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1816 return(1);
1817 }
1818 }
1819 } else {
1820 for (i = 0; i < cur->nodeNr; i++) {
1821 if (cur->nodeTab[i] == val)
1822 return(1);
1823 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001824 }
1825 return(0);
1826}
1827
1828/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001829 * xmlXPathNodeSetAddNs:
1830 * @cur: the initial node set
1831 * @node: the hosting node
1832 * @ns: a the namespace node
1833 *
1834 * add a new namespace node to an existing NodeSet
1835 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001836void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001837xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1838 int i;
1839
1840 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1841 (node->type != XML_ELEMENT_NODE))
1842 return;
1843
William M. Brack08171912003-12-29 02:52:11 +00001844 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001845 /*
William M. Brack08171912003-12-29 02:52:11 +00001846 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001847 */
1848 for (i = 0;i < cur->nodeNr;i++) {
1849 if ((cur->nodeTab[i] != NULL) &&
1850 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001851 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001852 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1853 return;
1854 }
1855
1856 /*
1857 * grow the nodeTab if needed
1858 */
1859 if (cur->nodeMax == 0) {
1860 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1861 sizeof(xmlNodePtr));
1862 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001863 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001864 return;
1865 }
1866 memset(cur->nodeTab, 0 ,
1867 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1868 cur->nodeMax = XML_NODESET_DEFAULT;
1869 } else if (cur->nodeNr == cur->nodeMax) {
1870 xmlNodePtr *temp;
1871
1872 cur->nodeMax *= 2;
1873 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1874 sizeof(xmlNodePtr));
1875 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001876 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001877 return;
1878 }
1879 cur->nodeTab = temp;
1880 }
1881 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1882}
1883
1884/**
Owen Taylor3473f882001-02-23 17:55:21 +00001885 * xmlXPathNodeSetAdd:
1886 * @cur: the initial node set
1887 * @val: a new xmlNodePtr
1888 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001889 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001890 */
1891void
1892xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1893 int i;
1894
1895 if (val == NULL) return;
1896
Daniel Veillardef0b4502003-03-24 13:57:34 +00001897#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001898 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1899 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001900#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001901
William M. Brack08171912003-12-29 02:52:11 +00001902 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001903 /*
William M. Brack08171912003-12-29 02:52:11 +00001904 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001905 */
1906 for (i = 0;i < cur->nodeNr;i++)
1907 if (cur->nodeTab[i] == val) return;
1908
1909 /*
1910 * grow the nodeTab if needed
1911 */
1912 if (cur->nodeMax == 0) {
1913 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1914 sizeof(xmlNodePtr));
1915 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001916 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001917 return;
1918 }
1919 memset(cur->nodeTab, 0 ,
1920 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1921 cur->nodeMax = XML_NODESET_DEFAULT;
1922 } else if (cur->nodeNr == cur->nodeMax) {
1923 xmlNodePtr *temp;
1924
1925 cur->nodeMax *= 2;
1926 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1927 sizeof(xmlNodePtr));
1928 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001929 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001930 return;
1931 }
1932 cur->nodeTab = temp;
1933 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001934 if (val->type == XML_NAMESPACE_DECL) {
1935 xmlNsPtr ns = (xmlNsPtr) val;
1936
1937 cur->nodeTab[cur->nodeNr++] =
1938 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1939 } else
1940 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001941}
1942
1943/**
1944 * xmlXPathNodeSetAddUnique:
1945 * @cur: the initial node set
1946 * @val: a new xmlNodePtr
1947 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001948 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001949 * when we are sure the node is not already in the set.
1950 */
1951void
1952xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1953 if (val == NULL) return;
1954
Daniel Veillardef0b4502003-03-24 13:57:34 +00001955#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001956 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1957 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001958#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001959
William M. Brack08171912003-12-29 02:52:11 +00001960 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001961 /*
1962 * grow the nodeTab if needed
1963 */
1964 if (cur->nodeMax == 0) {
1965 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1966 sizeof(xmlNodePtr));
1967 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001968 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001969 return;
1970 }
1971 memset(cur->nodeTab, 0 ,
1972 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1973 cur->nodeMax = XML_NODESET_DEFAULT;
1974 } else if (cur->nodeNr == cur->nodeMax) {
1975 xmlNodePtr *temp;
1976
1977 cur->nodeMax *= 2;
1978 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1979 sizeof(xmlNodePtr));
1980 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001981 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001982 return;
1983 }
1984 cur->nodeTab = temp;
1985 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001986 if (val->type == XML_NAMESPACE_DECL) {
1987 xmlNsPtr ns = (xmlNsPtr) val;
1988
1989 cur->nodeTab[cur->nodeNr++] =
1990 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1991 } else
1992 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001993}
1994
1995/**
1996 * xmlXPathNodeSetMerge:
1997 * @val1: the first NodeSet or NULL
1998 * @val2: the second NodeSet
1999 *
2000 * Merges two nodesets, all nodes from @val2 are added to @val1
2001 * if @val1 is NULL, a new set is created and copied from @val2
2002 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002003 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00002004 */
2005xmlNodeSetPtr
2006xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002007 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002008
2009 if (val2 == NULL) return(val1);
2010 if (val1 == NULL) {
2011 val1 = xmlXPathNodeSetCreate(NULL);
2012 }
2013
William M. Brack08171912003-12-29 02:52:11 +00002014 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002015 initNr = val1->nodeNr;
2016
2017 for (i = 0;i < val2->nodeNr;i++) {
2018 /*
William M. Brack08171912003-12-29 02:52:11 +00002019 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002020 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002021 skip = 0;
2022 for (j = 0; j < initNr; j++) {
2023 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2024 skip = 1;
2025 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002026 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2027 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2028 xmlNsPtr ns1, ns2;
2029 ns1 = (xmlNsPtr) val1->nodeTab[j];
2030 ns2 = (xmlNsPtr) val2->nodeTab[i];
2031 if ((ns1->next == ns2->next) &&
2032 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2033 skip = 1;
2034 break;
2035 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002036 }
2037 }
2038 if (skip)
2039 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002040
2041 /*
2042 * grow the nodeTab if needed
2043 */
2044 if (val1->nodeMax == 0) {
2045 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2046 sizeof(xmlNodePtr));
2047 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002048 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002049 return(NULL);
2050 }
2051 memset(val1->nodeTab, 0 ,
2052 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2053 val1->nodeMax = XML_NODESET_DEFAULT;
2054 } else if (val1->nodeNr == val1->nodeMax) {
2055 xmlNodePtr *temp;
2056
2057 val1->nodeMax *= 2;
2058 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2059 sizeof(xmlNodePtr));
2060 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002061 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002062 return(NULL);
2063 }
2064 val1->nodeTab = temp;
2065 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002066 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2067 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2068
2069 val1->nodeTab[val1->nodeNr++] =
2070 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2071 } else
2072 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002073 }
2074
2075 return(val1);
2076}
2077
2078/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002079 * xmlXPathNodeSetMergeUnique:
2080 * @val1: the first NodeSet or NULL
2081 * @val2: the second NodeSet
2082 *
2083 * Merges two nodesets, all nodes from @val2 are added to @val1
2084 * if @val1 is NULL, a new set is created and copied from @val2
2085 *
2086 * Returns @val1 once extended or NULL in case of error.
2087 */
2088static xmlNodeSetPtr
2089xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002090 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002091
2092 if (val2 == NULL) return(val1);
2093 if (val1 == NULL) {
2094 val1 = xmlXPathNodeSetCreate(NULL);
2095 }
2096
William M. Brack08171912003-12-29 02:52:11 +00002097 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002098
2099 for (i = 0;i < val2->nodeNr;i++) {
2100 /*
2101 * grow the nodeTab if needed
2102 */
2103 if (val1->nodeMax == 0) {
2104 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2105 sizeof(xmlNodePtr));
2106 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002107 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002108 return(NULL);
2109 }
2110 memset(val1->nodeTab, 0 ,
2111 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2112 val1->nodeMax = XML_NODESET_DEFAULT;
2113 } else if (val1->nodeNr == val1->nodeMax) {
2114 xmlNodePtr *temp;
2115
2116 val1->nodeMax *= 2;
2117 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2118 sizeof(xmlNodePtr));
2119 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002120 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002121 return(NULL);
2122 }
2123 val1->nodeTab = temp;
2124 }
2125 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2126 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2127
2128 val1->nodeTab[val1->nodeNr++] =
2129 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2130 } else
2131 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2132 }
2133
2134 return(val1);
2135}
2136
2137/**
Owen Taylor3473f882001-02-23 17:55:21 +00002138 * xmlXPathNodeSetDel:
2139 * @cur: the initial node set
2140 * @val: an xmlNodePtr
2141 *
2142 * Removes an xmlNodePtr from an existing NodeSet
2143 */
2144void
2145xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2146 int i;
2147
2148 if (cur == NULL) return;
2149 if (val == NULL) return;
2150
2151 /*
William M. Brack08171912003-12-29 02:52:11 +00002152 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002153 */
2154 for (i = 0;i < cur->nodeNr;i++)
2155 if (cur->nodeTab[i] == val) break;
2156
William M. Brack08171912003-12-29 02:52:11 +00002157 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002158#ifdef DEBUG
2159 xmlGenericError(xmlGenericErrorContext,
2160 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2161 val->name);
2162#endif
2163 return;
2164 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002165 if ((cur->nodeTab[i] != NULL) &&
2166 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2167 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002168 cur->nodeNr--;
2169 for (;i < cur->nodeNr;i++)
2170 cur->nodeTab[i] = cur->nodeTab[i + 1];
2171 cur->nodeTab[cur->nodeNr] = NULL;
2172}
2173
2174/**
2175 * xmlXPathNodeSetRemove:
2176 * @cur: the initial node set
2177 * @val: the index to remove
2178 *
2179 * Removes an entry from an existing NodeSet list.
2180 */
2181void
2182xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2183 if (cur == NULL) return;
2184 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002185 if ((cur->nodeTab[val] != NULL) &&
2186 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2187 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002188 cur->nodeNr--;
2189 for (;val < cur->nodeNr;val++)
2190 cur->nodeTab[val] = cur->nodeTab[val + 1];
2191 cur->nodeTab[cur->nodeNr] = NULL;
2192}
2193
2194/**
2195 * xmlXPathFreeNodeSet:
2196 * @obj: the xmlNodeSetPtr to free
2197 *
2198 * Free the NodeSet compound (not the actual nodes !).
2199 */
2200void
2201xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2202 if (obj == NULL) return;
2203 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002204 int i;
2205
William M. Brack08171912003-12-29 02:52:11 +00002206 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002207 for (i = 0;i < obj->nodeNr;i++)
2208 if ((obj->nodeTab[i] != NULL) &&
2209 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2210 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002211 xmlFree(obj->nodeTab);
2212 }
Owen Taylor3473f882001-02-23 17:55:21 +00002213 xmlFree(obj);
2214}
2215
2216/**
2217 * xmlXPathFreeValueTree:
2218 * @obj: the xmlNodeSetPtr to free
2219 *
2220 * Free the NodeSet compound and the actual tree, this is different
2221 * from xmlXPathFreeNodeSet()
2222 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002223static void
Owen Taylor3473f882001-02-23 17:55:21 +00002224xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2225 int i;
2226
2227 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002228
2229 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002230 for (i = 0;i < obj->nodeNr;i++) {
2231 if (obj->nodeTab[i] != NULL) {
2232 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2233 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2234 } else {
2235 xmlFreeNodeList(obj->nodeTab[i]);
2236 }
2237 }
2238 }
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#if defined(DEBUG) || defined(DEBUG_STEP)
2245/**
2246 * xmlGenericErrorContextNodeSet:
2247 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002248 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002249 *
2250 * Quick display of a NodeSet
2251 */
2252void
2253xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2254 int i;
2255
2256 if (output == NULL) output = xmlGenericErrorContext;
2257 if (obj == NULL) {
2258 fprintf(output, "NodeSet == NULL !\n");
2259 return;
2260 }
2261 if (obj->nodeNr == 0) {
2262 fprintf(output, "NodeSet is empty\n");
2263 return;
2264 }
2265 if (obj->nodeTab == NULL) {
2266 fprintf(output, " nodeTab == NULL !\n");
2267 return;
2268 }
2269 for (i = 0; i < obj->nodeNr; i++) {
2270 if (obj->nodeTab[i] == NULL) {
2271 fprintf(output, " NULL !\n");
2272 return;
2273 }
2274 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2275 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2276 fprintf(output, " /");
2277 else if (obj->nodeTab[i]->name == NULL)
2278 fprintf(output, " noname!");
2279 else fprintf(output, " %s", obj->nodeTab[i]->name);
2280 }
2281 fprintf(output, "\n");
2282}
2283#endif
2284
2285/**
2286 * xmlXPathNewNodeSet:
2287 * @val: the NodePtr value
2288 *
2289 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2290 * it with the single Node @val
2291 *
2292 * Returns the newly created object.
2293 */
2294xmlXPathObjectPtr
2295xmlXPathNewNodeSet(xmlNodePtr val) {
2296 xmlXPathObjectPtr ret;
2297
2298 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2299 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002300 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(NULL);
2302 }
2303 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2304 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002305 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002306 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002307 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002308 return(ret);
2309}
2310
2311/**
2312 * xmlXPathNewValueTree:
2313 * @val: the NodePtr value
2314 *
2315 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2316 * it with the tree root @val
2317 *
2318 * Returns the newly created object.
2319 */
2320xmlXPathObjectPtr
2321xmlXPathNewValueTree(xmlNodePtr val) {
2322 xmlXPathObjectPtr ret;
2323
2324 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2325 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002326 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002327 return(NULL);
2328 }
2329 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2330 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002331 ret->boolval = 1;
2332 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002333 ret->nodesetval = xmlXPathNodeSetCreate(val);
2334 return(ret);
2335}
2336
2337/**
2338 * xmlXPathNewNodeSetList:
2339 * @val: an existing NodeSet
2340 *
2341 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2342 * it with the Nodeset @val
2343 *
2344 * Returns the newly created object.
2345 */
2346xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002347xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2348{
Owen Taylor3473f882001-02-23 17:55:21 +00002349 xmlXPathObjectPtr ret;
2350 int i;
2351
2352 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002353 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002354 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002355 ret = xmlXPathNewNodeSet(NULL);
2356 else {
2357 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2358 for (i = 1; i < val->nodeNr; ++i)
2359 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2360 }
Owen Taylor3473f882001-02-23 17:55:21 +00002361
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002362 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002363}
2364
2365/**
2366 * xmlXPathWrapNodeSet:
2367 * @val: the NodePtr value
2368 *
2369 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2370 *
2371 * Returns the newly created object.
2372 */
2373xmlXPathObjectPtr
2374xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2375 xmlXPathObjectPtr ret;
2376
2377 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2378 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002379 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002380 return(NULL);
2381 }
2382 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2383 ret->type = XPATH_NODESET;
2384 ret->nodesetval = val;
2385 return(ret);
2386}
2387
2388/**
2389 * xmlXPathFreeNodeSetList:
2390 * @obj: an existing NodeSetList object
2391 *
2392 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2393 * the list contrary to xmlXPathFreeObject().
2394 */
2395void
2396xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2397 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002398 xmlFree(obj);
2399}
2400
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002401/**
2402 * xmlXPathDifference:
2403 * @nodes1: a node-set
2404 * @nodes2: a node-set
2405 *
2406 * Implements the EXSLT - Sets difference() function:
2407 * node-set set:difference (node-set, node-set)
2408 *
2409 * Returns the difference between the two node sets, or nodes1 if
2410 * nodes2 is empty
2411 */
2412xmlNodeSetPtr
2413xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2414 xmlNodeSetPtr ret;
2415 int i, l1;
2416 xmlNodePtr cur;
2417
2418 if (xmlXPathNodeSetIsEmpty(nodes2))
2419 return(nodes1);
2420
2421 ret = xmlXPathNodeSetCreate(NULL);
2422 if (xmlXPathNodeSetIsEmpty(nodes1))
2423 return(ret);
2424
2425 l1 = xmlXPathNodeSetGetLength(nodes1);
2426
2427 for (i = 0; i < l1; i++) {
2428 cur = xmlXPathNodeSetItem(nodes1, i);
2429 if (!xmlXPathNodeSetContains(nodes2, cur))
2430 xmlXPathNodeSetAddUnique(ret, cur);
2431 }
2432 return(ret);
2433}
2434
2435/**
2436 * xmlXPathIntersection:
2437 * @nodes1: a node-set
2438 * @nodes2: a node-set
2439 *
2440 * Implements the EXSLT - Sets intersection() function:
2441 * node-set set:intersection (node-set, node-set)
2442 *
2443 * Returns a node set comprising the nodes that are within both the
2444 * node sets passed as arguments
2445 */
2446xmlNodeSetPtr
2447xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2448 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2449 int i, l1;
2450 xmlNodePtr cur;
2451
2452 if (xmlXPathNodeSetIsEmpty(nodes1))
2453 return(ret);
2454 if (xmlXPathNodeSetIsEmpty(nodes2))
2455 return(ret);
2456
2457 l1 = xmlXPathNodeSetGetLength(nodes1);
2458
2459 for (i = 0; i < l1; i++) {
2460 cur = xmlXPathNodeSetItem(nodes1, i);
2461 if (xmlXPathNodeSetContains(nodes2, cur))
2462 xmlXPathNodeSetAddUnique(ret, cur);
2463 }
2464 return(ret);
2465}
2466
2467/**
2468 * xmlXPathDistinctSorted:
2469 * @nodes: a node-set, sorted by document order
2470 *
2471 * Implements the EXSLT - Sets distinct() function:
2472 * node-set set:distinct (node-set)
2473 *
2474 * Returns a subset of the nodes contained in @nodes, or @nodes if
2475 * it is empty
2476 */
2477xmlNodeSetPtr
2478xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2479 xmlNodeSetPtr ret;
2480 xmlHashTablePtr hash;
2481 int i, l;
2482 xmlChar * strval;
2483 xmlNodePtr cur;
2484
2485 if (xmlXPathNodeSetIsEmpty(nodes))
2486 return(nodes);
2487
2488 ret = xmlXPathNodeSetCreate(NULL);
2489 l = xmlXPathNodeSetGetLength(nodes);
2490 hash = xmlHashCreate (l);
2491 for (i = 0; i < l; i++) {
2492 cur = xmlXPathNodeSetItem(nodes, i);
2493 strval = xmlXPathCastNodeToString(cur);
2494 if (xmlHashLookup(hash, strval) == NULL) {
2495 xmlHashAddEntry(hash, strval, strval);
2496 xmlXPathNodeSetAddUnique(ret, cur);
2497 } else {
2498 xmlFree(strval);
2499 }
2500 }
2501 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2502 return(ret);
2503}
2504
2505/**
2506 * xmlXPathDistinct:
2507 * @nodes: a node-set
2508 *
2509 * Implements the EXSLT - Sets distinct() function:
2510 * node-set set:distinct (node-set)
2511 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2512 * is called with the sorted node-set
2513 *
2514 * Returns a subset of the nodes contained in @nodes, or @nodes if
2515 * it is empty
2516 */
2517xmlNodeSetPtr
2518xmlXPathDistinct (xmlNodeSetPtr nodes) {
2519 if (xmlXPathNodeSetIsEmpty(nodes))
2520 return(nodes);
2521
2522 xmlXPathNodeSetSort(nodes);
2523 return(xmlXPathDistinctSorted(nodes));
2524}
2525
2526/**
2527 * xmlXPathHasSameNodes:
2528 * @nodes1: a node-set
2529 * @nodes2: a node-set
2530 *
2531 * Implements the EXSLT - Sets has-same-nodes function:
2532 * boolean set:has-same-node(node-set, node-set)
2533 *
2534 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2535 * otherwise
2536 */
2537int
2538xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2539 int i, l;
2540 xmlNodePtr cur;
2541
2542 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2543 xmlXPathNodeSetIsEmpty(nodes2))
2544 return(0);
2545
2546 l = xmlXPathNodeSetGetLength(nodes1);
2547 for (i = 0; i < l; i++) {
2548 cur = xmlXPathNodeSetItem(nodes1, i);
2549 if (xmlXPathNodeSetContains(nodes2, cur))
2550 return(1);
2551 }
2552 return(0);
2553}
2554
2555/**
2556 * xmlXPathNodeLeadingSorted:
2557 * @nodes: a node-set, sorted by document order
2558 * @node: a node
2559 *
2560 * Implements the EXSLT - Sets leading() function:
2561 * node-set set:leading (node-set, node-set)
2562 *
2563 * Returns the nodes in @nodes that precede @node in document order,
2564 * @nodes if @node is NULL or an empty node-set if @nodes
2565 * doesn't contain @node
2566 */
2567xmlNodeSetPtr
2568xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2569 int i, l;
2570 xmlNodePtr cur;
2571 xmlNodeSetPtr ret;
2572
2573 if (node == NULL)
2574 return(nodes);
2575
2576 ret = xmlXPathNodeSetCreate(NULL);
2577 if (xmlXPathNodeSetIsEmpty(nodes) ||
2578 (!xmlXPathNodeSetContains(nodes, node)))
2579 return(ret);
2580
2581 l = xmlXPathNodeSetGetLength(nodes);
2582 for (i = 0; i < l; i++) {
2583 cur = xmlXPathNodeSetItem(nodes, i);
2584 if (cur == node)
2585 break;
2586 xmlXPathNodeSetAddUnique(ret, cur);
2587 }
2588 return(ret);
2589}
2590
2591/**
2592 * xmlXPathNodeLeading:
2593 * @nodes: a node-set
2594 * @node: a node
2595 *
2596 * Implements the EXSLT - Sets leading() function:
2597 * node-set set:leading (node-set, node-set)
2598 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2599 * is called.
2600 *
2601 * Returns the nodes in @nodes that precede @node in document order,
2602 * @nodes if @node is NULL or an empty node-set if @nodes
2603 * doesn't contain @node
2604 */
2605xmlNodeSetPtr
2606xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2607 xmlXPathNodeSetSort(nodes);
2608 return(xmlXPathNodeLeadingSorted(nodes, node));
2609}
2610
2611/**
2612 * xmlXPathLeadingSorted:
2613 * @nodes1: a node-set, sorted by document order
2614 * @nodes2: a node-set, sorted by document order
2615 *
2616 * Implements the EXSLT - Sets leading() function:
2617 * node-set set:leading (node-set, node-set)
2618 *
2619 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2620 * in document order, @nodes1 if @nodes2 is NULL or empty or
2621 * an empty node-set if @nodes1 doesn't contain @nodes2
2622 */
2623xmlNodeSetPtr
2624xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2625 if (xmlXPathNodeSetIsEmpty(nodes2))
2626 return(nodes1);
2627 return(xmlXPathNodeLeadingSorted(nodes1,
2628 xmlXPathNodeSetItem(nodes2, 1)));
2629}
2630
2631/**
2632 * xmlXPathLeading:
2633 * @nodes1: a node-set
2634 * @nodes2: a node-set
2635 *
2636 * Implements the EXSLT - Sets leading() function:
2637 * node-set set:leading (node-set, node-set)
2638 * @nodes1 and @nodes2 are sorted by document order, then
2639 * #exslSetsLeadingSorted is called.
2640 *
2641 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2642 * in document order, @nodes1 if @nodes2 is NULL or empty or
2643 * an empty node-set if @nodes1 doesn't contain @nodes2
2644 */
2645xmlNodeSetPtr
2646xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2647 if (xmlXPathNodeSetIsEmpty(nodes2))
2648 return(nodes1);
2649 if (xmlXPathNodeSetIsEmpty(nodes1))
2650 return(xmlXPathNodeSetCreate(NULL));
2651 xmlXPathNodeSetSort(nodes1);
2652 xmlXPathNodeSetSort(nodes2);
2653 return(xmlXPathNodeLeadingSorted(nodes1,
2654 xmlXPathNodeSetItem(nodes2, 1)));
2655}
2656
2657/**
2658 * xmlXPathNodeTrailingSorted:
2659 * @nodes: a node-set, sorted by document order
2660 * @node: a node
2661 *
2662 * Implements the EXSLT - Sets trailing() function:
2663 * node-set set:trailing (node-set, node-set)
2664 *
2665 * Returns the nodes in @nodes that follow @node in document order,
2666 * @nodes if @node is NULL or an empty node-set if @nodes
2667 * doesn't contain @node
2668 */
2669xmlNodeSetPtr
2670xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2671 int i, l;
2672 xmlNodePtr cur;
2673 xmlNodeSetPtr ret;
2674
2675 if (node == NULL)
2676 return(nodes);
2677
2678 ret = xmlXPathNodeSetCreate(NULL);
2679 if (xmlXPathNodeSetIsEmpty(nodes) ||
2680 (!xmlXPathNodeSetContains(nodes, node)))
2681 return(ret);
2682
2683 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002684 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002685 cur = xmlXPathNodeSetItem(nodes, i);
2686 if (cur == node)
2687 break;
2688 xmlXPathNodeSetAddUnique(ret, cur);
2689 }
2690 return(ret);
2691}
2692
2693/**
2694 * xmlXPathNodeTrailing:
2695 * @nodes: a node-set
2696 * @node: a node
2697 *
2698 * Implements the EXSLT - Sets trailing() function:
2699 * node-set set:trailing (node-set, node-set)
2700 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2701 * is called.
2702 *
2703 * Returns the nodes in @nodes that follow @node in document order,
2704 * @nodes if @node is NULL or an empty node-set if @nodes
2705 * doesn't contain @node
2706 */
2707xmlNodeSetPtr
2708xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2709 xmlXPathNodeSetSort(nodes);
2710 return(xmlXPathNodeTrailingSorted(nodes, node));
2711}
2712
2713/**
2714 * xmlXPathTrailingSorted:
2715 * @nodes1: a node-set, sorted by document order
2716 * @nodes2: a node-set, sorted by document order
2717 *
2718 * Implements the EXSLT - Sets trailing() function:
2719 * node-set set:trailing (node-set, node-set)
2720 *
2721 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2722 * in document order, @nodes1 if @nodes2 is NULL or empty or
2723 * an empty node-set if @nodes1 doesn't contain @nodes2
2724 */
2725xmlNodeSetPtr
2726xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2727 if (xmlXPathNodeSetIsEmpty(nodes2))
2728 return(nodes1);
2729 return(xmlXPathNodeTrailingSorted(nodes1,
2730 xmlXPathNodeSetItem(nodes2, 0)));
2731}
2732
2733/**
2734 * xmlXPathTrailing:
2735 * @nodes1: a node-set
2736 * @nodes2: a node-set
2737 *
2738 * Implements the EXSLT - Sets trailing() function:
2739 * node-set set:trailing (node-set, node-set)
2740 * @nodes1 and @nodes2 are sorted by document order, then
2741 * #xmlXPathTrailingSorted is called.
2742 *
2743 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2744 * in document order, @nodes1 if @nodes2 is NULL or empty or
2745 * an empty node-set if @nodes1 doesn't contain @nodes2
2746 */
2747xmlNodeSetPtr
2748xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2749 if (xmlXPathNodeSetIsEmpty(nodes2))
2750 return(nodes1);
2751 if (xmlXPathNodeSetIsEmpty(nodes1))
2752 return(xmlXPathNodeSetCreate(NULL));
2753 xmlXPathNodeSetSort(nodes1);
2754 xmlXPathNodeSetSort(nodes2);
2755 return(xmlXPathNodeTrailingSorted(nodes1,
2756 xmlXPathNodeSetItem(nodes2, 0)));
2757}
2758
Owen Taylor3473f882001-02-23 17:55:21 +00002759/************************************************************************
2760 * *
2761 * Routines to handle extra functions *
2762 * *
2763 ************************************************************************/
2764
2765/**
2766 * xmlXPathRegisterFunc:
2767 * @ctxt: the XPath context
2768 * @name: the function name
2769 * @f: the function implementation or NULL
2770 *
2771 * Register a new function. If @f is NULL it unregisters the function
2772 *
2773 * Returns 0 in case of success, -1 in case of error
2774 */
2775int
2776xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2777 xmlXPathFunction f) {
2778 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2779}
2780
2781/**
2782 * xmlXPathRegisterFuncNS:
2783 * @ctxt: the XPath context
2784 * @name: the function name
2785 * @ns_uri: the function namespace URI
2786 * @f: the function implementation or NULL
2787 *
2788 * Register a new function. If @f is NULL it unregisters the function
2789 *
2790 * Returns 0 in case of success, -1 in case of error
2791 */
2792int
2793xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2794 const xmlChar *ns_uri, xmlXPathFunction f) {
2795 if (ctxt == NULL)
2796 return(-1);
2797 if (name == NULL)
2798 return(-1);
2799
2800 if (ctxt->funcHash == NULL)
2801 ctxt->funcHash = xmlHashCreate(0);
2802 if (ctxt->funcHash == NULL)
2803 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002804 if (f == NULL)
2805 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002806 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2807}
2808
2809/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002810 * xmlXPathRegisterFuncLookup:
2811 * @ctxt: the XPath context
2812 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002813 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002814 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002815 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002816 */
2817void
2818xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2819 xmlXPathFuncLookupFunc f,
2820 void *funcCtxt) {
2821 if (ctxt == NULL)
2822 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002823 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002824 ctxt->funcLookupData = funcCtxt;
2825}
2826
2827/**
Owen Taylor3473f882001-02-23 17:55:21 +00002828 * xmlXPathFunctionLookup:
2829 * @ctxt: the XPath context
2830 * @name: the function name
2831 *
2832 * Search in the Function array of the context for the given
2833 * function.
2834 *
2835 * Returns the xmlXPathFunction or NULL if not found
2836 */
2837xmlXPathFunction
2838xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002839 if (ctxt == NULL)
2840 return (NULL);
2841
2842 if (ctxt->funcLookupFunc != NULL) {
2843 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002844 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002845
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002846 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002847 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002848 if (ret != NULL)
2849 return(ret);
2850 }
Owen Taylor3473f882001-02-23 17:55:21 +00002851 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2852}
2853
2854/**
2855 * xmlXPathFunctionLookupNS:
2856 * @ctxt: the XPath context
2857 * @name: the function name
2858 * @ns_uri: the function namespace URI
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
2866xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2867 const xmlChar *ns_uri) {
2868 if (ctxt == NULL)
2869 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002870 if (name == NULL)
2871 return(NULL);
2872
Thomas Broyerba4ad322001-07-26 16:55:21 +00002873 if (ctxt->funcLookupFunc != NULL) {
2874 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002875 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002876
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002877 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002878 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002879 if (ret != NULL)
2880 return(ret);
2881 }
2882
2883 if (ctxt->funcHash == NULL)
2884 return(NULL);
2885
Owen Taylor3473f882001-02-23 17:55:21 +00002886 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2887}
2888
2889/**
2890 * xmlXPathRegisteredFuncsCleanup:
2891 * @ctxt: the XPath context
2892 *
2893 * Cleanup the XPath context data associated to registered functions
2894 */
2895void
2896xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2897 if (ctxt == NULL)
2898 return;
2899
2900 xmlHashFree(ctxt->funcHash, NULL);
2901 ctxt->funcHash = NULL;
2902}
2903
2904/************************************************************************
2905 * *
William M. Brack08171912003-12-29 02:52:11 +00002906 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002907 * *
2908 ************************************************************************/
2909
2910/**
2911 * xmlXPathRegisterVariable:
2912 * @ctxt: the XPath context
2913 * @name: the variable name
2914 * @value: the variable value or NULL
2915 *
2916 * Register a new variable value. If @value is NULL it unregisters
2917 * the variable
2918 *
2919 * Returns 0 in case of success, -1 in case of error
2920 */
2921int
2922xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2923 xmlXPathObjectPtr value) {
2924 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2925}
2926
2927/**
2928 * xmlXPathRegisterVariableNS:
2929 * @ctxt: the XPath context
2930 * @name: the variable name
2931 * @ns_uri: the variable namespace URI
2932 * @value: the variable value or NULL
2933 *
2934 * Register a new variable value. If @value is NULL it unregisters
2935 * the variable
2936 *
2937 * Returns 0 in case of success, -1 in case of error
2938 */
2939int
2940xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2941 const xmlChar *ns_uri,
2942 xmlXPathObjectPtr value) {
2943 if (ctxt == NULL)
2944 return(-1);
2945 if (name == NULL)
2946 return(-1);
2947
2948 if (ctxt->varHash == NULL)
2949 ctxt->varHash = xmlHashCreate(0);
2950 if (ctxt->varHash == NULL)
2951 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002952 if (value == NULL)
2953 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2954 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002955 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2956 (void *) value,
2957 (xmlHashDeallocator)xmlXPathFreeObject));
2958}
2959
2960/**
2961 * xmlXPathRegisterVariableLookup:
2962 * @ctxt: the XPath context
2963 * @f: the lookup function
2964 * @data: the lookup data
2965 *
2966 * register an external mechanism to do variable lookup
2967 */
2968void
2969xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2970 xmlXPathVariableLookupFunc f, void *data) {
2971 if (ctxt == NULL)
2972 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002973 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002974 ctxt->varLookupData = data;
2975}
2976
2977/**
2978 * xmlXPathVariableLookup:
2979 * @ctxt: the XPath context
2980 * @name: the variable name
2981 *
2982 * Search in the Variable array of the context for the given
2983 * variable value.
2984 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002985 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002986 */
2987xmlXPathObjectPtr
2988xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2989 if (ctxt == NULL)
2990 return(NULL);
2991
2992 if (ctxt->varLookupFunc != NULL) {
2993 xmlXPathObjectPtr ret;
2994
2995 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2996 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002997 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002998 }
2999 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3000}
3001
3002/**
3003 * xmlXPathVariableLookupNS:
3004 * @ctxt: the XPath context
3005 * @name: the variable name
3006 * @ns_uri: the variable namespace URI
3007 *
3008 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003009 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003010 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003011 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003012 */
3013xmlXPathObjectPtr
3014xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3015 const xmlChar *ns_uri) {
3016 if (ctxt == NULL)
3017 return(NULL);
3018
3019 if (ctxt->varLookupFunc != NULL) {
3020 xmlXPathObjectPtr ret;
3021
3022 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3023 (ctxt->varLookupData, name, ns_uri);
3024 if (ret != NULL) return(ret);
3025 }
3026
3027 if (ctxt->varHash == NULL)
3028 return(NULL);
3029 if (name == NULL)
3030 return(NULL);
3031
Daniel Veillard8c357d52001-07-03 23:43:33 +00003032 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3033 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003034}
3035
3036/**
3037 * xmlXPathRegisteredVariablesCleanup:
3038 * @ctxt: the XPath context
3039 *
3040 * Cleanup the XPath context data associated to registered variables
3041 */
3042void
3043xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3044 if (ctxt == NULL)
3045 return;
3046
Daniel Veillard76d66f42001-05-16 21:05:17 +00003047 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003048 ctxt->varHash = NULL;
3049}
3050
3051/**
3052 * xmlXPathRegisterNs:
3053 * @ctxt: the XPath context
3054 * @prefix: the namespace prefix
3055 * @ns_uri: the namespace name
3056 *
3057 * Register a new namespace. If @ns_uri is NULL it unregisters
3058 * the namespace
3059 *
3060 * Returns 0 in case of success, -1 in case of error
3061 */
3062int
3063xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3064 const xmlChar *ns_uri) {
3065 if (ctxt == NULL)
3066 return(-1);
3067 if (prefix == NULL)
3068 return(-1);
3069
3070 if (ctxt->nsHash == NULL)
3071 ctxt->nsHash = xmlHashCreate(10);
3072 if (ctxt->nsHash == NULL)
3073 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003074 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003075 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003076 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003077 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003078 (xmlHashDeallocator)xmlFree));
3079}
3080
3081/**
3082 * xmlXPathNsLookup:
3083 * @ctxt: the XPath context
3084 * @prefix: the namespace prefix value
3085 *
3086 * Search in the namespace declaration array of the context for the given
3087 * namespace name associated to the given prefix
3088 *
3089 * Returns the value or NULL if not found
3090 */
3091const xmlChar *
3092xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3093 if (ctxt == NULL)
3094 return(NULL);
3095 if (prefix == NULL)
3096 return(NULL);
3097
3098#ifdef XML_XML_NAMESPACE
3099 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3100 return(XML_XML_NAMESPACE);
3101#endif
3102
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003103 if (ctxt->namespaces != NULL) {
3104 int i;
3105
3106 for (i = 0;i < ctxt->nsNr;i++) {
3107 if ((ctxt->namespaces[i] != NULL) &&
3108 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3109 return(ctxt->namespaces[i]->href);
3110 }
3111 }
Owen Taylor3473f882001-02-23 17:55:21 +00003112
3113 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3114}
3115
3116/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003117 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003118 * @ctxt: the XPath context
3119 *
3120 * Cleanup the XPath context data associated to registered variables
3121 */
3122void
3123xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3124 if (ctxt == NULL)
3125 return;
3126
Daniel Veillard42766c02002-08-22 20:52:17 +00003127 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003128 ctxt->nsHash = NULL;
3129}
3130
3131/************************************************************************
3132 * *
3133 * Routines to handle Values *
3134 * *
3135 ************************************************************************/
3136
William M. Brack08171912003-12-29 02:52:11 +00003137/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003138
3139/**
3140 * xmlXPathNewFloat:
3141 * @val: the double value
3142 *
3143 * Create a new xmlXPathObjectPtr of type double and of value @val
3144 *
3145 * Returns the newly created object.
3146 */
3147xmlXPathObjectPtr
3148xmlXPathNewFloat(double val) {
3149 xmlXPathObjectPtr ret;
3150
3151 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3152 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003153 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003154 return(NULL);
3155 }
3156 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3157 ret->type = XPATH_NUMBER;
3158 ret->floatval = val;
3159 return(ret);
3160}
3161
3162/**
3163 * xmlXPathNewBoolean:
3164 * @val: the boolean value
3165 *
3166 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3167 *
3168 * Returns the newly created object.
3169 */
3170xmlXPathObjectPtr
3171xmlXPathNewBoolean(int val) {
3172 xmlXPathObjectPtr ret;
3173
3174 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3175 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003176 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003177 return(NULL);
3178 }
3179 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3180 ret->type = XPATH_BOOLEAN;
3181 ret->boolval = (val != 0);
3182 return(ret);
3183}
3184
3185/**
3186 * xmlXPathNewString:
3187 * @val: the xmlChar * value
3188 *
3189 * Create a new xmlXPathObjectPtr of type string and of value @val
3190 *
3191 * Returns the newly created object.
3192 */
3193xmlXPathObjectPtr
3194xmlXPathNewString(const xmlChar *val) {
3195 xmlXPathObjectPtr ret;
3196
3197 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3198 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003199 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003200 return(NULL);
3201 }
3202 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3203 ret->type = XPATH_STRING;
3204 if (val != NULL)
3205 ret->stringval = xmlStrdup(val);
3206 else
3207 ret->stringval = xmlStrdup((const xmlChar *)"");
3208 return(ret);
3209}
3210
3211/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003212 * xmlXPathWrapString:
3213 * @val: the xmlChar * value
3214 *
3215 * Wraps the @val string into an XPath object.
3216 *
3217 * Returns the newly created object.
3218 */
3219xmlXPathObjectPtr
3220xmlXPathWrapString (xmlChar *val) {
3221 xmlXPathObjectPtr ret;
3222
3223 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3224 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003225 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003226 return(NULL);
3227 }
3228 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3229 ret->type = XPATH_STRING;
3230 ret->stringval = val;
3231 return(ret);
3232}
3233
3234/**
Owen Taylor3473f882001-02-23 17:55:21 +00003235 * xmlXPathNewCString:
3236 * @val: the char * value
3237 *
3238 * Create a new xmlXPathObjectPtr of type string and of value @val
3239 *
3240 * Returns the newly created object.
3241 */
3242xmlXPathObjectPtr
3243xmlXPathNewCString(const char *val) {
3244 xmlXPathObjectPtr ret;
3245
3246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3247 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003248 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003249 return(NULL);
3250 }
3251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3252 ret->type = XPATH_STRING;
3253 ret->stringval = xmlStrdup(BAD_CAST val);
3254 return(ret);
3255}
3256
3257/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003258 * xmlXPathWrapCString:
3259 * @val: the char * value
3260 *
3261 * Wraps a string into an XPath object.
3262 *
3263 * Returns the newly created object.
3264 */
3265xmlXPathObjectPtr
3266xmlXPathWrapCString (char * val) {
3267 return(xmlXPathWrapString((xmlChar *)(val)));
3268}
3269
3270/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003271 * xmlXPathWrapExternal:
3272 * @val: the user data
3273 *
3274 * Wraps the @val data into an XPath object.
3275 *
3276 * Returns the newly created object.
3277 */
3278xmlXPathObjectPtr
3279xmlXPathWrapExternal (void *val) {
3280 xmlXPathObjectPtr ret;
3281
3282 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3283 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003284 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003285 return(NULL);
3286 }
3287 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3288 ret->type = XPATH_USERS;
3289 ret->user = val;
3290 return(ret);
3291}
3292
3293/**
Owen Taylor3473f882001-02-23 17:55:21 +00003294 * xmlXPathObjectCopy:
3295 * @val: the original object
3296 *
3297 * allocate a new copy of a given object
3298 *
3299 * Returns the newly created object.
3300 */
3301xmlXPathObjectPtr
3302xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3303 xmlXPathObjectPtr ret;
3304
3305 if (val == NULL)
3306 return(NULL);
3307
3308 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3309 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003310 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003311 return(NULL);
3312 }
3313 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3314 switch (val->type) {
3315 case XPATH_BOOLEAN:
3316 case XPATH_NUMBER:
3317 case XPATH_POINT:
3318 case XPATH_RANGE:
3319 break;
3320 case XPATH_STRING:
3321 ret->stringval = xmlStrdup(val->stringval);
3322 break;
3323 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003324#if 0
3325/*
3326 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3327 this previous handling is no longer correct, and can cause some serious
3328 problems (ref. bug 145547)
3329*/
Owen Taylor3473f882001-02-23 17:55:21 +00003330 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003331 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003332 xmlNodePtr cur, tmp;
3333 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003334
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003335 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003336 top = xmlNewDoc(NULL);
3337 top->name = (char *)
3338 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003339 ret->user = top;
3340 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003341 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003342 cur = val->nodesetval->nodeTab[0]->children;
3343 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003344 tmp = xmlDocCopyNode(cur, top, 1);
3345 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003346 cur = cur->next;
3347 }
3348 }
William M. Bracke9449c52004-07-11 14:41:20 +00003349
Daniel Veillard9adc0462003-03-24 18:39:54 +00003350 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003351 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003352 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003353 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003354 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003355#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003356 case XPATH_NODESET:
3357 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003358 /* Do not deallocate the copied tree value */
3359 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003360 break;
3361 case XPATH_LOCATIONSET:
3362#ifdef LIBXML_XPTR_ENABLED
3363 {
3364 xmlLocationSetPtr loc = val->user;
3365 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3366 break;
3367 }
3368#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003369 case XPATH_USERS:
3370 ret->user = val->user;
3371 break;
3372 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003373 xmlGenericError(xmlGenericErrorContext,
3374 "xmlXPathObjectCopy: unsupported type %d\n",
3375 val->type);
3376 break;
3377 }
3378 return(ret);
3379}
3380
3381/**
3382 * xmlXPathFreeObject:
3383 * @obj: the object to free
3384 *
3385 * Free up an xmlXPathObjectPtr object.
3386 */
3387void
3388xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3389 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003390 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003391 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003392#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003393 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003394 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003395 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003396 } else
3397#endif
3398 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003399 xmlXPathFreeValueTree(obj->nodesetval);
3400 } else {
3401 if (obj->nodesetval != NULL)
3402 xmlXPathFreeNodeSet(obj->nodesetval);
3403 }
Owen Taylor3473f882001-02-23 17:55:21 +00003404#ifdef LIBXML_XPTR_ENABLED
3405 } else if (obj->type == XPATH_LOCATIONSET) {
3406 if (obj->user != NULL)
3407 xmlXPtrFreeLocationSet(obj->user);
3408#endif
3409 } else if (obj->type == XPATH_STRING) {
3410 if (obj->stringval != NULL)
3411 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003412 }
3413
Owen Taylor3473f882001-02-23 17:55:21 +00003414 xmlFree(obj);
3415}
3416
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003417
3418/************************************************************************
3419 * *
3420 * Type Casting Routines *
3421 * *
3422 ************************************************************************/
3423
3424/**
3425 * xmlXPathCastBooleanToString:
3426 * @val: a boolean
3427 *
3428 * Converts a boolean to its string value.
3429 *
3430 * Returns a newly allocated string.
3431 */
3432xmlChar *
3433xmlXPathCastBooleanToString (int val) {
3434 xmlChar *ret;
3435 if (val)
3436 ret = xmlStrdup((const xmlChar *) "true");
3437 else
3438 ret = xmlStrdup((const xmlChar *) "false");
3439 return(ret);
3440}
3441
3442/**
3443 * xmlXPathCastNumberToString:
3444 * @val: a number
3445 *
3446 * Converts a number to its string value.
3447 *
3448 * Returns a newly allocated string.
3449 */
3450xmlChar *
3451xmlXPathCastNumberToString (double val) {
3452 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003453 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003454 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003455 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003456 break;
3457 case -1:
3458 ret = xmlStrdup((const xmlChar *) "-Infinity");
3459 break;
3460 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003461 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003462 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003463 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3464 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003465 } else {
3466 /* could be improved */
3467 char buf[100];
3468 xmlXPathFormatNumber(val, buf, 100);
3469 ret = xmlStrdup((const xmlChar *) buf);
3470 }
3471 }
3472 return(ret);
3473}
3474
3475/**
3476 * xmlXPathCastNodeToString:
3477 * @node: a node
3478 *
3479 * Converts a node to its string value.
3480 *
3481 * Returns a newly allocated string.
3482 */
3483xmlChar *
3484xmlXPathCastNodeToString (xmlNodePtr node) {
3485 return(xmlNodeGetContent(node));
3486}
3487
3488/**
3489 * xmlXPathCastNodeSetToString:
3490 * @ns: a node-set
3491 *
3492 * Converts a node-set to its string value.
3493 *
3494 * Returns a newly allocated string.
3495 */
3496xmlChar *
3497xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3498 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3499 return(xmlStrdup((const xmlChar *) ""));
3500
3501 xmlXPathNodeSetSort(ns);
3502 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3503}
3504
3505/**
3506 * xmlXPathCastToString:
3507 * @val: an XPath object
3508 *
3509 * Converts an existing object to its string() equivalent
3510 *
3511 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003512 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003513 * string object).
3514 */
3515xmlChar *
3516xmlXPathCastToString(xmlXPathObjectPtr val) {
3517 xmlChar *ret = NULL;
3518
3519 if (val == NULL)
3520 return(xmlStrdup((const xmlChar *) ""));
3521 switch (val->type) {
3522 case XPATH_UNDEFINED:
3523#ifdef DEBUG_EXPR
3524 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3525#endif
3526 ret = xmlStrdup((const xmlChar *) "");
3527 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003528 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003529 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003530 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3531 break;
3532 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003533 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003534 case XPATH_BOOLEAN:
3535 ret = xmlXPathCastBooleanToString(val->boolval);
3536 break;
3537 case XPATH_NUMBER: {
3538 ret = xmlXPathCastNumberToString(val->floatval);
3539 break;
3540 }
3541 case XPATH_USERS:
3542 case XPATH_POINT:
3543 case XPATH_RANGE:
3544 case XPATH_LOCATIONSET:
3545 TODO
3546 ret = xmlStrdup((const xmlChar *) "");
3547 break;
3548 }
3549 return(ret);
3550}
3551
3552/**
3553 * xmlXPathConvertString:
3554 * @val: an XPath object
3555 *
3556 * Converts an existing object to its string() equivalent
3557 *
3558 * Returns the new object, the old one is freed (or the operation
3559 * is done directly on @val)
3560 */
3561xmlXPathObjectPtr
3562xmlXPathConvertString(xmlXPathObjectPtr val) {
3563 xmlChar *res = NULL;
3564
3565 if (val == NULL)
3566 return(xmlXPathNewCString(""));
3567
3568 switch (val->type) {
3569 case XPATH_UNDEFINED:
3570#ifdef DEBUG_EXPR
3571 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3572#endif
3573 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003574 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003575 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003576 res = xmlXPathCastNodeSetToString(val->nodesetval);
3577 break;
3578 case XPATH_STRING:
3579 return(val);
3580 case XPATH_BOOLEAN:
3581 res = xmlXPathCastBooleanToString(val->boolval);
3582 break;
3583 case XPATH_NUMBER:
3584 res = xmlXPathCastNumberToString(val->floatval);
3585 break;
3586 case XPATH_USERS:
3587 case XPATH_POINT:
3588 case XPATH_RANGE:
3589 case XPATH_LOCATIONSET:
3590 TODO;
3591 break;
3592 }
3593 xmlXPathFreeObject(val);
3594 if (res == NULL)
3595 return(xmlXPathNewCString(""));
3596 return(xmlXPathWrapString(res));
3597}
3598
3599/**
3600 * xmlXPathCastBooleanToNumber:
3601 * @val: a boolean
3602 *
3603 * Converts a boolean to its number value
3604 *
3605 * Returns the number value
3606 */
3607double
3608xmlXPathCastBooleanToNumber(int val) {
3609 if (val)
3610 return(1.0);
3611 return(0.0);
3612}
3613
3614/**
3615 * xmlXPathCastStringToNumber:
3616 * @val: a string
3617 *
3618 * Converts a string to its number value
3619 *
3620 * Returns the number value
3621 */
3622double
3623xmlXPathCastStringToNumber(const xmlChar * val) {
3624 return(xmlXPathStringEvalNumber(val));
3625}
3626
3627/**
3628 * xmlXPathCastNodeToNumber:
3629 * @node: a node
3630 *
3631 * Converts a node to its number value
3632 *
3633 * Returns the number value
3634 */
3635double
3636xmlXPathCastNodeToNumber (xmlNodePtr node) {
3637 xmlChar *strval;
3638 double ret;
3639
3640 if (node == NULL)
3641 return(xmlXPathNAN);
3642 strval = xmlXPathCastNodeToString(node);
3643 if (strval == NULL)
3644 return(xmlXPathNAN);
3645 ret = xmlXPathCastStringToNumber(strval);
3646 xmlFree(strval);
3647
3648 return(ret);
3649}
3650
3651/**
3652 * xmlXPathCastNodeSetToNumber:
3653 * @ns: a node-set
3654 *
3655 * Converts a node-set to its number value
3656 *
3657 * Returns the number value
3658 */
3659double
3660xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3661 xmlChar *str;
3662 double ret;
3663
3664 if (ns == NULL)
3665 return(xmlXPathNAN);
3666 str = xmlXPathCastNodeSetToString(ns);
3667 ret = xmlXPathCastStringToNumber(str);
3668 xmlFree(str);
3669 return(ret);
3670}
3671
3672/**
3673 * xmlXPathCastToNumber:
3674 * @val: an XPath object
3675 *
3676 * Converts an XPath object to its number value
3677 *
3678 * Returns the number value
3679 */
3680double
3681xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3682 double ret = 0.0;
3683
3684 if (val == NULL)
3685 return(xmlXPathNAN);
3686 switch (val->type) {
3687 case XPATH_UNDEFINED:
3688#ifdef DEGUB_EXPR
3689 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3690#endif
3691 ret = xmlXPathNAN;
3692 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003693 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003694 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003695 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3696 break;
3697 case XPATH_STRING:
3698 ret = xmlXPathCastStringToNumber(val->stringval);
3699 break;
3700 case XPATH_NUMBER:
3701 ret = val->floatval;
3702 break;
3703 case XPATH_BOOLEAN:
3704 ret = xmlXPathCastBooleanToNumber(val->boolval);
3705 break;
3706 case XPATH_USERS:
3707 case XPATH_POINT:
3708 case XPATH_RANGE:
3709 case XPATH_LOCATIONSET:
3710 TODO;
3711 ret = xmlXPathNAN;
3712 break;
3713 }
3714 return(ret);
3715}
3716
3717/**
3718 * xmlXPathConvertNumber:
3719 * @val: an XPath object
3720 *
3721 * Converts an existing object to its number() equivalent
3722 *
3723 * Returns the new object, the old one is freed (or the operation
3724 * is done directly on @val)
3725 */
3726xmlXPathObjectPtr
3727xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3728 xmlXPathObjectPtr ret;
3729
3730 if (val == NULL)
3731 return(xmlXPathNewFloat(0.0));
3732 if (val->type == XPATH_NUMBER)
3733 return(val);
3734 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3735 xmlXPathFreeObject(val);
3736 return(ret);
3737}
3738
3739/**
3740 * xmlXPathCastNumberToBoolean:
3741 * @val: a number
3742 *
3743 * Converts a number to its boolean value
3744 *
3745 * Returns the boolean value
3746 */
3747int
3748xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003749 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003750 return(0);
3751 return(1);
3752}
3753
3754/**
3755 * xmlXPathCastStringToBoolean:
3756 * @val: a string
3757 *
3758 * Converts a string to its boolean value
3759 *
3760 * Returns the boolean value
3761 */
3762int
3763xmlXPathCastStringToBoolean (const xmlChar *val) {
3764 if ((val == NULL) || (xmlStrlen(val) == 0))
3765 return(0);
3766 return(1);
3767}
3768
3769/**
3770 * xmlXPathCastNodeSetToBoolean:
3771 * @ns: a node-set
3772 *
3773 * Converts a node-set to its boolean value
3774 *
3775 * Returns the boolean value
3776 */
3777int
3778xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3779 if ((ns == NULL) || (ns->nodeNr == 0))
3780 return(0);
3781 return(1);
3782}
3783
3784/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003785 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003786 * @val: an XPath object
3787 *
3788 * Converts an XPath object to its boolean value
3789 *
3790 * Returns the boolean value
3791 */
3792int
3793xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3794 int ret = 0;
3795
3796 if (val == NULL)
3797 return(0);
3798 switch (val->type) {
3799 case XPATH_UNDEFINED:
3800#ifdef DEBUG_EXPR
3801 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3802#endif
3803 ret = 0;
3804 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003805 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003806 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003807 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3808 break;
3809 case XPATH_STRING:
3810 ret = xmlXPathCastStringToBoolean(val->stringval);
3811 break;
3812 case XPATH_NUMBER:
3813 ret = xmlXPathCastNumberToBoolean(val->floatval);
3814 break;
3815 case XPATH_BOOLEAN:
3816 ret = val->boolval;
3817 break;
3818 case XPATH_USERS:
3819 case XPATH_POINT:
3820 case XPATH_RANGE:
3821 case XPATH_LOCATIONSET:
3822 TODO;
3823 ret = 0;
3824 break;
3825 }
3826 return(ret);
3827}
3828
3829
3830/**
3831 * xmlXPathConvertBoolean:
3832 * @val: an XPath object
3833 *
3834 * Converts an existing object to its boolean() equivalent
3835 *
3836 * Returns the new object, the old one is freed (or the operation
3837 * is done directly on @val)
3838 */
3839xmlXPathObjectPtr
3840xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3841 xmlXPathObjectPtr ret;
3842
3843 if (val == NULL)
3844 return(xmlXPathNewBoolean(0));
3845 if (val->type == XPATH_BOOLEAN)
3846 return(val);
3847 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3848 xmlXPathFreeObject(val);
3849 return(ret);
3850}
3851
Owen Taylor3473f882001-02-23 17:55:21 +00003852/************************************************************************
3853 * *
3854 * Routines to handle XPath contexts *
3855 * *
3856 ************************************************************************/
3857
3858/**
3859 * xmlXPathNewContext:
3860 * @doc: the XML document
3861 *
3862 * Create a new xmlXPathContext
3863 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003864 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003865 */
3866xmlXPathContextPtr
3867xmlXPathNewContext(xmlDocPtr doc) {
3868 xmlXPathContextPtr ret;
3869
3870 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3871 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003872 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003873 return(NULL);
3874 }
3875 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3876 ret->doc = doc;
3877 ret->node = NULL;
3878
3879 ret->varHash = NULL;
3880
3881 ret->nb_types = 0;
3882 ret->max_types = 0;
3883 ret->types = NULL;
3884
3885 ret->funcHash = xmlHashCreate(0);
3886
3887 ret->nb_axis = 0;
3888 ret->max_axis = 0;
3889 ret->axis = NULL;
3890
3891 ret->nsHash = NULL;
3892 ret->user = NULL;
3893
3894 ret->contextSize = -1;
3895 ret->proximityPosition = -1;
3896
3897 xmlXPathRegisterAllFunctions(ret);
3898
3899 return(ret);
3900}
3901
3902/**
3903 * xmlXPathFreeContext:
3904 * @ctxt: the context to free
3905 *
3906 * Free up an xmlXPathContext
3907 */
3908void
3909xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3910 xmlXPathRegisteredNsCleanup(ctxt);
3911 xmlXPathRegisteredFuncsCleanup(ctxt);
3912 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003913 xmlFree(ctxt);
3914}
3915
3916/************************************************************************
3917 * *
3918 * Routines to handle XPath parser contexts *
3919 * *
3920 ************************************************************************/
3921
3922#define CHECK_CTXT(ctxt) \
3923 if (ctxt == NULL) { \
3924 xmlGenericError(xmlGenericErrorContext, \
3925 "%s:%d Internal error: ctxt == NULL\n", \
3926 __FILE__, __LINE__); \
3927 } \
3928
3929
3930#define CHECK_CONTEXT(ctxt) \
3931 if (ctxt == NULL) { \
3932 xmlGenericError(xmlGenericErrorContext, \
3933 "%s:%d Internal error: no context\n", \
3934 __FILE__, __LINE__); \
3935 } \
3936 else if (ctxt->doc == NULL) { \
3937 xmlGenericError(xmlGenericErrorContext, \
3938 "%s:%d Internal error: no document\n", \
3939 __FILE__, __LINE__); \
3940 } \
3941 else if (ctxt->doc->children == NULL) { \
3942 xmlGenericError(xmlGenericErrorContext, \
3943 "%s:%d Internal error: document without root\n", \
3944 __FILE__, __LINE__); \
3945 } \
3946
3947
3948/**
3949 * xmlXPathNewParserContext:
3950 * @str: the XPath expression
3951 * @ctxt: the XPath context
3952 *
3953 * Create a new xmlXPathParserContext
3954 *
3955 * Returns the xmlXPathParserContext just allocated.
3956 */
3957xmlXPathParserContextPtr
3958xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3959 xmlXPathParserContextPtr ret;
3960
3961 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3962 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003963 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003964 return(NULL);
3965 }
3966 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3967 ret->cur = ret->base = str;
3968 ret->context = ctxt;
3969
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003970 ret->comp = xmlXPathNewCompExpr();
3971 if (ret->comp == NULL) {
3972 xmlFree(ret->valueTab);
3973 xmlFree(ret);
3974 return(NULL);
3975 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003976 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3977 ret->comp->dict = ctxt->dict;
3978 xmlDictReference(ret->comp->dict);
3979 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003980
3981 return(ret);
3982}
3983
3984/**
3985 * xmlXPathCompParserContext:
3986 * @comp: the XPath compiled expression
3987 * @ctxt: the XPath context
3988 *
3989 * Create a new xmlXPathParserContext when processing a compiled expression
3990 *
3991 * Returns the xmlXPathParserContext just allocated.
3992 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003993static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003994xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3995 xmlXPathParserContextPtr ret;
3996
3997 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3998 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003999 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004000 return(NULL);
4001 }
4002 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
4003
Owen Taylor3473f882001-02-23 17:55:21 +00004004 /* Allocate the value stack */
4005 ret->valueTab = (xmlXPathObjectPtr *)
4006 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004007 if (ret->valueTab == NULL) {
4008 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004009 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004010 return(NULL);
4011 }
Owen Taylor3473f882001-02-23 17:55:21 +00004012 ret->valueNr = 0;
4013 ret->valueMax = 10;
4014 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004015
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004016 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004017 ret->comp = comp;
4018
Owen Taylor3473f882001-02-23 17:55:21 +00004019 return(ret);
4020}
4021
4022/**
4023 * xmlXPathFreeParserContext:
4024 * @ctxt: the context to free
4025 *
4026 * Free up an xmlXPathParserContext
4027 */
4028void
4029xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4030 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004031 xmlFree(ctxt->valueTab);
4032 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004033 if (ctxt->comp)
4034 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004035 xmlFree(ctxt);
4036}
4037
4038/************************************************************************
4039 * *
4040 * The implicit core function library *
4041 * *
4042 ************************************************************************/
4043
Owen Taylor3473f882001-02-23 17:55:21 +00004044/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004045 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004046 * @node: a node pointer
4047 *
4048 * Function computing the beginning of the string value of the node,
4049 * used to speed up comparisons
4050 *
4051 * Returns an int usable as a hash
4052 */
4053static unsigned int
4054xmlXPathNodeValHash(xmlNodePtr node) {
4055 int len = 2;
4056 const xmlChar * string = NULL;
4057 xmlNodePtr tmp = NULL;
4058 unsigned int ret = 0;
4059
4060 if (node == NULL)
4061 return(0);
4062
Daniel Veillard9adc0462003-03-24 18:39:54 +00004063 if (node->type == XML_DOCUMENT_NODE) {
4064 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4065 if (tmp == NULL)
4066 node = node->children;
4067 else
4068 node = tmp;
4069
4070 if (node == NULL)
4071 return(0);
4072 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004073
4074 switch (node->type) {
4075 case XML_COMMENT_NODE:
4076 case XML_PI_NODE:
4077 case XML_CDATA_SECTION_NODE:
4078 case XML_TEXT_NODE:
4079 string = node->content;
4080 if (string == NULL)
4081 return(0);
4082 if (string[0] == 0)
4083 return(0);
4084 return(((unsigned int) string[0]) +
4085 (((unsigned int) string[1]) << 8));
4086 case XML_NAMESPACE_DECL:
4087 string = ((xmlNsPtr)node)->href;
4088 if (string == NULL)
4089 return(0);
4090 if (string[0] == 0)
4091 return(0);
4092 return(((unsigned int) string[0]) +
4093 (((unsigned int) string[1]) << 8));
4094 case XML_ATTRIBUTE_NODE:
4095 tmp = ((xmlAttrPtr) node)->children;
4096 break;
4097 case XML_ELEMENT_NODE:
4098 tmp = node->children;
4099 break;
4100 default:
4101 return(0);
4102 }
4103 while (tmp != NULL) {
4104 switch (tmp->type) {
4105 case XML_COMMENT_NODE:
4106 case XML_PI_NODE:
4107 case XML_CDATA_SECTION_NODE:
4108 case XML_TEXT_NODE:
4109 string = tmp->content;
4110 break;
4111 case XML_NAMESPACE_DECL:
4112 string = ((xmlNsPtr)tmp)->href;
4113 break;
4114 default:
4115 break;
4116 }
4117 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004118 if (len == 1) {
4119 return(ret + (((unsigned int) string[0]) << 8));
4120 }
4121 if (string[1] == 0) {
4122 len = 1;
4123 ret = (unsigned int) string[0];
4124 } else {
4125 return(((unsigned int) string[0]) +
4126 (((unsigned int) string[1]) << 8));
4127 }
4128 }
4129 /*
4130 * Skip to next node
4131 */
4132 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4133 if (tmp->children->type != XML_ENTITY_DECL) {
4134 tmp = tmp->children;
4135 continue;
4136 }
4137 }
4138 if (tmp == node)
4139 break;
4140
4141 if (tmp->next != NULL) {
4142 tmp = tmp->next;
4143 continue;
4144 }
4145
4146 do {
4147 tmp = tmp->parent;
4148 if (tmp == NULL)
4149 break;
4150 if (tmp == node) {
4151 tmp = NULL;
4152 break;
4153 }
4154 if (tmp->next != NULL) {
4155 tmp = tmp->next;
4156 break;
4157 }
4158 } while (tmp != NULL);
4159 }
4160 return(ret);
4161}
4162
4163/**
4164 * xmlXPathStringHash:
4165 * @string: a string
4166 *
4167 * Function computing the beginning of the string value of the node,
4168 * used to speed up comparisons
4169 *
4170 * Returns an int usable as a hash
4171 */
4172static unsigned int
4173xmlXPathStringHash(const xmlChar * string) {
4174 if (string == NULL)
4175 return((unsigned int) 0);
4176 if (string[0] == 0)
4177 return(0);
4178 return(((unsigned int) string[0]) +
4179 (((unsigned int) string[1]) << 8));
4180}
4181
4182/**
Owen Taylor3473f882001-02-23 17:55:21 +00004183 * xmlXPathCompareNodeSetFloat:
4184 * @ctxt: the XPath Parser context
4185 * @inf: less than (1) or greater than (0)
4186 * @strict: is the comparison strict
4187 * @arg: the node set
4188 * @f: the value
4189 *
4190 * Implement the compare operation between a nodeset and a number
4191 * @ns < @val (1, 1, ...
4192 * @ns <= @val (1, 0, ...
4193 * @ns > @val (0, 1, ...
4194 * @ns >= @val (0, 0, ...
4195 *
4196 * If one object to be compared is a node-set and the other is a number,
4197 * then the comparison will be true if and only if there is a node in the
4198 * node-set such that the result of performing the comparison on the number
4199 * to be compared and on the result of converting the string-value of that
4200 * node to a number using the number function is true.
4201 *
4202 * Returns 0 or 1 depending on the results of the test.
4203 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004204static int
Owen Taylor3473f882001-02-23 17:55:21 +00004205xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4206 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4207 int i, ret = 0;
4208 xmlNodeSetPtr ns;
4209 xmlChar *str2;
4210
4211 if ((f == NULL) || (arg == NULL) ||
4212 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4213 xmlXPathFreeObject(arg);
4214 xmlXPathFreeObject(f);
4215 return(0);
4216 }
4217 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004218 if (ns != NULL) {
4219 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004220 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004221 if (str2 != NULL) {
4222 valuePush(ctxt,
4223 xmlXPathNewString(str2));
4224 xmlFree(str2);
4225 xmlXPathNumberFunction(ctxt, 1);
4226 valuePush(ctxt, xmlXPathObjectCopy(f));
4227 ret = xmlXPathCompareValues(ctxt, inf, strict);
4228 if (ret)
4229 break;
4230 }
4231 }
Owen Taylor3473f882001-02-23 17:55:21 +00004232 }
4233 xmlXPathFreeObject(arg);
4234 xmlXPathFreeObject(f);
4235 return(ret);
4236}
4237
4238/**
4239 * xmlXPathCompareNodeSetString:
4240 * @ctxt: the XPath Parser context
4241 * @inf: less than (1) or greater than (0)
4242 * @strict: is the comparison strict
4243 * @arg: the node set
4244 * @s: the value
4245 *
4246 * Implement the compare operation between a nodeset and a string
4247 * @ns < @val (1, 1, ...
4248 * @ns <= @val (1, 0, ...
4249 * @ns > @val (0, 1, ...
4250 * @ns >= @val (0, 0, ...
4251 *
4252 * If one object to be compared is a node-set and the other is a string,
4253 * then the comparison will be true if and only if there is a node in
4254 * the node-set such that the result of performing the comparison on the
4255 * string-value of the node and the other string is true.
4256 *
4257 * Returns 0 or 1 depending on the results of the test.
4258 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004259static int
Owen Taylor3473f882001-02-23 17:55:21 +00004260xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4261 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4262 int i, ret = 0;
4263 xmlNodeSetPtr ns;
4264 xmlChar *str2;
4265
4266 if ((s == NULL) || (arg == NULL) ||
4267 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4268 xmlXPathFreeObject(arg);
4269 xmlXPathFreeObject(s);
4270 return(0);
4271 }
4272 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004273 if (ns != NULL) {
4274 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004275 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004276 if (str2 != NULL) {
4277 valuePush(ctxt,
4278 xmlXPathNewString(str2));
4279 xmlFree(str2);
4280 valuePush(ctxt, xmlXPathObjectCopy(s));
4281 ret = xmlXPathCompareValues(ctxt, inf, strict);
4282 if (ret)
4283 break;
4284 }
4285 }
Owen Taylor3473f882001-02-23 17:55:21 +00004286 }
4287 xmlXPathFreeObject(arg);
4288 xmlXPathFreeObject(s);
4289 return(ret);
4290}
4291
4292/**
4293 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004294 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004295 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004296 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004297 * @arg2: the second node set object
4298 *
4299 * Implement the compare operation on nodesets:
4300 *
4301 * If both objects to be compared are node-sets, then the comparison
4302 * will be true if and only if there is a node in the first node-set
4303 * and a node in the second node-set such that the result of performing
4304 * the comparison on the string-values of the two nodes is true.
4305 * ....
4306 * When neither object to be compared is a node-set and the operator
4307 * is <=, <, >= or >, then the objects are compared by converting both
4308 * objects to numbers and comparing the numbers according to IEEE 754.
4309 * ....
4310 * The number function converts its argument to a number as follows:
4311 * - a string that consists of optional whitespace followed by an
4312 * optional minus sign followed by a Number followed by whitespace
4313 * is converted to the IEEE 754 number that is nearest (according
4314 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4315 * represented by the string; any other string is converted to NaN
4316 *
4317 * Conclusion all nodes need to be converted first to their string value
4318 * and then the comparison must be done when possible
4319 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004320static int
4321xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004322 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4323 int i, j, init = 0;
4324 double val1;
4325 double *values2;
4326 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004327 xmlNodeSetPtr ns1;
4328 xmlNodeSetPtr ns2;
4329
4330 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004331 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4332 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004333 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004334 }
Owen Taylor3473f882001-02-23 17:55:21 +00004335 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004336 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4337 xmlXPathFreeObject(arg1);
4338 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004339 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004340 }
Owen Taylor3473f882001-02-23 17:55:21 +00004341
4342 ns1 = arg1->nodesetval;
4343 ns2 = arg2->nodesetval;
4344
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004345 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004346 xmlXPathFreeObject(arg1);
4347 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004348 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004349 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004350 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004351 xmlXPathFreeObject(arg1);
4352 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004353 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004354 }
Owen Taylor3473f882001-02-23 17:55:21 +00004355
4356 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4357 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004358 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004359 xmlXPathFreeObject(arg1);
4360 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004361 return(0);
4362 }
4363 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004364 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004365 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004366 continue;
4367 for (j = 0;j < ns2->nodeNr;j++) {
4368 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004369 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004370 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004371 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004372 continue;
4373 if (inf && strict)
4374 ret = (val1 < values2[j]);
4375 else if (inf && !strict)
4376 ret = (val1 <= values2[j]);
4377 else if (!inf && strict)
4378 ret = (val1 > values2[j]);
4379 else if (!inf && !strict)
4380 ret = (val1 >= values2[j]);
4381 if (ret)
4382 break;
4383 }
4384 if (ret)
4385 break;
4386 init = 1;
4387 }
4388 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004389 xmlXPathFreeObject(arg1);
4390 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004391 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004392}
4393
4394/**
4395 * xmlXPathCompareNodeSetValue:
4396 * @ctxt: the XPath Parser context
4397 * @inf: less than (1) or greater than (0)
4398 * @strict: is the comparison strict
4399 * @arg: the node set
4400 * @val: the value
4401 *
4402 * Implement the compare operation between a nodeset and a value
4403 * @ns < @val (1, 1, ...
4404 * @ns <= @val (1, 0, ...
4405 * @ns > @val (0, 1, ...
4406 * @ns >= @val (0, 0, ...
4407 *
4408 * If one object to be compared is a node-set and the other is a boolean,
4409 * then the comparison will be true if and only if the result of performing
4410 * the comparison on the boolean and on the result of converting
4411 * the node-set to a boolean using the boolean function is true.
4412 *
4413 * Returns 0 or 1 depending on the results of the test.
4414 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004415static int
Owen Taylor3473f882001-02-23 17:55:21 +00004416xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4417 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4418 if ((val == NULL) || (arg == NULL) ||
4419 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4420 return(0);
4421
4422 switch(val->type) {
4423 case XPATH_NUMBER:
4424 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4425 case XPATH_NODESET:
4426 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004427 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004428 case XPATH_STRING:
4429 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4430 case XPATH_BOOLEAN:
4431 valuePush(ctxt, arg);
4432 xmlXPathBooleanFunction(ctxt, 1);
4433 valuePush(ctxt, val);
4434 return(xmlXPathCompareValues(ctxt, inf, strict));
4435 default:
4436 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004437 }
4438 return(0);
4439}
4440
4441/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004442 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004443 * @arg: the nodeset object argument
4444 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004445 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004446 *
4447 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4448 * If one object to be compared is a node-set and the other is a string,
4449 * then the comparison will be true if and only if there is a node in
4450 * the node-set such that the result of performing the comparison on the
4451 * string-value of the node and the other string is true.
4452 *
4453 * Returns 0 or 1 depending on the results of the test.
4454 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004455static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004456xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004457{
Owen Taylor3473f882001-02-23 17:55:21 +00004458 int i;
4459 xmlNodeSetPtr ns;
4460 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004461 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004462
4463 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004464 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4465 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004466 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004467 /*
4468 * A NULL nodeset compared with a string is always false
4469 * (since there is no node equal, and no node not equal)
4470 */
4471 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004472 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004473 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004474 for (i = 0; i < ns->nodeNr; i++) {
4475 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4476 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4477 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4478 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004479 if (neq)
4480 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004481 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004482 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4483 if (neq)
4484 continue;
4485 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 } else if (neq) {
4487 if (str2 != NULL)
4488 xmlFree(str2);
4489 return (1);
4490 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004491 if (str2 != NULL)
4492 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004493 } else if (neq)
4494 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004495 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004496 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004497}
4498
4499/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004500 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004501 * @arg: the nodeset object argument
4502 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004503 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004504 *
4505 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4506 * If one object to be compared is a node-set and the other is a number,
4507 * then the comparison will be true if and only if there is a node in
4508 * the node-set such that the result of performing the comparison on the
4509 * number to be compared and on the result of converting the string-value
4510 * of that node to a number using the number function is true.
4511 *
4512 * Returns 0 or 1 depending on the results of the test.
4513 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004514static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004515xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4516 xmlXPathObjectPtr arg, double f, int neq) {
4517 int i, ret=0;
4518 xmlNodeSetPtr ns;
4519 xmlChar *str2;
4520 xmlXPathObjectPtr val;
4521 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004522
4523 if ((arg == NULL) ||
4524 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4525 return(0);
4526
William M. Brack0c022ad2002-07-12 00:56:01 +00004527 ns = arg->nodesetval;
4528 if (ns != NULL) {
4529 for (i=0;i<ns->nodeNr;i++) {
4530 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4531 if (str2 != NULL) {
4532 valuePush(ctxt, xmlXPathNewString(str2));
4533 xmlFree(str2);
4534 xmlXPathNumberFunction(ctxt, 1);
4535 val = valuePop(ctxt);
4536 v = val->floatval;
4537 xmlXPathFreeObject(val);
4538 if (!xmlXPathIsNaN(v)) {
4539 if ((!neq) && (v==f)) {
4540 ret = 1;
4541 break;
4542 } else if ((neq) && (v!=f)) {
4543 ret = 1;
4544 break;
4545 }
4546 }
4547 }
4548 }
4549 }
4550
4551 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004552}
4553
4554
4555/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004556 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004557 * @arg1: first nodeset object argument
4558 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004559 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004560 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004561 * Implement the equal / not equal operation on XPath nodesets:
4562 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004563 * If both objects to be compared are node-sets, then the comparison
4564 * will be true if and only if there is a node in the first node-set and
4565 * a node in the second node-set such that the result of performing the
4566 * comparison on the string-values of the two nodes is true.
4567 *
4568 * (needless to say, this is a costly operation)
4569 *
4570 * Returns 0 or 1 depending on the results of the test.
4571 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004572static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004573xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004574 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004575 unsigned int *hashs1;
4576 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004577 xmlChar **values1;
4578 xmlChar **values2;
4579 int ret = 0;
4580 xmlNodeSetPtr ns1;
4581 xmlNodeSetPtr ns2;
4582
4583 if ((arg1 == NULL) ||
4584 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4585 return(0);
4586 if ((arg2 == NULL) ||
4587 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4588 return(0);
4589
4590 ns1 = arg1->nodesetval;
4591 ns2 = arg2->nodesetval;
4592
Daniel Veillard911f49a2001-04-07 15:39:35 +00004593 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004594 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004595 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004596 return(0);
4597
4598 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004599 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004600 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004601 if (neq == 0)
4602 for (i = 0;i < ns1->nodeNr;i++)
4603 for (j = 0;j < ns2->nodeNr;j++)
4604 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4605 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004606
4607 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004608 if (values1 == NULL) {
4609 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004610 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004611 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004612 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4613 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004614 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004615 xmlFree(values1);
4616 return(0);
4617 }
Owen Taylor3473f882001-02-23 17:55:21 +00004618 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4619 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4620 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004621 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004622 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004623 xmlFree(values1);
4624 return(0);
4625 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004626 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4627 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004628 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004629 xmlFree(hashs1);
4630 xmlFree(values1);
4631 xmlFree(values2);
4632 return(0);
4633 }
Owen Taylor3473f882001-02-23 17:55:21 +00004634 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4635 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004636 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004637 for (j = 0;j < ns2->nodeNr;j++) {
4638 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004639 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004640 if (hashs1[i] != hashs2[j]) {
4641 if (neq) {
4642 ret = 1;
4643 break;
4644 }
4645 }
4646 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004647 if (values1[i] == NULL)
4648 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4649 if (values2[j] == NULL)
4650 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004651 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004652 if (ret)
4653 break;
4654 }
Owen Taylor3473f882001-02-23 17:55:21 +00004655 }
4656 if (ret)
4657 break;
4658 }
4659 for (i = 0;i < ns1->nodeNr;i++)
4660 if (values1[i] != NULL)
4661 xmlFree(values1[i]);
4662 for (j = 0;j < ns2->nodeNr;j++)
4663 if (values2[j] != NULL)
4664 xmlFree(values2[j]);
4665 xmlFree(values1);
4666 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004667 xmlFree(hashs1);
4668 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004669 return(ret);
4670}
4671
William M. Brack0c022ad2002-07-12 00:56:01 +00004672static int
4673xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4674 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004675 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004676 /*
4677 *At this point we are assured neither arg1 nor arg2
4678 *is a nodeset, so we can just pick the appropriate routine.
4679 */
Owen Taylor3473f882001-02-23 17:55:21 +00004680 switch (arg1->type) {
4681 case XPATH_UNDEFINED:
4682#ifdef DEBUG_EXPR
4683 xmlGenericError(xmlGenericErrorContext,
4684 "Equal: undefined\n");
4685#endif
4686 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004687 case XPATH_BOOLEAN:
4688 switch (arg2->type) {
4689 case XPATH_UNDEFINED:
4690#ifdef DEBUG_EXPR
4691 xmlGenericError(xmlGenericErrorContext,
4692 "Equal: undefined\n");
4693#endif
4694 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004695 case XPATH_BOOLEAN:
4696#ifdef DEBUG_EXPR
4697 xmlGenericError(xmlGenericErrorContext,
4698 "Equal: %d boolean %d \n",
4699 arg1->boolval, arg2->boolval);
4700#endif
4701 ret = (arg1->boolval == arg2->boolval);
4702 break;
4703 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004704 ret = (arg1->boolval ==
4705 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004706 break;
4707 case XPATH_STRING:
4708 if ((arg2->stringval == NULL) ||
4709 (arg2->stringval[0] == 0)) ret = 0;
4710 else
4711 ret = 1;
4712 ret = (arg1->boolval == ret);
4713 break;
4714 case XPATH_USERS:
4715 case XPATH_POINT:
4716 case XPATH_RANGE:
4717 case XPATH_LOCATIONSET:
4718 TODO
4719 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004720 case XPATH_NODESET:
4721 case XPATH_XSLT_TREE:
4722 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004723 }
4724 break;
4725 case XPATH_NUMBER:
4726 switch (arg2->type) {
4727 case XPATH_UNDEFINED:
4728#ifdef DEBUG_EXPR
4729 xmlGenericError(xmlGenericErrorContext,
4730 "Equal: undefined\n");
4731#endif
4732 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004733 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004734 ret = (arg2->boolval==
4735 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004736 break;
4737 case XPATH_STRING:
4738 valuePush(ctxt, arg2);
4739 xmlXPathNumberFunction(ctxt, 1);
4740 arg2 = valuePop(ctxt);
4741 /* no break on purpose */
4742 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004743 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004744 if (xmlXPathIsNaN(arg1->floatval) ||
4745 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004746 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004747 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4748 if (xmlXPathIsInf(arg2->floatval) == 1)
4749 ret = 1;
4750 else
4751 ret = 0;
4752 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4753 if (xmlXPathIsInf(arg2->floatval) == -1)
4754 ret = 1;
4755 else
4756 ret = 0;
4757 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4758 if (xmlXPathIsInf(arg1->floatval) == 1)
4759 ret = 1;
4760 else
4761 ret = 0;
4762 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4763 if (xmlXPathIsInf(arg1->floatval) == -1)
4764 ret = 1;
4765 else
4766 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004767 } else {
4768 ret = (arg1->floatval == arg2->floatval);
4769 }
Owen Taylor3473f882001-02-23 17:55:21 +00004770 break;
4771 case XPATH_USERS:
4772 case XPATH_POINT:
4773 case XPATH_RANGE:
4774 case XPATH_LOCATIONSET:
4775 TODO
4776 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004777 case XPATH_NODESET:
4778 case XPATH_XSLT_TREE:
4779 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004780 }
4781 break;
4782 case XPATH_STRING:
4783 switch (arg2->type) {
4784 case XPATH_UNDEFINED:
4785#ifdef DEBUG_EXPR
4786 xmlGenericError(xmlGenericErrorContext,
4787 "Equal: undefined\n");
4788#endif
4789 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004790 case XPATH_BOOLEAN:
4791 if ((arg1->stringval == NULL) ||
4792 (arg1->stringval[0] == 0)) ret = 0;
4793 else
4794 ret = 1;
4795 ret = (arg2->boolval == ret);
4796 break;
4797 case XPATH_STRING:
4798 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4799 break;
4800 case XPATH_NUMBER:
4801 valuePush(ctxt, arg1);
4802 xmlXPathNumberFunction(ctxt, 1);
4803 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004804 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004805 if (xmlXPathIsNaN(arg1->floatval) ||
4806 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004807 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004808 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4809 if (xmlXPathIsInf(arg2->floatval) == 1)
4810 ret = 1;
4811 else
4812 ret = 0;
4813 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4814 if (xmlXPathIsInf(arg2->floatval) == -1)
4815 ret = 1;
4816 else
4817 ret = 0;
4818 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4819 if (xmlXPathIsInf(arg1->floatval) == 1)
4820 ret = 1;
4821 else
4822 ret = 0;
4823 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4824 if (xmlXPathIsInf(arg1->floatval) == -1)
4825 ret = 1;
4826 else
4827 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004828 } else {
4829 ret = (arg1->floatval == arg2->floatval);
4830 }
Owen Taylor3473f882001-02-23 17:55:21 +00004831 break;
4832 case XPATH_USERS:
4833 case XPATH_POINT:
4834 case XPATH_RANGE:
4835 case XPATH_LOCATIONSET:
4836 TODO
4837 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004838 case XPATH_NODESET:
4839 case XPATH_XSLT_TREE:
4840 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004841 }
4842 break;
4843 case XPATH_USERS:
4844 case XPATH_POINT:
4845 case XPATH_RANGE:
4846 case XPATH_LOCATIONSET:
4847 TODO
4848 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004849 case XPATH_NODESET:
4850 case XPATH_XSLT_TREE:
4851 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004852 }
4853 xmlXPathFreeObject(arg1);
4854 xmlXPathFreeObject(arg2);
4855 return(ret);
4856}
4857
William M. Brack0c022ad2002-07-12 00:56:01 +00004858/**
4859 * xmlXPathEqualValues:
4860 * @ctxt: the XPath Parser context
4861 *
4862 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4863 *
4864 * Returns 0 or 1 depending on the results of the test.
4865 */
4866int
4867xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4868 xmlXPathObjectPtr arg1, arg2, argtmp;
4869 int ret = 0;
4870
4871 arg2 = valuePop(ctxt);
4872 arg1 = valuePop(ctxt);
4873 if ((arg1 == NULL) || (arg2 == NULL)) {
4874 if (arg1 != NULL)
4875 xmlXPathFreeObject(arg1);
4876 else
4877 xmlXPathFreeObject(arg2);
4878 XP_ERROR0(XPATH_INVALID_OPERAND);
4879 }
4880
4881 if (arg1 == arg2) {
4882#ifdef DEBUG_EXPR
4883 xmlGenericError(xmlGenericErrorContext,
4884 "Equal: by pointer\n");
4885#endif
4886 return(1);
4887 }
4888
4889 /*
4890 *If either argument is a nodeset, it's a 'special case'
4891 */
4892 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4893 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4894 /*
4895 *Hack it to assure arg1 is the nodeset
4896 */
4897 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4898 argtmp = arg2;
4899 arg2 = arg1;
4900 arg1 = argtmp;
4901 }
4902 switch (arg2->type) {
4903 case XPATH_UNDEFINED:
4904#ifdef DEBUG_EXPR
4905 xmlGenericError(xmlGenericErrorContext,
4906 "Equal: undefined\n");
4907#endif
4908 break;
4909 case XPATH_NODESET:
4910 case XPATH_XSLT_TREE:
4911 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4912 break;
4913 case XPATH_BOOLEAN:
4914 if ((arg1->nodesetval == NULL) ||
4915 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4916 else
4917 ret = 1;
4918 ret = (ret == arg2->boolval);
4919 break;
4920 case XPATH_NUMBER:
4921 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4922 break;
4923 case XPATH_STRING:
4924 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4925 break;
4926 case XPATH_USERS:
4927 case XPATH_POINT:
4928 case XPATH_RANGE:
4929 case XPATH_LOCATIONSET:
4930 TODO
4931 break;
4932 }
4933 xmlXPathFreeObject(arg1);
4934 xmlXPathFreeObject(arg2);
4935 return(ret);
4936 }
4937
4938 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4939}
4940
4941/**
4942 * xmlXPathNotEqualValues:
4943 * @ctxt: the XPath Parser context
4944 *
4945 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4946 *
4947 * Returns 0 or 1 depending on the results of the test.
4948 */
4949int
4950xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4951 xmlXPathObjectPtr arg1, arg2, argtmp;
4952 int ret = 0;
4953
4954 arg2 = valuePop(ctxt);
4955 arg1 = valuePop(ctxt);
4956 if ((arg1 == NULL) || (arg2 == NULL)) {
4957 if (arg1 != NULL)
4958 xmlXPathFreeObject(arg1);
4959 else
4960 xmlXPathFreeObject(arg2);
4961 XP_ERROR0(XPATH_INVALID_OPERAND);
4962 }
4963
4964 if (arg1 == arg2) {
4965#ifdef DEBUG_EXPR
4966 xmlGenericError(xmlGenericErrorContext,
4967 "NotEqual: by pointer\n");
4968#endif
4969 return(0);
4970 }
4971
4972 /*
4973 *If either argument is a nodeset, it's a 'special case'
4974 */
4975 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4976 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4977 /*
4978 *Hack it to assure arg1 is the nodeset
4979 */
4980 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4981 argtmp = arg2;
4982 arg2 = arg1;
4983 arg1 = argtmp;
4984 }
4985 switch (arg2->type) {
4986 case XPATH_UNDEFINED:
4987#ifdef DEBUG_EXPR
4988 xmlGenericError(xmlGenericErrorContext,
4989 "NotEqual: undefined\n");
4990#endif
4991 break;
4992 case XPATH_NODESET:
4993 case XPATH_XSLT_TREE:
4994 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4995 break;
4996 case XPATH_BOOLEAN:
4997 if ((arg1->nodesetval == NULL) ||
4998 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4999 else
5000 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00005001 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00005002 break;
5003 case XPATH_NUMBER:
5004 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5005 break;
5006 case XPATH_STRING:
5007 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5008 break;
5009 case XPATH_USERS:
5010 case XPATH_POINT:
5011 case XPATH_RANGE:
5012 case XPATH_LOCATIONSET:
5013 TODO
5014 break;
5015 }
5016 xmlXPathFreeObject(arg1);
5017 xmlXPathFreeObject(arg2);
5018 return(ret);
5019 }
5020
5021 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5022}
Owen Taylor3473f882001-02-23 17:55:21 +00005023
5024/**
5025 * xmlXPathCompareValues:
5026 * @ctxt: the XPath Parser context
5027 * @inf: less than (1) or greater than (0)
5028 * @strict: is the comparison strict
5029 *
5030 * Implement the compare operation on XPath objects:
5031 * @arg1 < @arg2 (1, 1, ...
5032 * @arg1 <= @arg2 (1, 0, ...
5033 * @arg1 > @arg2 (0, 1, ...
5034 * @arg1 >= @arg2 (0, 0, ...
5035 *
5036 * When neither object to be compared is a node-set and the operator is
5037 * <=, <, >=, >, then the objects are compared by converted both objects
5038 * to numbers and comparing the numbers according to IEEE 754. The <
5039 * comparison will be true if and only if the first number is less than the
5040 * second number. The <= comparison will be true if and only if the first
5041 * number is less than or equal to the second number. The > comparison
5042 * will be true if and only if the first number is greater than the second
5043 * number. The >= comparison will be true if and only if the first number
5044 * is greater than or equal to the second number.
5045 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005046 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005047 */
5048int
5049xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005050 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005051 xmlXPathObjectPtr arg1, arg2;
5052
William M. Brack0c022ad2002-07-12 00:56:01 +00005053 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005054 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005055 if ((arg1 == NULL) || (arg2 == NULL)) {
5056 if (arg1 != NULL)
5057 xmlXPathFreeObject(arg1);
5058 else
5059 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005060 XP_ERROR0(XPATH_INVALID_OPERAND);
5061 }
5062
William M. Brack0c022ad2002-07-12 00:56:01 +00005063 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5064 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5065 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5066 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005067 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005068 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005069 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005070 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5071 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005072 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005073 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5074 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005075 }
5076 }
5077 return(ret);
5078 }
5079
5080 if (arg1->type != XPATH_NUMBER) {
5081 valuePush(ctxt, arg1);
5082 xmlXPathNumberFunction(ctxt, 1);
5083 arg1 = valuePop(ctxt);
5084 }
5085 if (arg1->type != XPATH_NUMBER) {
5086 xmlXPathFreeObject(arg1);
5087 xmlXPathFreeObject(arg2);
5088 XP_ERROR0(XPATH_INVALID_OPERAND);
5089 }
5090 if (arg2->type != XPATH_NUMBER) {
5091 valuePush(ctxt, arg2);
5092 xmlXPathNumberFunction(ctxt, 1);
5093 arg2 = valuePop(ctxt);
5094 }
5095 if (arg2->type != XPATH_NUMBER) {
5096 xmlXPathFreeObject(arg1);
5097 xmlXPathFreeObject(arg2);
5098 XP_ERROR0(XPATH_INVALID_OPERAND);
5099 }
5100 /*
5101 * Add tests for infinity and nan
5102 * => feedback on 3.4 for Inf and NaN
5103 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005104 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005105 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005106 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005107 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005108 arg1i=xmlXPathIsInf(arg1->floatval);
5109 arg2i=xmlXPathIsInf(arg2->floatval);
5110 if (inf && strict) {
5111 if ((arg1i == -1 && arg2i != -1) ||
5112 (arg2i == 1 && arg1i != 1)) {
5113 ret = 1;
5114 } else if (arg1i == 0 && arg2i == 0) {
5115 ret = (arg1->floatval < arg2->floatval);
5116 } else {
5117 ret = 0;
5118 }
5119 }
5120 else if (inf && !strict) {
5121 if (arg1i == -1 || arg2i == 1) {
5122 ret = 1;
5123 } else if (arg1i == 0 && arg2i == 0) {
5124 ret = (arg1->floatval <= arg2->floatval);
5125 } else {
5126 ret = 0;
5127 }
5128 }
5129 else if (!inf && strict) {
5130 if ((arg1i == 1 && arg2i != 1) ||
5131 (arg2i == -1 && arg1i != -1)) {
5132 ret = 1;
5133 } else if (arg1i == 0 && arg2i == 0) {
5134 ret = (arg1->floatval > arg2->floatval);
5135 } else {
5136 ret = 0;
5137 }
5138 }
5139 else if (!inf && !strict) {
5140 if (arg1i == 1 || arg2i == -1) {
5141 ret = 1;
5142 } else if (arg1i == 0 && arg2i == 0) {
5143 ret = (arg1->floatval >= arg2->floatval);
5144 } else {
5145 ret = 0;
5146 }
5147 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005148 }
Owen Taylor3473f882001-02-23 17:55:21 +00005149 xmlXPathFreeObject(arg1);
5150 xmlXPathFreeObject(arg2);
5151 return(ret);
5152}
5153
5154/**
5155 * xmlXPathValueFlipSign:
5156 * @ctxt: the XPath Parser context
5157 *
5158 * Implement the unary - operation on an XPath object
5159 * The numeric operators convert their operands to numbers as if
5160 * by calling the number function.
5161 */
5162void
5163xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005164 CAST_TO_NUMBER;
5165 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005166 if (xmlXPathIsNaN(ctxt->value->floatval))
5167 ctxt->value->floatval=xmlXPathNAN;
5168 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5169 ctxt->value->floatval=xmlXPathNINF;
5170 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5171 ctxt->value->floatval=xmlXPathPINF;
5172 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005173 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5174 ctxt->value->floatval = xmlXPathNZERO;
5175 else
5176 ctxt->value->floatval = 0;
5177 }
5178 else
5179 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005180}
5181
5182/**
5183 * xmlXPathAddValues:
5184 * @ctxt: the XPath Parser context
5185 *
5186 * Implement the add operation on XPath objects:
5187 * The numeric operators convert their operands to numbers as if
5188 * by calling the number function.
5189 */
5190void
5191xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5192 xmlXPathObjectPtr arg;
5193 double val;
5194
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005195 arg = valuePop(ctxt);
5196 if (arg == NULL)
5197 XP_ERROR(XPATH_INVALID_OPERAND);
5198 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005199 xmlXPathFreeObject(arg);
5200
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005201 CAST_TO_NUMBER;
5202 CHECK_TYPE(XPATH_NUMBER);
5203 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005204}
5205
5206/**
5207 * xmlXPathSubValues:
5208 * @ctxt: the XPath Parser context
5209 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005210 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005211 * The numeric operators convert their operands to numbers as if
5212 * by calling the number function.
5213 */
5214void
5215xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5216 xmlXPathObjectPtr arg;
5217 double val;
5218
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005219 arg = valuePop(ctxt);
5220 if (arg == NULL)
5221 XP_ERROR(XPATH_INVALID_OPERAND);
5222 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005223 xmlXPathFreeObject(arg);
5224
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005225 CAST_TO_NUMBER;
5226 CHECK_TYPE(XPATH_NUMBER);
5227 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005228}
5229
5230/**
5231 * xmlXPathMultValues:
5232 * @ctxt: the XPath Parser context
5233 *
5234 * Implement the multiply operation on XPath objects:
5235 * The numeric operators convert their operands to numbers as if
5236 * by calling the number function.
5237 */
5238void
5239xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5240 xmlXPathObjectPtr arg;
5241 double val;
5242
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005243 arg = valuePop(ctxt);
5244 if (arg == NULL)
5245 XP_ERROR(XPATH_INVALID_OPERAND);
5246 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005247 xmlXPathFreeObject(arg);
5248
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005249 CAST_TO_NUMBER;
5250 CHECK_TYPE(XPATH_NUMBER);
5251 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005252}
5253
5254/**
5255 * xmlXPathDivValues:
5256 * @ctxt: the XPath Parser context
5257 *
5258 * Implement the div operation on XPath objects @arg1 / @arg2:
5259 * The numeric operators convert their operands to numbers as if
5260 * by calling the number function.
5261 */
5262void
5263xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5264 xmlXPathObjectPtr arg;
5265 double val;
5266
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005267 arg = valuePop(ctxt);
5268 if (arg == NULL)
5269 XP_ERROR(XPATH_INVALID_OPERAND);
5270 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005271 xmlXPathFreeObject(arg);
5272
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005273 CAST_TO_NUMBER;
5274 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005275 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5276 ctxt->value->floatval = xmlXPathNAN;
5277 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005278 if (ctxt->value->floatval == 0)
5279 ctxt->value->floatval = xmlXPathNAN;
5280 else if (ctxt->value->floatval > 0)
5281 ctxt->value->floatval = xmlXPathNINF;
5282 else if (ctxt->value->floatval < 0)
5283 ctxt->value->floatval = xmlXPathPINF;
5284 }
5285 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005286 if (ctxt->value->floatval == 0)
5287 ctxt->value->floatval = xmlXPathNAN;
5288 else if (ctxt->value->floatval > 0)
5289 ctxt->value->floatval = xmlXPathPINF;
5290 else if (ctxt->value->floatval < 0)
5291 ctxt->value->floatval = xmlXPathNINF;
5292 } else
5293 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005294}
5295
5296/**
5297 * xmlXPathModValues:
5298 * @ctxt: the XPath Parser context
5299 *
5300 * Implement the mod operation on XPath objects: @arg1 / @arg2
5301 * The numeric operators convert their operands to numbers as if
5302 * by calling the number function.
5303 */
5304void
5305xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5306 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005307 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005308
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005309 arg = valuePop(ctxt);
5310 if (arg == NULL)
5311 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005312 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005313 xmlXPathFreeObject(arg);
5314
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005315 CAST_TO_NUMBER;
5316 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005317 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005318 if (arg2 == 0)
5319 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005320 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005321 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005322 }
Owen Taylor3473f882001-02-23 17:55:21 +00005323}
5324
5325/************************************************************************
5326 * *
5327 * The traversal functions *
5328 * *
5329 ************************************************************************/
5330
Owen Taylor3473f882001-02-23 17:55:21 +00005331/*
5332 * A traversal function enumerates nodes along an axis.
5333 * Initially it must be called with NULL, and it indicates
5334 * termination on the axis by returning NULL.
5335 */
5336typedef xmlNodePtr (*xmlXPathTraversalFunction)
5337 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5338
5339/**
5340 * xmlXPathNextSelf:
5341 * @ctxt: the XPath Parser context
5342 * @cur: the current node in the traversal
5343 *
5344 * Traversal function for the "self" direction
5345 * The self axis contains just the context node itself
5346 *
5347 * Returns the next element following that axis
5348 */
5349xmlNodePtr
5350xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5351 if (cur == NULL)
5352 return(ctxt->context->node);
5353 return(NULL);
5354}
5355
5356/**
5357 * xmlXPathNextChild:
5358 * @ctxt: the XPath Parser context
5359 * @cur: the current node in the traversal
5360 *
5361 * Traversal function for the "child" direction
5362 * The child axis contains the children of the context node in document order.
5363 *
5364 * Returns the next element following that axis
5365 */
5366xmlNodePtr
5367xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5368 if (cur == NULL) {
5369 if (ctxt->context->node == NULL) return(NULL);
5370 switch (ctxt->context->node->type) {
5371 case XML_ELEMENT_NODE:
5372 case XML_TEXT_NODE:
5373 case XML_CDATA_SECTION_NODE:
5374 case XML_ENTITY_REF_NODE:
5375 case XML_ENTITY_NODE:
5376 case XML_PI_NODE:
5377 case XML_COMMENT_NODE:
5378 case XML_NOTATION_NODE:
5379 case XML_DTD_NODE:
5380 return(ctxt->context->node->children);
5381 case XML_DOCUMENT_NODE:
5382 case XML_DOCUMENT_TYPE_NODE:
5383 case XML_DOCUMENT_FRAG_NODE:
5384 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005385#ifdef LIBXML_DOCB_ENABLED
5386 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005387#endif
5388 return(((xmlDocPtr) ctxt->context->node)->children);
5389 case XML_ELEMENT_DECL:
5390 case XML_ATTRIBUTE_DECL:
5391 case XML_ENTITY_DECL:
5392 case XML_ATTRIBUTE_NODE:
5393 case XML_NAMESPACE_DECL:
5394 case XML_XINCLUDE_START:
5395 case XML_XINCLUDE_END:
5396 return(NULL);
5397 }
5398 return(NULL);
5399 }
5400 if ((cur->type == XML_DOCUMENT_NODE) ||
5401 (cur->type == XML_HTML_DOCUMENT_NODE))
5402 return(NULL);
5403 return(cur->next);
5404}
5405
5406/**
5407 * xmlXPathNextDescendant:
5408 * @ctxt: the XPath Parser context
5409 * @cur: the current node in the traversal
5410 *
5411 * Traversal function for the "descendant" direction
5412 * the descendant axis contains the descendants of the context node in document
5413 * order; a descendant is a child or a child of a child and so on.
5414 *
5415 * Returns the next element following that axis
5416 */
5417xmlNodePtr
5418xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5419 if (cur == NULL) {
5420 if (ctxt->context->node == NULL)
5421 return(NULL);
5422 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5423 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5424 return(NULL);
5425
5426 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5427 return(ctxt->context->doc->children);
5428 return(ctxt->context->node->children);
5429 }
5430
Daniel Veillard567e1b42001-08-01 15:53:47 +00005431 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005432 /*
5433 * Do not descend on entities declarations
5434 */
5435 if (cur->children->type != XML_ENTITY_DECL) {
5436 cur = cur->children;
5437 /*
5438 * Skip DTDs
5439 */
5440 if (cur->type != XML_DTD_NODE)
5441 return(cur);
5442 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005443 }
5444
5445 if (cur == ctxt->context->node) return(NULL);
5446
Daniel Veillard68e9e742002-11-16 15:35:11 +00005447 while (cur->next != NULL) {
5448 cur = cur->next;
5449 if ((cur->type != XML_ENTITY_DECL) &&
5450 (cur->type != XML_DTD_NODE))
5451 return(cur);
5452 }
Owen Taylor3473f882001-02-23 17:55:21 +00005453
5454 do {
5455 cur = cur->parent;
5456 if (cur == NULL) return(NULL);
5457 if (cur == ctxt->context->node) return(NULL);
5458 if (cur->next != NULL) {
5459 cur = cur->next;
5460 return(cur);
5461 }
5462 } while (cur != NULL);
5463 return(cur);
5464}
5465
5466/**
5467 * xmlXPathNextDescendantOrSelf:
5468 * @ctxt: the XPath Parser context
5469 * @cur: the current node in the traversal
5470 *
5471 * Traversal function for the "descendant-or-self" direction
5472 * the descendant-or-self axis contains the context node and the descendants
5473 * of the context node in document order; thus the context node is the first
5474 * node on the axis, and the first child of the context node is the second node
5475 * on the axis
5476 *
5477 * Returns the next element following that axis
5478 */
5479xmlNodePtr
5480xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5481 if (cur == NULL) {
5482 if (ctxt->context->node == NULL)
5483 return(NULL);
5484 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5485 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5486 return(NULL);
5487 return(ctxt->context->node);
5488 }
5489
5490 return(xmlXPathNextDescendant(ctxt, cur));
5491}
5492
5493/**
5494 * xmlXPathNextParent:
5495 * @ctxt: the XPath Parser context
5496 * @cur: the current node in the traversal
5497 *
5498 * Traversal function for the "parent" direction
5499 * The parent axis contains the parent of the context node, if there is one.
5500 *
5501 * Returns the next element following that axis
5502 */
5503xmlNodePtr
5504xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5505 /*
5506 * the parent of an attribute or namespace node is the element
5507 * to which the attribute or namespace node is attached
5508 * Namespace handling !!!
5509 */
5510 if (cur == NULL) {
5511 if (ctxt->context->node == NULL) return(NULL);
5512 switch (ctxt->context->node->type) {
5513 case XML_ELEMENT_NODE:
5514 case XML_TEXT_NODE:
5515 case XML_CDATA_SECTION_NODE:
5516 case XML_ENTITY_REF_NODE:
5517 case XML_ENTITY_NODE:
5518 case XML_PI_NODE:
5519 case XML_COMMENT_NODE:
5520 case XML_NOTATION_NODE:
5521 case XML_DTD_NODE:
5522 case XML_ELEMENT_DECL:
5523 case XML_ATTRIBUTE_DECL:
5524 case XML_XINCLUDE_START:
5525 case XML_XINCLUDE_END:
5526 case XML_ENTITY_DECL:
5527 if (ctxt->context->node->parent == NULL)
5528 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005529 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005530 ((ctxt->context->node->parent->name[0] == ' ') ||
5531 (xmlStrEqual(ctxt->context->node->parent->name,
5532 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005533 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005534 return(ctxt->context->node->parent);
5535 case XML_ATTRIBUTE_NODE: {
5536 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5537
5538 return(att->parent);
5539 }
5540 case XML_DOCUMENT_NODE:
5541 case XML_DOCUMENT_TYPE_NODE:
5542 case XML_DOCUMENT_FRAG_NODE:
5543 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005544#ifdef LIBXML_DOCB_ENABLED
5545 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005546#endif
5547 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005548 case XML_NAMESPACE_DECL: {
5549 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5550
5551 if ((ns->next != NULL) &&
5552 (ns->next->type != XML_NAMESPACE_DECL))
5553 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005554 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005555 }
Owen Taylor3473f882001-02-23 17:55:21 +00005556 }
5557 }
5558 return(NULL);
5559}
5560
5561/**
5562 * xmlXPathNextAncestor:
5563 * @ctxt: the XPath Parser context
5564 * @cur: the current node in the traversal
5565 *
5566 * Traversal function for the "ancestor" direction
5567 * the ancestor axis contains the ancestors of the context node; the ancestors
5568 * of the context node consist of the parent of context node and the parent's
5569 * parent and so on; the nodes are ordered in reverse document order; thus the
5570 * parent is the first node on the axis, and the parent's parent is the second
5571 * node on the axis
5572 *
5573 * Returns the next element following that axis
5574 */
5575xmlNodePtr
5576xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5577 /*
5578 * the parent of an attribute or namespace node is the element
5579 * to which the attribute or namespace node is attached
5580 * !!!!!!!!!!!!!
5581 */
5582 if (cur == NULL) {
5583 if (ctxt->context->node == NULL) return(NULL);
5584 switch (ctxt->context->node->type) {
5585 case XML_ELEMENT_NODE:
5586 case XML_TEXT_NODE:
5587 case XML_CDATA_SECTION_NODE:
5588 case XML_ENTITY_REF_NODE:
5589 case XML_ENTITY_NODE:
5590 case XML_PI_NODE:
5591 case XML_COMMENT_NODE:
5592 case XML_DTD_NODE:
5593 case XML_ELEMENT_DECL:
5594 case XML_ATTRIBUTE_DECL:
5595 case XML_ENTITY_DECL:
5596 case XML_NOTATION_NODE:
5597 case XML_XINCLUDE_START:
5598 case XML_XINCLUDE_END:
5599 if (ctxt->context->node->parent == NULL)
5600 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005601 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005602 ((ctxt->context->node->parent->name[0] == ' ') ||
5603 (xmlStrEqual(ctxt->context->node->parent->name,
5604 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005605 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005606 return(ctxt->context->node->parent);
5607 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005608 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005609
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005610 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005611 }
5612 case XML_DOCUMENT_NODE:
5613 case XML_DOCUMENT_TYPE_NODE:
5614 case XML_DOCUMENT_FRAG_NODE:
5615 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005616#ifdef LIBXML_DOCB_ENABLED
5617 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005618#endif
5619 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005620 case XML_NAMESPACE_DECL: {
5621 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5622
5623 if ((ns->next != NULL) &&
5624 (ns->next->type != XML_NAMESPACE_DECL))
5625 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005626 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005627 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005628 }
Owen Taylor3473f882001-02-23 17:55:21 +00005629 }
5630 return(NULL);
5631 }
5632 if (cur == ctxt->context->doc->children)
5633 return((xmlNodePtr) ctxt->context->doc);
5634 if (cur == (xmlNodePtr) ctxt->context->doc)
5635 return(NULL);
5636 switch (cur->type) {
5637 case XML_ELEMENT_NODE:
5638 case XML_TEXT_NODE:
5639 case XML_CDATA_SECTION_NODE:
5640 case XML_ENTITY_REF_NODE:
5641 case XML_ENTITY_NODE:
5642 case XML_PI_NODE:
5643 case XML_COMMENT_NODE:
5644 case XML_NOTATION_NODE:
5645 case XML_DTD_NODE:
5646 case XML_ELEMENT_DECL:
5647 case XML_ATTRIBUTE_DECL:
5648 case XML_ENTITY_DECL:
5649 case XML_XINCLUDE_START:
5650 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005651 if (cur->parent == NULL)
5652 return(NULL);
5653 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005654 ((cur->parent->name[0] == ' ') ||
5655 (xmlStrEqual(cur->parent->name,
5656 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005657 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005658 return(cur->parent);
5659 case XML_ATTRIBUTE_NODE: {
5660 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5661
5662 return(att->parent);
5663 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005664 case XML_NAMESPACE_DECL: {
5665 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5666
5667 if ((ns->next != NULL) &&
5668 (ns->next->type != XML_NAMESPACE_DECL))
5669 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005670 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005671 return(NULL);
5672 }
Owen Taylor3473f882001-02-23 17:55:21 +00005673 case XML_DOCUMENT_NODE:
5674 case XML_DOCUMENT_TYPE_NODE:
5675 case XML_DOCUMENT_FRAG_NODE:
5676 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005677#ifdef LIBXML_DOCB_ENABLED
5678 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005679#endif
5680 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005681 }
5682 return(NULL);
5683}
5684
5685/**
5686 * xmlXPathNextAncestorOrSelf:
5687 * @ctxt: the XPath Parser context
5688 * @cur: the current node in the traversal
5689 *
5690 * Traversal function for the "ancestor-or-self" direction
5691 * he ancestor-or-self axis contains the context node and ancestors of
5692 * the context node in reverse document order; thus the context node is
5693 * the first node on the axis, and the context node's parent the second;
5694 * parent here is defined the same as with the parent axis.
5695 *
5696 * Returns the next element following that axis
5697 */
5698xmlNodePtr
5699xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5700 if (cur == NULL)
5701 return(ctxt->context->node);
5702 return(xmlXPathNextAncestor(ctxt, cur));
5703}
5704
5705/**
5706 * xmlXPathNextFollowingSibling:
5707 * @ctxt: the XPath Parser context
5708 * @cur: the current node in the traversal
5709 *
5710 * Traversal function for the "following-sibling" direction
5711 * The following-sibling axis contains the following siblings of the context
5712 * node in document order.
5713 *
5714 * Returns the next element following that axis
5715 */
5716xmlNodePtr
5717xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5718 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5719 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5720 return(NULL);
5721 if (cur == (xmlNodePtr) ctxt->context->doc)
5722 return(NULL);
5723 if (cur == NULL)
5724 return(ctxt->context->node->next);
5725 return(cur->next);
5726}
5727
5728/**
5729 * xmlXPathNextPrecedingSibling:
5730 * @ctxt: the XPath Parser context
5731 * @cur: the current node in the traversal
5732 *
5733 * Traversal function for the "preceding-sibling" direction
5734 * The preceding-sibling axis contains the preceding siblings of the context
5735 * node in reverse document order; the first preceding sibling is first on the
5736 * axis; the sibling preceding that node is the second on the axis and so on.
5737 *
5738 * Returns the next element following that axis
5739 */
5740xmlNodePtr
5741xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5742 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5743 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5744 return(NULL);
5745 if (cur == (xmlNodePtr) ctxt->context->doc)
5746 return(NULL);
5747 if (cur == NULL)
5748 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005749 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5750 cur = cur->prev;
5751 if (cur == NULL)
5752 return(ctxt->context->node->prev);
5753 }
Owen Taylor3473f882001-02-23 17:55:21 +00005754 return(cur->prev);
5755}
5756
5757/**
5758 * xmlXPathNextFollowing:
5759 * @ctxt: the XPath Parser context
5760 * @cur: the current node in the traversal
5761 *
5762 * Traversal function for the "following" direction
5763 * The following axis contains all nodes in the same document as the context
5764 * node that are after the context node in document order, excluding any
5765 * descendants and excluding attribute nodes and namespace nodes; the nodes
5766 * are ordered in document order
5767 *
5768 * Returns the next element following that axis
5769 */
5770xmlNodePtr
5771xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5772 if (cur != NULL && cur->children != NULL)
5773 return cur->children ;
5774 if (cur == NULL) cur = ctxt->context->node;
5775 if (cur == NULL) return(NULL) ; /* ERROR */
5776 if (cur->next != NULL) return(cur->next) ;
5777 do {
5778 cur = cur->parent;
5779 if (cur == NULL) return(NULL);
5780 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5781 if (cur->next != NULL) return(cur->next);
5782 } while (cur != NULL);
5783 return(cur);
5784}
5785
5786/*
5787 * xmlXPathIsAncestor:
5788 * @ancestor: the ancestor node
5789 * @node: the current node
5790 *
5791 * Check that @ancestor is a @node's ancestor
5792 *
5793 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5794 */
5795static int
5796xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5797 if ((ancestor == NULL) || (node == NULL)) return(0);
5798 /* nodes need to be in the same document */
5799 if (ancestor->doc != node->doc) return(0);
5800 /* avoid searching if ancestor or node is the root node */
5801 if (ancestor == (xmlNodePtr) node->doc) return(1);
5802 if (node == (xmlNodePtr) ancestor->doc) return(0);
5803 while (node->parent != NULL) {
5804 if (node->parent == ancestor)
5805 return(1);
5806 node = node->parent;
5807 }
5808 return(0);
5809}
5810
5811/**
5812 * xmlXPathNextPreceding:
5813 * @ctxt: the XPath Parser context
5814 * @cur: the current node in the traversal
5815 *
5816 * Traversal function for the "preceding" direction
5817 * the preceding axis contains all nodes in the same document as the context
5818 * node that are before the context node in document order, excluding any
5819 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5820 * ordered in reverse document order
5821 *
5822 * Returns the next element following that axis
5823 */
5824xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005825xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5826{
Owen Taylor3473f882001-02-23 17:55:21 +00005827 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005828 cur = ctxt->context->node;
5829 if (cur == NULL)
5830 return (NULL);
5831 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5832 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005833 do {
5834 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005835 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5836 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005837 }
5838
5839 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005840 if (cur == NULL)
5841 return (NULL);
5842 if (cur == ctxt->context->doc->children)
5843 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005844 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005845 return (cur);
5846}
5847
5848/**
5849 * xmlXPathNextPrecedingInternal:
5850 * @ctxt: the XPath Parser context
5851 * @cur: the current node in the traversal
5852 *
5853 * Traversal function for the "preceding" direction
5854 * the preceding axis contains all nodes in the same document as the context
5855 * node that are before the context node in document order, excluding any
5856 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5857 * ordered in reverse document order
5858 * This is a faster implementation but internal only since it requires a
5859 * state kept in the parser context: ctxt->ancestor.
5860 *
5861 * Returns the next element following that axis
5862 */
5863static xmlNodePtr
5864xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5865 xmlNodePtr cur)
5866{
5867 if (cur == NULL) {
5868 cur = ctxt->context->node;
5869 if (cur == NULL)
5870 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005871 if (cur->type == XML_NAMESPACE_DECL)
5872 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005873 ctxt->ancestor = cur->parent;
5874 }
5875 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5876 cur = cur->prev;
5877 while (cur->prev == NULL) {
5878 cur = cur->parent;
5879 if (cur == NULL)
5880 return (NULL);
5881 if (cur == ctxt->context->doc->children)
5882 return (NULL);
5883 if (cur != ctxt->ancestor)
5884 return (cur);
5885 ctxt->ancestor = cur->parent;
5886 }
5887 cur = cur->prev;
5888 while (cur->last != NULL)
5889 cur = cur->last;
5890 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005891}
5892
5893/**
5894 * xmlXPathNextNamespace:
5895 * @ctxt: the XPath Parser context
5896 * @cur: the current attribute in the traversal
5897 *
5898 * Traversal function for the "namespace" direction
5899 * the namespace axis contains the namespace nodes of the context node;
5900 * the order of nodes on this axis is implementation-defined; the axis will
5901 * be empty unless the context node is an element
5902 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005903 * We keep the XML namespace node at the end of the list.
5904 *
Owen Taylor3473f882001-02-23 17:55:21 +00005905 * Returns the next element following that axis
5906 */
5907xmlNodePtr
5908xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5909 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005910 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005911 if (ctxt->context->tmpNsList != NULL)
5912 xmlFree(ctxt->context->tmpNsList);
5913 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005914 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005915 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005916 if (ctxt->context->tmpNsList != NULL) {
5917 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5918 ctxt->context->tmpNsNr++;
5919 }
5920 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005921 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005922 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005923 if (ctxt->context->tmpNsNr > 0) {
5924 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5925 } else {
5926 if (ctxt->context->tmpNsList != NULL)
5927 xmlFree(ctxt->context->tmpNsList);
5928 ctxt->context->tmpNsList = NULL;
5929 return(NULL);
5930 }
Owen Taylor3473f882001-02-23 17:55:21 +00005931}
5932
5933/**
5934 * xmlXPathNextAttribute:
5935 * @ctxt: the XPath Parser context
5936 * @cur: the current attribute in the traversal
5937 *
5938 * Traversal function for the "attribute" direction
5939 * TODO: support DTD inherited default attributes
5940 *
5941 * Returns the next element following that axis
5942 */
5943xmlNodePtr
5944xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005945 if (ctxt->context->node == NULL)
5946 return(NULL);
5947 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5948 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005949 if (cur == NULL) {
5950 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5951 return(NULL);
5952 return((xmlNodePtr)ctxt->context->node->properties);
5953 }
5954 return((xmlNodePtr)cur->next);
5955}
5956
5957/************************************************************************
5958 * *
5959 * NodeTest Functions *
5960 * *
5961 ************************************************************************/
5962
Owen Taylor3473f882001-02-23 17:55:21 +00005963#define IS_FUNCTION 200
5964
Owen Taylor3473f882001-02-23 17:55:21 +00005965
5966/************************************************************************
5967 * *
5968 * Implicit tree core function library *
5969 * *
5970 ************************************************************************/
5971
5972/**
5973 * xmlXPathRoot:
5974 * @ctxt: the XPath Parser context
5975 *
5976 * Initialize the context to the root of the document
5977 */
5978void
5979xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5980 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5981 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5982}
5983
5984/************************************************************************
5985 * *
5986 * The explicit core function library *
5987 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5988 * *
5989 ************************************************************************/
5990
5991
5992/**
5993 * xmlXPathLastFunction:
5994 * @ctxt: the XPath Parser context
5995 * @nargs: the number of arguments
5996 *
5997 * Implement the last() XPath function
5998 * number last()
5999 * The last function returns the number of nodes in the context node list.
6000 */
6001void
6002xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6003 CHECK_ARITY(0);
6004 if (ctxt->context->contextSize >= 0) {
6005 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
6006#ifdef DEBUG_EXPR
6007 xmlGenericError(xmlGenericErrorContext,
6008 "last() : %d\n", ctxt->context->contextSize);
6009#endif
6010 } else {
6011 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6012 }
6013}
6014
6015/**
6016 * xmlXPathPositionFunction:
6017 * @ctxt: the XPath Parser context
6018 * @nargs: the number of arguments
6019 *
6020 * Implement the position() XPath function
6021 * number position()
6022 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006023 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006024 * will be equal to last().
6025 */
6026void
6027xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6028 CHECK_ARITY(0);
6029 if (ctxt->context->proximityPosition >= 0) {
6030 valuePush(ctxt,
6031 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6032#ifdef DEBUG_EXPR
6033 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6034 ctxt->context->proximityPosition);
6035#endif
6036 } else {
6037 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6038 }
6039}
6040
6041/**
6042 * xmlXPathCountFunction:
6043 * @ctxt: the XPath Parser context
6044 * @nargs: the number of arguments
6045 *
6046 * Implement the count() XPath function
6047 * number count(node-set)
6048 */
6049void
6050xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6051 xmlXPathObjectPtr cur;
6052
6053 CHECK_ARITY(1);
6054 if ((ctxt->value == NULL) ||
6055 ((ctxt->value->type != XPATH_NODESET) &&
6056 (ctxt->value->type != XPATH_XSLT_TREE)))
6057 XP_ERROR(XPATH_INVALID_TYPE);
6058 cur = valuePop(ctxt);
6059
Daniel Veillard911f49a2001-04-07 15:39:35 +00006060 if ((cur == NULL) || (cur->nodesetval == NULL))
6061 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006062 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006063 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006064 } else {
6065 if ((cur->nodesetval->nodeNr != 1) ||
6066 (cur->nodesetval->nodeTab == NULL)) {
6067 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6068 } else {
6069 xmlNodePtr tmp;
6070 int i = 0;
6071
6072 tmp = cur->nodesetval->nodeTab[0];
6073 if (tmp != NULL) {
6074 tmp = tmp->children;
6075 while (tmp != NULL) {
6076 tmp = tmp->next;
6077 i++;
6078 }
6079 }
6080 valuePush(ctxt, xmlXPathNewFloat((double) i));
6081 }
6082 }
Owen Taylor3473f882001-02-23 17:55:21 +00006083 xmlXPathFreeObject(cur);
6084}
6085
6086/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006087 * xmlXPathGetElementsByIds:
6088 * @doc: the document
6089 * @ids: a whitespace separated list of IDs
6090 *
6091 * Selects elements by their unique ID.
6092 *
6093 * Returns a node-set of selected elements.
6094 */
6095static xmlNodeSetPtr
6096xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6097 xmlNodeSetPtr ret;
6098 const xmlChar *cur = ids;
6099 xmlChar *ID;
6100 xmlAttrPtr attr;
6101 xmlNodePtr elem = NULL;
6102
Daniel Veillard7a985a12003-07-06 17:57:42 +00006103 if (ids == NULL) return(NULL);
6104
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006105 ret = xmlXPathNodeSetCreate(NULL);
6106
William M. Brack76e95df2003-10-18 16:20:14 +00006107 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006108 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006109 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006110 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006111
6112 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006113 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006114 /*
6115 * We used to check the fact that the value passed
6116 * was an NCName, but this generated much troubles for
6117 * me and Aleksey Sanin, people blatantly violated that
6118 * constaint, like Visa3D spec.
6119 * if (xmlValidateNCName(ID, 1) == 0)
6120 */
6121 attr = xmlGetID(doc, ID);
6122 if (attr != NULL) {
6123 if (attr->type == XML_ATTRIBUTE_NODE)
6124 elem = attr->parent;
6125 else if (attr->type == XML_ELEMENT_NODE)
6126 elem = (xmlNodePtr) attr;
6127 else
6128 elem = NULL;
6129 if (elem != NULL)
6130 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006131 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006132 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006133 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006134
William M. Brack76e95df2003-10-18 16:20:14 +00006135 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006136 ids = cur;
6137 }
6138 return(ret);
6139}
6140
6141/**
Owen Taylor3473f882001-02-23 17:55:21 +00006142 * xmlXPathIdFunction:
6143 * @ctxt: the XPath Parser context
6144 * @nargs: the number of arguments
6145 *
6146 * Implement the id() XPath function
6147 * node-set id(object)
6148 * The id function selects elements by their unique ID
6149 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6150 * then the result is the union of the result of applying id to the
6151 * string value of each of the nodes in the argument node-set. When the
6152 * argument to id is of any other type, the argument is converted to a
6153 * string as if by a call to the string function; the string is split
6154 * into a whitespace-separated list of tokens (whitespace is any sequence
6155 * of characters matching the production S); the result is a node-set
6156 * containing the elements in the same document as the context node that
6157 * have a unique ID equal to any of the tokens in the list.
6158 */
6159void
6160xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006161 xmlChar *tokens;
6162 xmlNodeSetPtr ret;
6163 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006164
6165 CHECK_ARITY(1);
6166 obj = valuePop(ctxt);
6167 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006168 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006169 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006170 int i;
6171
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006172 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006173
Daniel Veillard911f49a2001-04-07 15:39:35 +00006174 if (obj->nodesetval != NULL) {
6175 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006176 tokens =
6177 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6178 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6179 ret = xmlXPathNodeSetMerge(ret, ns);
6180 xmlXPathFreeNodeSet(ns);
6181 if (tokens != NULL)
6182 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006183 }
Owen Taylor3473f882001-02-23 17:55:21 +00006184 }
6185
6186 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006187 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006188 return;
6189 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006190 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006191
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006192 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6193 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006194
Owen Taylor3473f882001-02-23 17:55:21 +00006195 xmlXPathFreeObject(obj);
6196 return;
6197}
6198
6199/**
6200 * xmlXPathLocalNameFunction:
6201 * @ctxt: the XPath Parser context
6202 * @nargs: the number of arguments
6203 *
6204 * Implement the local-name() XPath function
6205 * string local-name(node-set?)
6206 * The local-name function returns a string containing the local part
6207 * of the name of the node in the argument node-set that is first in
6208 * document order. If the node-set is empty or the first node has no
6209 * name, an empty string is returned. If the argument is omitted it
6210 * defaults to the context node.
6211 */
6212void
6213xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6214 xmlXPathObjectPtr cur;
6215
6216 if (nargs == 0) {
6217 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6218 nargs = 1;
6219 }
6220
6221 CHECK_ARITY(1);
6222 if ((ctxt->value == NULL) ||
6223 ((ctxt->value->type != XPATH_NODESET) &&
6224 (ctxt->value->type != XPATH_XSLT_TREE)))
6225 XP_ERROR(XPATH_INVALID_TYPE);
6226 cur = valuePop(ctxt);
6227
Daniel Veillard911f49a2001-04-07 15:39:35 +00006228 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006229 valuePush(ctxt, xmlXPathNewCString(""));
6230 } else {
6231 int i = 0; /* Should be first in document order !!!!! */
6232 switch (cur->nodesetval->nodeTab[i]->type) {
6233 case XML_ELEMENT_NODE:
6234 case XML_ATTRIBUTE_NODE:
6235 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006236 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6237 valuePush(ctxt, xmlXPathNewCString(""));
6238 else
6239 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006240 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6241 break;
6242 case XML_NAMESPACE_DECL:
6243 valuePush(ctxt, xmlXPathNewString(
6244 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6245 break;
6246 default:
6247 valuePush(ctxt, xmlXPathNewCString(""));
6248 }
6249 }
6250 xmlXPathFreeObject(cur);
6251}
6252
6253/**
6254 * xmlXPathNamespaceURIFunction:
6255 * @ctxt: the XPath Parser context
6256 * @nargs: the number of arguments
6257 *
6258 * Implement the namespace-uri() XPath function
6259 * string namespace-uri(node-set?)
6260 * The namespace-uri function returns a string containing the
6261 * namespace URI of the expanded name of the node in the argument
6262 * node-set that is first in document order. If the node-set is empty,
6263 * the first node has no name, or the expanded name has no namespace
6264 * URI, an empty string is returned. If the argument is omitted it
6265 * defaults to the context node.
6266 */
6267void
6268xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6269 xmlXPathObjectPtr cur;
6270
6271 if (nargs == 0) {
6272 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6273 nargs = 1;
6274 }
6275 CHECK_ARITY(1);
6276 if ((ctxt->value == NULL) ||
6277 ((ctxt->value->type != XPATH_NODESET) &&
6278 (ctxt->value->type != XPATH_XSLT_TREE)))
6279 XP_ERROR(XPATH_INVALID_TYPE);
6280 cur = valuePop(ctxt);
6281
Daniel Veillard911f49a2001-04-07 15:39:35 +00006282 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006283 valuePush(ctxt, xmlXPathNewCString(""));
6284 } else {
6285 int i = 0; /* Should be first in document order !!!!! */
6286 switch (cur->nodesetval->nodeTab[i]->type) {
6287 case XML_ELEMENT_NODE:
6288 case XML_ATTRIBUTE_NODE:
6289 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6290 valuePush(ctxt, xmlXPathNewCString(""));
6291 else
6292 valuePush(ctxt, xmlXPathNewString(
6293 cur->nodesetval->nodeTab[i]->ns->href));
6294 break;
6295 default:
6296 valuePush(ctxt, xmlXPathNewCString(""));
6297 }
6298 }
6299 xmlXPathFreeObject(cur);
6300}
6301
6302/**
6303 * xmlXPathNameFunction:
6304 * @ctxt: the XPath Parser context
6305 * @nargs: the number of arguments
6306 *
6307 * Implement the name() XPath function
6308 * string name(node-set?)
6309 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006310 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006311 * order. The QName must represent the name with respect to the namespace
6312 * declarations in effect on the node whose name is being represented.
6313 * Typically, this will be the form in which the name occurred in the XML
6314 * source. This need not be the case if there are namespace declarations
6315 * in effect on the node that associate multiple prefixes with the same
6316 * namespace. However, an implementation may include information about
6317 * the original prefix in its representation of nodes; in this case, an
6318 * implementation can ensure that the returned string is always the same
6319 * as the QName used in the XML source. If the argument it omitted it
6320 * defaults to the context node.
6321 * Libxml keep the original prefix so the "real qualified name" used is
6322 * returned.
6323 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006324static void
Daniel Veillard04383752001-07-08 14:27:15 +00006325xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6326{
Owen Taylor3473f882001-02-23 17:55:21 +00006327 xmlXPathObjectPtr cur;
6328
6329 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006330 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6331 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006332 }
6333
6334 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006335 if ((ctxt->value == NULL) ||
6336 ((ctxt->value->type != XPATH_NODESET) &&
6337 (ctxt->value->type != XPATH_XSLT_TREE)))
6338 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006339 cur = valuePop(ctxt);
6340
Daniel Veillard911f49a2001-04-07 15:39:35 +00006341 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006342 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006343 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006344 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006345
Daniel Veillard04383752001-07-08 14:27:15 +00006346 switch (cur->nodesetval->nodeTab[i]->type) {
6347 case XML_ELEMENT_NODE:
6348 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006349 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6350 valuePush(ctxt, xmlXPathNewCString(""));
6351 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6352 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006353 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006354 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006355
Daniel Veillard652d8a92003-02-04 19:28:49 +00006356 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006357 xmlChar *fullname;
6358
6359 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6360 cur->nodesetval->nodeTab[i]->ns->prefix,
6361 NULL, 0);
6362 if (fullname == cur->nodesetval->nodeTab[i]->name)
6363 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6364 if (fullname == NULL) {
6365 XP_ERROR(XPATH_MEMORY_ERROR);
6366 }
6367 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006368 }
6369 break;
6370 default:
6371 valuePush(ctxt,
6372 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6373 xmlXPathLocalNameFunction(ctxt, 1);
6374 }
Owen Taylor3473f882001-02-23 17:55:21 +00006375 }
6376 xmlXPathFreeObject(cur);
6377}
6378
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006379
6380/**
Owen Taylor3473f882001-02-23 17:55:21 +00006381 * xmlXPathStringFunction:
6382 * @ctxt: the XPath Parser context
6383 * @nargs: the number of arguments
6384 *
6385 * Implement the string() XPath function
6386 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006387 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006388 * - A node-set is converted to a string by returning the value of
6389 * the node in the node-set that is first in document order.
6390 * If the node-set is empty, an empty string is returned.
6391 * - A number is converted to a string as follows
6392 * + NaN is converted to the string NaN
6393 * + positive zero is converted to the string 0
6394 * + negative zero is converted to the string 0
6395 * + positive infinity is converted to the string Infinity
6396 * + negative infinity is converted to the string -Infinity
6397 * + if the number is an integer, the number is represented in
6398 * decimal form as a Number with no decimal point and no leading
6399 * zeros, preceded by a minus sign (-) if the number is negative
6400 * + otherwise, the number is represented in decimal form as a
6401 * Number including a decimal point with at least one digit
6402 * before the decimal point and at least one digit after the
6403 * decimal point, preceded by a minus sign (-) if the number
6404 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006405 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006406 * before the decimal point; beyond the one required digit
6407 * after the decimal point there must be as many, but only as
6408 * many, more digits as are needed to uniquely distinguish the
6409 * number from all other IEEE 754 numeric values.
6410 * - The boolean false value is converted to the string false.
6411 * The boolean true value is converted to the string true.
6412 *
6413 * If the argument is omitted, it defaults to a node-set with the
6414 * context node as its only member.
6415 */
6416void
6417xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6418 xmlXPathObjectPtr cur;
6419
6420 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006421 valuePush(ctxt,
6422 xmlXPathWrapString(
6423 xmlXPathCastNodeToString(ctxt->context->node)));
6424 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006425 }
6426
6427 CHECK_ARITY(1);
6428 cur = valuePop(ctxt);
6429 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006430 cur = xmlXPathConvertString(cur);
6431 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006432}
6433
6434/**
6435 * xmlXPathStringLengthFunction:
6436 * @ctxt: the XPath Parser context
6437 * @nargs: the number of arguments
6438 *
6439 * Implement the string-length() XPath function
6440 * number string-length(string?)
6441 * The string-length returns the number of characters in the string
6442 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6443 * the context node converted to a string, in other words the value
6444 * of the context node.
6445 */
6446void
6447xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6448 xmlXPathObjectPtr cur;
6449
6450 if (nargs == 0) {
6451 if (ctxt->context->node == NULL) {
6452 valuePush(ctxt, xmlXPathNewFloat(0));
6453 } else {
6454 xmlChar *content;
6455
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006456 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006457 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006458 xmlFree(content);
6459 }
6460 return;
6461 }
6462 CHECK_ARITY(1);
6463 CAST_TO_STRING;
6464 CHECK_TYPE(XPATH_STRING);
6465 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006466 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006467 xmlXPathFreeObject(cur);
6468}
6469
6470/**
6471 * xmlXPathConcatFunction:
6472 * @ctxt: the XPath Parser context
6473 * @nargs: the number of arguments
6474 *
6475 * Implement the concat() XPath function
6476 * string concat(string, string, string*)
6477 * The concat function returns the concatenation of its arguments.
6478 */
6479void
6480xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6481 xmlXPathObjectPtr cur, newobj;
6482 xmlChar *tmp;
6483
6484 if (nargs < 2) {
6485 CHECK_ARITY(2);
6486 }
6487
6488 CAST_TO_STRING;
6489 cur = valuePop(ctxt);
6490 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6491 xmlXPathFreeObject(cur);
6492 return;
6493 }
6494 nargs--;
6495
6496 while (nargs > 0) {
6497 CAST_TO_STRING;
6498 newobj = valuePop(ctxt);
6499 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6500 xmlXPathFreeObject(newobj);
6501 xmlXPathFreeObject(cur);
6502 XP_ERROR(XPATH_INVALID_TYPE);
6503 }
6504 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6505 newobj->stringval = cur->stringval;
6506 cur->stringval = tmp;
6507
6508 xmlXPathFreeObject(newobj);
6509 nargs--;
6510 }
6511 valuePush(ctxt, cur);
6512}
6513
6514/**
6515 * xmlXPathContainsFunction:
6516 * @ctxt: the XPath Parser context
6517 * @nargs: the number of arguments
6518 *
6519 * Implement the contains() XPath function
6520 * boolean contains(string, string)
6521 * The contains function returns true if the first argument string
6522 * contains the second argument string, and otherwise returns false.
6523 */
6524void
6525xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6526 xmlXPathObjectPtr hay, needle;
6527
6528 CHECK_ARITY(2);
6529 CAST_TO_STRING;
6530 CHECK_TYPE(XPATH_STRING);
6531 needle = valuePop(ctxt);
6532 CAST_TO_STRING;
6533 hay = valuePop(ctxt);
6534 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6535 xmlXPathFreeObject(hay);
6536 xmlXPathFreeObject(needle);
6537 XP_ERROR(XPATH_INVALID_TYPE);
6538 }
6539 if (xmlStrstr(hay->stringval, needle->stringval))
6540 valuePush(ctxt, xmlXPathNewBoolean(1));
6541 else
6542 valuePush(ctxt, xmlXPathNewBoolean(0));
6543 xmlXPathFreeObject(hay);
6544 xmlXPathFreeObject(needle);
6545}
6546
6547/**
6548 * xmlXPathStartsWithFunction:
6549 * @ctxt: the XPath Parser context
6550 * @nargs: the number of arguments
6551 *
6552 * Implement the starts-with() XPath function
6553 * boolean starts-with(string, string)
6554 * The starts-with function returns true if the first argument string
6555 * starts with the second argument string, and otherwise returns false.
6556 */
6557void
6558xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6559 xmlXPathObjectPtr hay, needle;
6560 int n;
6561
6562 CHECK_ARITY(2);
6563 CAST_TO_STRING;
6564 CHECK_TYPE(XPATH_STRING);
6565 needle = valuePop(ctxt);
6566 CAST_TO_STRING;
6567 hay = valuePop(ctxt);
6568 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6569 xmlXPathFreeObject(hay);
6570 xmlXPathFreeObject(needle);
6571 XP_ERROR(XPATH_INVALID_TYPE);
6572 }
6573 n = xmlStrlen(needle->stringval);
6574 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6575 valuePush(ctxt, xmlXPathNewBoolean(0));
6576 else
6577 valuePush(ctxt, xmlXPathNewBoolean(1));
6578 xmlXPathFreeObject(hay);
6579 xmlXPathFreeObject(needle);
6580}
6581
6582/**
6583 * xmlXPathSubstringFunction:
6584 * @ctxt: the XPath Parser context
6585 * @nargs: the number of arguments
6586 *
6587 * Implement the substring() XPath function
6588 * string substring(string, number, number?)
6589 * The substring function returns the substring of the first argument
6590 * starting at the position specified in the second argument with
6591 * length specified in the third argument. For example,
6592 * substring("12345",2,3) returns "234". If the third argument is not
6593 * specified, it returns the substring starting at the position specified
6594 * in the second argument and continuing to the end of the string. For
6595 * example, substring("12345",2) returns "2345". More precisely, each
6596 * character in the string (see [3.6 Strings]) is considered to have a
6597 * numeric position: the position of the first character is 1, the position
6598 * of the second character is 2 and so on. The returned substring contains
6599 * those characters for which the position of the character is greater than
6600 * or equal to the second argument and, if the third argument is specified,
6601 * less than the sum of the second and third arguments; the comparisons
6602 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6603 * - substring("12345", 1.5, 2.6) returns "234"
6604 * - substring("12345", 0, 3) returns "12"
6605 * - substring("12345", 0 div 0, 3) returns ""
6606 * - substring("12345", 1, 0 div 0) returns ""
6607 * - substring("12345", -42, 1 div 0) returns "12345"
6608 * - substring("12345", -1 div 0, 1 div 0) returns ""
6609 */
6610void
6611xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6612 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006613 double le=0, in;
6614 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006615 xmlChar *ret;
6616
Owen Taylor3473f882001-02-23 17:55:21 +00006617 if (nargs < 2) {
6618 CHECK_ARITY(2);
6619 }
6620 if (nargs > 3) {
6621 CHECK_ARITY(3);
6622 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006623 /*
6624 * take care of possible last (position) argument
6625 */
Owen Taylor3473f882001-02-23 17:55:21 +00006626 if (nargs == 3) {
6627 CAST_TO_NUMBER;
6628 CHECK_TYPE(XPATH_NUMBER);
6629 len = valuePop(ctxt);
6630 le = len->floatval;
6631 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006632 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006633
Owen Taylor3473f882001-02-23 17:55:21 +00006634 CAST_TO_NUMBER;
6635 CHECK_TYPE(XPATH_NUMBER);
6636 start = valuePop(ctxt);
6637 in = start->floatval;
6638 xmlXPathFreeObject(start);
6639 CAST_TO_STRING;
6640 CHECK_TYPE(XPATH_STRING);
6641 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006642 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006643
Daniel Veillard97ac1312001-05-30 19:14:17 +00006644 /*
6645 * If last pos not present, calculate last position
6646 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006647 if (nargs != 3) {
6648 le = (double)m;
6649 if (in < 1.0)
6650 in = 1.0;
6651 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006652
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006653 /* Need to check for the special cases where either
6654 * the index is NaN, the length is NaN, or both
6655 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006656 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006657 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006658 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006659 * To meet the requirements of the spec, the arguments
6660 * must be converted to integer format before
6661 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006662 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006663 * First we go to integer form, rounding up
6664 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006665 */
6666 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006667 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006668
Daniel Veillard9e412302002-06-10 15:59:44 +00006669 if (xmlXPathIsInf(le) == 1) {
6670 l = m;
6671 if (i < 1)
6672 i = 1;
6673 }
6674 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6675 l = 0;
6676 else {
6677 l = (int) le;
6678 if (((double)l)+0.5 <= le) l++;
6679 }
6680
6681 /* Now we normalize inidices */
6682 i -= 1;
6683 l += i;
6684 if (i < 0)
6685 i = 0;
6686 if (l > m)
6687 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006688
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006689 /* number of chars to copy */
6690 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006691
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006692 ret = xmlUTF8Strsub(str->stringval, i, l);
6693 }
6694 else {
6695 ret = NULL;
6696 }
6697
Owen Taylor3473f882001-02-23 17:55:21 +00006698 if (ret == NULL)
6699 valuePush(ctxt, xmlXPathNewCString(""));
6700 else {
6701 valuePush(ctxt, xmlXPathNewString(ret));
6702 xmlFree(ret);
6703 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006704
Owen Taylor3473f882001-02-23 17:55:21 +00006705 xmlXPathFreeObject(str);
6706}
6707
6708/**
6709 * xmlXPathSubstringBeforeFunction:
6710 * @ctxt: the XPath Parser context
6711 * @nargs: the number of arguments
6712 *
6713 * Implement the substring-before() XPath function
6714 * string substring-before(string, string)
6715 * The substring-before function returns the substring of the first
6716 * argument string that precedes the first occurrence of the second
6717 * argument string in the first argument string, or the empty string
6718 * if the first argument string does not contain the second argument
6719 * string. For example, substring-before("1999/04/01","/") returns 1999.
6720 */
6721void
6722xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6723 xmlXPathObjectPtr str;
6724 xmlXPathObjectPtr find;
6725 xmlBufferPtr target;
6726 const xmlChar *point;
6727 int offset;
6728
6729 CHECK_ARITY(2);
6730 CAST_TO_STRING;
6731 find = valuePop(ctxt);
6732 CAST_TO_STRING;
6733 str = valuePop(ctxt);
6734
6735 target = xmlBufferCreate();
6736 if (target) {
6737 point = xmlStrstr(str->stringval, find->stringval);
6738 if (point) {
6739 offset = (int)(point - str->stringval);
6740 xmlBufferAdd(target, str->stringval, offset);
6741 }
6742 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6743 xmlBufferFree(target);
6744 }
6745
6746 xmlXPathFreeObject(str);
6747 xmlXPathFreeObject(find);
6748}
6749
6750/**
6751 * xmlXPathSubstringAfterFunction:
6752 * @ctxt: the XPath Parser context
6753 * @nargs: the number of arguments
6754 *
6755 * Implement the substring-after() XPath function
6756 * string substring-after(string, string)
6757 * The substring-after function returns the substring of the first
6758 * argument string that follows the first occurrence of the second
6759 * argument string in the first argument string, or the empty stringi
6760 * if the first argument string does not contain the second argument
6761 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6762 * and substring-after("1999/04/01","19") returns 99/04/01.
6763 */
6764void
6765xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6766 xmlXPathObjectPtr str;
6767 xmlXPathObjectPtr find;
6768 xmlBufferPtr target;
6769 const xmlChar *point;
6770 int offset;
6771
6772 CHECK_ARITY(2);
6773 CAST_TO_STRING;
6774 find = valuePop(ctxt);
6775 CAST_TO_STRING;
6776 str = valuePop(ctxt);
6777
6778 target = xmlBufferCreate();
6779 if (target) {
6780 point = xmlStrstr(str->stringval, find->stringval);
6781 if (point) {
6782 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6783 xmlBufferAdd(target, &str->stringval[offset],
6784 xmlStrlen(str->stringval) - offset);
6785 }
6786 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6787 xmlBufferFree(target);
6788 }
6789
6790 xmlXPathFreeObject(str);
6791 xmlXPathFreeObject(find);
6792}
6793
6794/**
6795 * xmlXPathNormalizeFunction:
6796 * @ctxt: the XPath Parser context
6797 * @nargs: the number of arguments
6798 *
6799 * Implement the normalize-space() XPath function
6800 * string normalize-space(string?)
6801 * The normalize-space function returns the argument string with white
6802 * space normalized by stripping leading and trailing whitespace
6803 * and replacing sequences of whitespace characters by a single
6804 * space. Whitespace characters are the same allowed by the S production
6805 * in XML. If the argument is omitted, it defaults to the context
6806 * node converted to a string, in other words the value of the context node.
6807 */
6808void
6809xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6810 xmlXPathObjectPtr obj = NULL;
6811 xmlChar *source = NULL;
6812 xmlBufferPtr target;
6813 xmlChar blank;
6814
6815 if (nargs == 0) {
6816 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006817 valuePush(ctxt,
6818 xmlXPathWrapString(
6819 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006820 nargs = 1;
6821 }
6822
6823 CHECK_ARITY(1);
6824 CAST_TO_STRING;
6825 CHECK_TYPE(XPATH_STRING);
6826 obj = valuePop(ctxt);
6827 source = obj->stringval;
6828
6829 target = xmlBufferCreate();
6830 if (target && source) {
6831
6832 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006833 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006834 source++;
6835
6836 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6837 blank = 0;
6838 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006839 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006840 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006841 } else {
6842 if (blank) {
6843 xmlBufferAdd(target, &blank, 1);
6844 blank = 0;
6845 }
6846 xmlBufferAdd(target, source, 1);
6847 }
6848 source++;
6849 }
6850
6851 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6852 xmlBufferFree(target);
6853 }
6854 xmlXPathFreeObject(obj);
6855}
6856
6857/**
6858 * xmlXPathTranslateFunction:
6859 * @ctxt: the XPath Parser context
6860 * @nargs: the number of arguments
6861 *
6862 * Implement the translate() XPath function
6863 * string translate(string, string, string)
6864 * The translate function returns the first argument string with
6865 * occurrences of characters in the second argument string replaced
6866 * by the character at the corresponding position in the third argument
6867 * string. For example, translate("bar","abc","ABC") returns the string
6868 * BAr. If there is a character in the second argument string with no
6869 * character at a corresponding position in the third argument string
6870 * (because the second argument string is longer than the third argument
6871 * string), then occurrences of that character in the first argument
6872 * string are removed. For example, translate("--aaa--","abc-","ABC")
6873 * returns "AAA". If a character occurs more than once in second
6874 * argument string, then the first occurrence determines the replacement
6875 * character. If the third argument string is longer than the second
6876 * argument string, then excess characters are ignored.
6877 */
6878void
6879xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006880 xmlXPathObjectPtr str;
6881 xmlXPathObjectPtr from;
6882 xmlXPathObjectPtr to;
6883 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006884 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006885 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006886 xmlChar *point;
6887 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006888
Daniel Veillarde043ee12001-04-16 14:08:07 +00006889 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006890
Daniel Veillarde043ee12001-04-16 14:08:07 +00006891 CAST_TO_STRING;
6892 to = valuePop(ctxt);
6893 CAST_TO_STRING;
6894 from = valuePop(ctxt);
6895 CAST_TO_STRING;
6896 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006897
Daniel Veillarde043ee12001-04-16 14:08:07 +00006898 target = xmlBufferCreate();
6899 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006900 max = xmlUTF8Strlen(to->stringval);
6901 for (cptr = str->stringval; (ch=*cptr); ) {
6902 offset = xmlUTF8Strloc(from->stringval, cptr);
6903 if (offset >= 0) {
6904 if (offset < max) {
6905 point = xmlUTF8Strpos(to->stringval, offset);
6906 if (point)
6907 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6908 }
6909 } else
6910 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6911
6912 /* Step to next character in input */
6913 cptr++;
6914 if ( ch & 0x80 ) {
6915 /* if not simple ascii, verify proper format */
6916 if ( (ch & 0xc0) != 0xc0 ) {
6917 xmlGenericError(xmlGenericErrorContext,
6918 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6919 break;
6920 }
6921 /* then skip over remaining bytes for this char */
6922 while ( (ch <<= 1) & 0x80 )
6923 if ( (*cptr++ & 0xc0) != 0x80 ) {
6924 xmlGenericError(xmlGenericErrorContext,
6925 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6926 break;
6927 }
6928 if (ch & 0x80) /* must have had error encountered */
6929 break;
6930 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006931 }
Owen Taylor3473f882001-02-23 17:55:21 +00006932 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006933 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6934 xmlBufferFree(target);
6935 xmlXPathFreeObject(str);
6936 xmlXPathFreeObject(from);
6937 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006938}
6939
6940/**
6941 * xmlXPathBooleanFunction:
6942 * @ctxt: the XPath Parser context
6943 * @nargs: the number of arguments
6944 *
6945 * Implement the boolean() XPath function
6946 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006947 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006948 * - a number is true if and only if it is neither positive or
6949 * negative zero nor NaN
6950 * - a node-set is true if and only if it is non-empty
6951 * - a string is true if and only if its length is non-zero
6952 */
6953void
6954xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6955 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006956
6957 CHECK_ARITY(1);
6958 cur = valuePop(ctxt);
6959 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006960 cur = xmlXPathConvertBoolean(cur);
6961 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006962}
6963
6964/**
6965 * xmlXPathNotFunction:
6966 * @ctxt: the XPath Parser context
6967 * @nargs: the number of arguments
6968 *
6969 * Implement the not() XPath function
6970 * boolean not(boolean)
6971 * The not function returns true if its argument is false,
6972 * and false otherwise.
6973 */
6974void
6975xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6976 CHECK_ARITY(1);
6977 CAST_TO_BOOLEAN;
6978 CHECK_TYPE(XPATH_BOOLEAN);
6979 ctxt->value->boolval = ! ctxt->value->boolval;
6980}
6981
6982/**
6983 * xmlXPathTrueFunction:
6984 * @ctxt: the XPath Parser context
6985 * @nargs: the number of arguments
6986 *
6987 * Implement the true() XPath function
6988 * boolean true()
6989 */
6990void
6991xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6992 CHECK_ARITY(0);
6993 valuePush(ctxt, xmlXPathNewBoolean(1));
6994}
6995
6996/**
6997 * xmlXPathFalseFunction:
6998 * @ctxt: the XPath Parser context
6999 * @nargs: the number of arguments
7000 *
7001 * Implement the false() XPath function
7002 * boolean false()
7003 */
7004void
7005xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7006 CHECK_ARITY(0);
7007 valuePush(ctxt, xmlXPathNewBoolean(0));
7008}
7009
7010/**
7011 * xmlXPathLangFunction:
7012 * @ctxt: the XPath Parser context
7013 * @nargs: the number of arguments
7014 *
7015 * Implement the lang() XPath function
7016 * boolean lang(string)
7017 * The lang function returns true or false depending on whether the
7018 * language of the context node as specified by xml:lang attributes
7019 * is the same as or is a sublanguage of the language specified by
7020 * the argument string. The language of the context node is determined
7021 * by the value of the xml:lang attribute on the context node, or, if
7022 * the context node has no xml:lang attribute, by the value of the
7023 * xml:lang attribute on the nearest ancestor of the context node that
7024 * has an xml:lang attribute. If there is no such attribute, then lang
7025 * returns false. If there is such an attribute, then lang returns
7026 * true if the attribute value is equal to the argument ignoring case,
7027 * or if there is some suffix starting with - such that the attribute
7028 * value is equal to the argument ignoring that suffix of the attribute
7029 * value and ignoring case.
7030 */
7031void
7032xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7033 xmlXPathObjectPtr val;
7034 const xmlChar *theLang;
7035 const xmlChar *lang;
7036 int ret = 0;
7037 int i;
7038
7039 CHECK_ARITY(1);
7040 CAST_TO_STRING;
7041 CHECK_TYPE(XPATH_STRING);
7042 val = valuePop(ctxt);
7043 lang = val->stringval;
7044 theLang = xmlNodeGetLang(ctxt->context->node);
7045 if ((theLang != NULL) && (lang != NULL)) {
7046 for (i = 0;lang[i] != 0;i++)
7047 if (toupper(lang[i]) != toupper(theLang[i]))
7048 goto not_equal;
7049 ret = 1;
7050 }
7051not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007052 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007053 xmlXPathFreeObject(val);
7054 valuePush(ctxt, xmlXPathNewBoolean(ret));
7055}
7056
7057/**
7058 * xmlXPathNumberFunction:
7059 * @ctxt: the XPath Parser context
7060 * @nargs: the number of arguments
7061 *
7062 * Implement the number() XPath function
7063 * number number(object?)
7064 */
7065void
7066xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7067 xmlXPathObjectPtr cur;
7068 double res;
7069
7070 if (nargs == 0) {
7071 if (ctxt->context->node == NULL) {
7072 valuePush(ctxt, xmlXPathNewFloat(0.0));
7073 } else {
7074 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7075
7076 res = xmlXPathStringEvalNumber(content);
7077 valuePush(ctxt, xmlXPathNewFloat(res));
7078 xmlFree(content);
7079 }
7080 return;
7081 }
7082
7083 CHECK_ARITY(1);
7084 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007085 cur = xmlXPathConvertNumber(cur);
7086 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007087}
7088
7089/**
7090 * xmlXPathSumFunction:
7091 * @ctxt: the XPath Parser context
7092 * @nargs: the number of arguments
7093 *
7094 * Implement the sum() XPath function
7095 * number sum(node-set)
7096 * The sum function returns the sum of the values of the nodes in
7097 * the argument node-set.
7098 */
7099void
7100xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7101 xmlXPathObjectPtr cur;
7102 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007103 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007104
7105 CHECK_ARITY(1);
7106 if ((ctxt->value == NULL) ||
7107 ((ctxt->value->type != XPATH_NODESET) &&
7108 (ctxt->value->type != XPATH_XSLT_TREE)))
7109 XP_ERROR(XPATH_INVALID_TYPE);
7110 cur = valuePop(ctxt);
7111
William M. Brack08171912003-12-29 02:52:11 +00007112 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007113 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7114 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007115 }
7116 }
William M. Brack08171912003-12-29 02:52:11 +00007117 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007118 xmlXPathFreeObject(cur);
7119}
7120
7121/**
7122 * xmlXPathFloorFunction:
7123 * @ctxt: the XPath Parser context
7124 * @nargs: the number of arguments
7125 *
7126 * Implement the floor() XPath function
7127 * number floor(number)
7128 * The floor function returns the largest (closest to positive infinity)
7129 * number that is not greater than the argument and that is an integer.
7130 */
7131void
7132xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007133 double f;
7134
Owen Taylor3473f882001-02-23 17:55:21 +00007135 CHECK_ARITY(1);
7136 CAST_TO_NUMBER;
7137 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007138
7139 f = (double)((int) ctxt->value->floatval);
7140 if (f != ctxt->value->floatval) {
7141 if (ctxt->value->floatval > 0)
7142 ctxt->value->floatval = f;
7143 else
7144 ctxt->value->floatval = f - 1;
7145 }
Owen Taylor3473f882001-02-23 17:55:21 +00007146}
7147
7148/**
7149 * xmlXPathCeilingFunction:
7150 * @ctxt: the XPath Parser context
7151 * @nargs: the number of arguments
7152 *
7153 * Implement the ceiling() XPath function
7154 * number ceiling(number)
7155 * The ceiling function returns the smallest (closest to negative infinity)
7156 * number that is not less than the argument and that is an integer.
7157 */
7158void
7159xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7160 double f;
7161
7162 CHECK_ARITY(1);
7163 CAST_TO_NUMBER;
7164 CHECK_TYPE(XPATH_NUMBER);
7165
7166#if 0
7167 ctxt->value->floatval = ceil(ctxt->value->floatval);
7168#else
7169 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007170 if (f != ctxt->value->floatval) {
7171 if (ctxt->value->floatval > 0)
7172 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007173 else {
7174 if (ctxt->value->floatval < 0 && f == 0)
7175 ctxt->value->floatval = xmlXPathNZERO;
7176 else
7177 ctxt->value->floatval = f;
7178 }
7179
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007180 }
Owen Taylor3473f882001-02-23 17:55:21 +00007181#endif
7182}
7183
7184/**
7185 * xmlXPathRoundFunction:
7186 * @ctxt: the XPath Parser context
7187 * @nargs: the number of arguments
7188 *
7189 * Implement the round() XPath function
7190 * number round(number)
7191 * The round function returns the number that is closest to the
7192 * argument and that is an integer. If there are two such numbers,
7193 * then the one that is even is returned.
7194 */
7195void
7196xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7197 double f;
7198
7199 CHECK_ARITY(1);
7200 CAST_TO_NUMBER;
7201 CHECK_TYPE(XPATH_NUMBER);
7202
Daniel Veillardcda96922001-08-21 10:56:31 +00007203 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7204 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7205 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007206 (ctxt->value->floatval == 0.0))
7207 return;
7208
Owen Taylor3473f882001-02-23 17:55:21 +00007209 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007210 if (ctxt->value->floatval < 0) {
7211 if (ctxt->value->floatval < f - 0.5)
7212 ctxt->value->floatval = f - 1;
7213 else
7214 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007215 if (ctxt->value->floatval == 0)
7216 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007217 } else {
7218 if (ctxt->value->floatval < f + 0.5)
7219 ctxt->value->floatval = f;
7220 else
7221 ctxt->value->floatval = f + 1;
7222 }
Owen Taylor3473f882001-02-23 17:55:21 +00007223}
7224
7225/************************************************************************
7226 * *
7227 * The Parser *
7228 * *
7229 ************************************************************************/
7230
7231/*
William M. Brack08171912003-12-29 02:52:11 +00007232 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007233 * implementation.
7234 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007235static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007236static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007237static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007238static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007239static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7240 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007241
7242/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007243 * xmlXPathCurrentChar:
7244 * @ctxt: the XPath parser context
7245 * @cur: pointer to the beginning of the char
7246 * @len: pointer to the length of the char read
7247 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007248 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007249 * bytes in the input buffer.
7250 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007251 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007252 */
7253
7254static int
7255xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7256 unsigned char c;
7257 unsigned int val;
7258 const xmlChar *cur;
7259
7260 if (ctxt == NULL)
7261 return(0);
7262 cur = ctxt->cur;
7263
7264 /*
7265 * We are supposed to handle UTF8, check it's valid
7266 * From rfc2044: encoding of the Unicode values on UTF-8:
7267 *
7268 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7269 * 0000 0000-0000 007F 0xxxxxxx
7270 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7271 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7272 *
7273 * Check for the 0x110000 limit too
7274 */
7275 c = *cur;
7276 if (c & 0x80) {
7277 if ((cur[1] & 0xc0) != 0x80)
7278 goto encoding_error;
7279 if ((c & 0xe0) == 0xe0) {
7280
7281 if ((cur[2] & 0xc0) != 0x80)
7282 goto encoding_error;
7283 if ((c & 0xf0) == 0xf0) {
7284 if (((c & 0xf8) != 0xf0) ||
7285 ((cur[3] & 0xc0) != 0x80))
7286 goto encoding_error;
7287 /* 4-byte code */
7288 *len = 4;
7289 val = (cur[0] & 0x7) << 18;
7290 val |= (cur[1] & 0x3f) << 12;
7291 val |= (cur[2] & 0x3f) << 6;
7292 val |= cur[3] & 0x3f;
7293 } else {
7294 /* 3-byte code */
7295 *len = 3;
7296 val = (cur[0] & 0xf) << 12;
7297 val |= (cur[1] & 0x3f) << 6;
7298 val |= cur[2] & 0x3f;
7299 }
7300 } else {
7301 /* 2-byte code */
7302 *len = 2;
7303 val = (cur[0] & 0x1f) << 6;
7304 val |= cur[1] & 0x3f;
7305 }
7306 if (!IS_CHAR(val)) {
7307 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7308 }
7309 return(val);
7310 } else {
7311 /* 1-byte code */
7312 *len = 1;
7313 return((int) *cur);
7314 }
7315encoding_error:
7316 /*
William M. Brack08171912003-12-29 02:52:11 +00007317 * If we detect an UTF8 error that probably means that the
7318 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007319 * declaration header. Report the error and switch the encoding
7320 * to ISO-Latin-1 (if you don't like this policy, just declare the
7321 * encoding !)
7322 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007323 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007324 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007325}
7326
7327/**
Owen Taylor3473f882001-02-23 17:55:21 +00007328 * xmlXPathParseNCName:
7329 * @ctxt: the XPath Parser context
7330 *
7331 * parse an XML namespace non qualified name.
7332 *
7333 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7334 *
7335 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7336 * CombiningChar | Extender
7337 *
7338 * Returns the namespace name or NULL
7339 */
7340
7341xmlChar *
7342xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007343 const xmlChar *in;
7344 xmlChar *ret;
7345 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007346
Daniel Veillard2156a562001-04-28 12:24:34 +00007347 /*
7348 * Accelerator for simple ASCII names
7349 */
7350 in = ctxt->cur;
7351 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7352 ((*in >= 0x41) && (*in <= 0x5A)) ||
7353 (*in == '_')) {
7354 in++;
7355 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7356 ((*in >= 0x41) && (*in <= 0x5A)) ||
7357 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007358 (*in == '_') || (*in == '.') ||
7359 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007360 in++;
7361 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7362 (*in == '[') || (*in == ']') || (*in == ':') ||
7363 (*in == '@') || (*in == '*')) {
7364 count = in - ctxt->cur;
7365 if (count == 0)
7366 return(NULL);
7367 ret = xmlStrndup(ctxt->cur, count);
7368 ctxt->cur = in;
7369 return(ret);
7370 }
7371 }
7372 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007373}
7374
Daniel Veillard2156a562001-04-28 12:24:34 +00007375
Owen Taylor3473f882001-02-23 17:55:21 +00007376/**
7377 * xmlXPathParseQName:
7378 * @ctxt: the XPath Parser context
7379 * @prefix: a xmlChar **
7380 *
7381 * parse an XML qualified name
7382 *
7383 * [NS 5] QName ::= (Prefix ':')? LocalPart
7384 *
7385 * [NS 6] Prefix ::= NCName
7386 *
7387 * [NS 7] LocalPart ::= NCName
7388 *
7389 * Returns the function returns the local part, and prefix is updated
7390 * to get the Prefix if any.
7391 */
7392
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007393static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007394xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7395 xmlChar *ret = NULL;
7396
7397 *prefix = NULL;
7398 ret = xmlXPathParseNCName(ctxt);
7399 if (CUR == ':') {
7400 *prefix = ret;
7401 NEXT;
7402 ret = xmlXPathParseNCName(ctxt);
7403 }
7404 return(ret);
7405}
7406
7407/**
7408 * xmlXPathParseName:
7409 * @ctxt: the XPath Parser context
7410 *
7411 * parse an XML name
7412 *
7413 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7414 * CombiningChar | Extender
7415 *
7416 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7417 *
7418 * Returns the namespace name or NULL
7419 */
7420
7421xmlChar *
7422xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007423 const xmlChar *in;
7424 xmlChar *ret;
7425 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007426
Daniel Veillard61d80a22001-04-27 17:13:01 +00007427 /*
7428 * Accelerator for simple ASCII names
7429 */
7430 in = ctxt->cur;
7431 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7432 ((*in >= 0x41) && (*in <= 0x5A)) ||
7433 (*in == '_') || (*in == ':')) {
7434 in++;
7435 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7436 ((*in >= 0x41) && (*in <= 0x5A)) ||
7437 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007438 (*in == '_') || (*in == '-') ||
7439 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007440 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007441 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007442 count = in - ctxt->cur;
7443 ret = xmlStrndup(ctxt->cur, count);
7444 ctxt->cur = in;
7445 return(ret);
7446 }
7447 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007448 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007449}
7450
Daniel Veillard61d80a22001-04-27 17:13:01 +00007451static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007452xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007453 xmlChar buf[XML_MAX_NAMELEN + 5];
7454 int len = 0, l;
7455 int c;
7456
7457 /*
7458 * Handler for more complex cases
7459 */
7460 c = CUR_CHAR(l);
7461 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007462 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7463 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007464 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007465 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007466 return(NULL);
7467 }
7468
7469 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7470 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7471 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007472 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007473 (IS_COMBINING(c)) ||
7474 (IS_EXTENDER(c)))) {
7475 COPY_BUF(l,buf,len,c);
7476 NEXTL(l);
7477 c = CUR_CHAR(l);
7478 if (len >= XML_MAX_NAMELEN) {
7479 /*
7480 * Okay someone managed to make a huge name, so he's ready to pay
7481 * for the processing speed.
7482 */
7483 xmlChar *buffer;
7484 int max = len * 2;
7485
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007486 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007487 if (buffer == NULL) {
7488 XP_ERROR0(XPATH_MEMORY_ERROR);
7489 }
7490 memcpy(buffer, buf, len);
7491 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7492 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007493 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007494 (IS_COMBINING(c)) ||
7495 (IS_EXTENDER(c))) {
7496 if (len + 10 > max) {
7497 max *= 2;
7498 buffer = (xmlChar *) xmlRealloc(buffer,
7499 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007500 if (buffer == NULL) {
7501 XP_ERROR0(XPATH_MEMORY_ERROR);
7502 }
7503 }
7504 COPY_BUF(l,buffer,len,c);
7505 NEXTL(l);
7506 c = CUR_CHAR(l);
7507 }
7508 buffer[len] = 0;
7509 return(buffer);
7510 }
7511 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007512 if (len == 0)
7513 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007514 return(xmlStrndup(buf, len));
7515}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007516
7517#define MAX_FRAC 20
7518
William M. Brack372a4452004-02-17 13:09:23 +00007519/*
7520 * These are used as divisors for the fractional part of a number.
7521 * Since the table includes 1.0 (representing '0' fractional digits),
7522 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7523 */
7524static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007525 1.0, 10.0, 100.0, 1000.0, 10000.0,
7526 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7527 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7528 100000000000000.0,
7529 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007530 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007531};
7532
Owen Taylor3473f882001-02-23 17:55:21 +00007533/**
7534 * xmlXPathStringEvalNumber:
7535 * @str: A string to scan
7536 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007537 * [30a] Float ::= Number ('e' Digits?)?
7538 *
Owen Taylor3473f882001-02-23 17:55:21 +00007539 * [30] Number ::= Digits ('.' Digits?)?
7540 * | '.' Digits
7541 * [31] Digits ::= [0-9]+
7542 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007543 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007544 * In complement of the Number expression, this function also handles
7545 * negative values : '-' Number.
7546 *
7547 * Returns the double value.
7548 */
7549double
7550xmlXPathStringEvalNumber(const xmlChar *str) {
7551 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007552 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007553 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007554 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007555 int exponent = 0;
7556 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007557#ifdef __GNUC__
7558 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007559 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007560#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007561 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007562 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007563 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7564 return(xmlXPathNAN);
7565 }
7566 if (*cur == '-') {
7567 isneg = 1;
7568 cur++;
7569 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007570
7571#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007572 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007573 * tmp/temp is a workaround against a gcc compiler bug
7574 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007575 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007576 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007577 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007578 ret = ret * 10;
7579 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007580 ok = 1;
7581 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007582 temp = (double) tmp;
7583 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007584 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007585#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007586 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007587 while ((*cur >= '0') && (*cur <= '9')) {
7588 ret = ret * 10 + (*cur - '0');
7589 ok = 1;
7590 cur++;
7591 }
7592#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007593
Owen Taylor3473f882001-02-23 17:55:21 +00007594 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007595 int v, frac = 0;
7596 double fraction = 0;
7597
Owen Taylor3473f882001-02-23 17:55:21 +00007598 cur++;
7599 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7600 return(xmlXPathNAN);
7601 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007602 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7603 v = (*cur - '0');
7604 fraction = fraction * 10 + v;
7605 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007606 cur++;
7607 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007608 fraction /= my_pow10[frac];
7609 ret = ret + fraction;
7610 while ((*cur >= '0') && (*cur <= '9'))
7611 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007612 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007613 if ((*cur == 'e') || (*cur == 'E')) {
7614 cur++;
7615 if (*cur == '-') {
7616 is_exponent_negative = 1;
7617 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007618 } else if (*cur == '+') {
7619 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007620 }
7621 while ((*cur >= '0') && (*cur <= '9')) {
7622 exponent = exponent * 10 + (*cur - '0');
7623 cur++;
7624 }
7625 }
William M. Brack76e95df2003-10-18 16:20:14 +00007626 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007627 if (*cur != 0) return(xmlXPathNAN);
7628 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007629 if (is_exponent_negative) exponent = -exponent;
7630 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007631 return(ret);
7632}
7633
7634/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007635 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007636 * @ctxt: the XPath Parser context
7637 *
7638 * [30] Number ::= Digits ('.' Digits?)?
7639 * | '.' Digits
7640 * [31] Digits ::= [0-9]+
7641 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007642 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007643 *
7644 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007645static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007646xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7647{
Owen Taylor3473f882001-02-23 17:55:21 +00007648 double ret = 0.0;
7649 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007650 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007651 int exponent = 0;
7652 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007653#ifdef __GNUC__
7654 unsigned long tmp = 0;
7655 double temp;
7656#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007657
7658 CHECK_ERROR;
7659 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7660 XP_ERROR(XPATH_NUMBER_ERROR);
7661 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007662#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007663 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007664 * tmp/temp is a workaround against a gcc compiler bug
7665 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007666 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007667 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007668 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007669 ret = ret * 10;
7670 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007671 ok = 1;
7672 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007673 temp = (double) tmp;
7674 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007675 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007676#else
7677 ret = 0;
7678 while ((CUR >= '0') && (CUR <= '9')) {
7679 ret = ret * 10 + (CUR - '0');
7680 ok = 1;
7681 NEXT;
7682 }
7683#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007684 if (CUR == '.') {
7685 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007686 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7687 XP_ERROR(XPATH_NUMBER_ERROR);
7688 }
7689 while ((CUR >= '0') && (CUR <= '9')) {
7690 mult /= 10;
7691 ret = ret + (CUR - '0') * mult;
7692 NEXT;
7693 }
Owen Taylor3473f882001-02-23 17:55:21 +00007694 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007695 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007696 NEXT;
7697 if (CUR == '-') {
7698 is_exponent_negative = 1;
7699 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007700 } else if (CUR == '+') {
7701 NEXT;
7702 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007703 while ((CUR >= '0') && (CUR <= '9')) {
7704 exponent = exponent * 10 + (CUR - '0');
7705 NEXT;
7706 }
7707 if (is_exponent_negative)
7708 exponent = -exponent;
7709 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007710 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007711 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007712 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007713}
7714
7715/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007716 * xmlXPathParseLiteral:
7717 * @ctxt: the XPath Parser context
7718 *
7719 * Parse a Literal
7720 *
7721 * [29] Literal ::= '"' [^"]* '"'
7722 * | "'" [^']* "'"
7723 *
7724 * Returns the value found or NULL in case of error
7725 */
7726static xmlChar *
7727xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7728 const xmlChar *q;
7729 xmlChar *ret = NULL;
7730
7731 if (CUR == '"') {
7732 NEXT;
7733 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007734 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007735 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007736 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007737 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7738 } else {
7739 ret = xmlStrndup(q, CUR_PTR - q);
7740 NEXT;
7741 }
7742 } else if (CUR == '\'') {
7743 NEXT;
7744 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007745 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007746 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007747 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007748 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7749 } else {
7750 ret = xmlStrndup(q, CUR_PTR - q);
7751 NEXT;
7752 }
7753 } else {
7754 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7755 }
7756 return(ret);
7757}
7758
7759/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007760 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007761 * @ctxt: the XPath Parser context
7762 *
7763 * Parse a Literal and push it on the stack.
7764 *
7765 * [29] Literal ::= '"' [^"]* '"'
7766 * | "'" [^']* "'"
7767 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007768 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007769 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007770static void
7771xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007772 const xmlChar *q;
7773 xmlChar *ret = NULL;
7774
7775 if (CUR == '"') {
7776 NEXT;
7777 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007778 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007779 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007780 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007781 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7782 } else {
7783 ret = xmlStrndup(q, CUR_PTR - q);
7784 NEXT;
7785 }
7786 } else if (CUR == '\'') {
7787 NEXT;
7788 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007789 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007790 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007791 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007792 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7793 } else {
7794 ret = xmlStrndup(q, CUR_PTR - q);
7795 NEXT;
7796 }
7797 } else {
7798 XP_ERROR(XPATH_START_LITERAL_ERROR);
7799 }
7800 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007801 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7802 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007803 xmlFree(ret);
7804}
7805
7806/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007807 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007808 * @ctxt: the XPath Parser context
7809 *
7810 * Parse a VariableReference, evaluate it and push it on the stack.
7811 *
7812 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007813 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007814 * of any of the types that are possible for the value of an expression,
7815 * and may also be of additional types not specified here.
7816 *
7817 * Early evaluation is possible since:
7818 * The variable bindings [...] used to evaluate a subexpression are
7819 * always the same as those used to evaluate the containing expression.
7820 *
7821 * [36] VariableReference ::= '$' QName
7822 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007823static void
7824xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007825 xmlChar *name;
7826 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007827
7828 SKIP_BLANKS;
7829 if (CUR != '$') {
7830 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7831 }
7832 NEXT;
7833 name = xmlXPathParseQName(ctxt, &prefix);
7834 if (name == NULL) {
7835 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7836 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007837 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007838 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7839 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007840 SKIP_BLANKS;
7841}
7842
7843/**
7844 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007845 * @name: a name string
7846 *
7847 * Is the name given a NodeType one.
7848 *
7849 * [38] NodeType ::= 'comment'
7850 * | 'text'
7851 * | 'processing-instruction'
7852 * | 'node'
7853 *
7854 * Returns 1 if true 0 otherwise
7855 */
7856int
7857xmlXPathIsNodeType(const xmlChar *name) {
7858 if (name == NULL)
7859 return(0);
7860
Daniel Veillard1971ee22002-01-31 20:29:19 +00007861 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007862 return(1);
7863 if (xmlStrEqual(name, BAD_CAST "text"))
7864 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007865 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007866 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007867 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007868 return(1);
7869 return(0);
7870}
7871
7872/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007873 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007874 * @ctxt: the XPath Parser context
7875 *
7876 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7877 * [17] Argument ::= Expr
7878 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007879 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007880 * pushed on the stack
7881 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007882static void
7883xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007884 xmlChar *name;
7885 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007886 int nbargs = 0;
7887
7888 name = xmlXPathParseQName(ctxt, &prefix);
7889 if (name == NULL) {
7890 XP_ERROR(XPATH_EXPR_ERROR);
7891 }
7892 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007893#ifdef DEBUG_EXPR
7894 if (prefix == NULL)
7895 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7896 name);
7897 else
7898 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7899 prefix, name);
7900#endif
7901
Owen Taylor3473f882001-02-23 17:55:21 +00007902 if (CUR != '(') {
7903 XP_ERROR(XPATH_EXPR_ERROR);
7904 }
7905 NEXT;
7906 SKIP_BLANKS;
7907
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007908 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007909 if (CUR != ')') {
7910 while (CUR != 0) {
7911 int op1 = ctxt->comp->last;
7912 ctxt->comp->last = -1;
7913 xmlXPathCompileExpr(ctxt);
7914 CHECK_ERROR;
7915 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7916 nbargs++;
7917 if (CUR == ')') break;
7918 if (CUR != ',') {
7919 XP_ERROR(XPATH_EXPR_ERROR);
7920 }
7921 NEXT;
7922 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007923 }
Owen Taylor3473f882001-02-23 17:55:21 +00007924 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007925 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7926 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007927 NEXT;
7928 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007929}
7930
7931/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007932 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007933 * @ctxt: the XPath Parser context
7934 *
7935 * [15] PrimaryExpr ::= VariableReference
7936 * | '(' Expr ')'
7937 * | Literal
7938 * | Number
7939 * | FunctionCall
7940 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007941 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007942 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943static void
7944xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007945 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007946 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007947 else if (CUR == '(') {
7948 NEXT;
7949 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007950 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007951 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007952 if (CUR != ')') {
7953 XP_ERROR(XPATH_EXPR_ERROR);
7954 }
7955 NEXT;
7956 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00007957 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007958 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007959 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007960 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007961 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007962 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007963 }
7964 SKIP_BLANKS;
7965}
7966
7967/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007968 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007969 * @ctxt: the XPath Parser context
7970 *
7971 * [20] FilterExpr ::= PrimaryExpr
7972 * | FilterExpr Predicate
7973 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007974 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007975 * Square brackets are used to filter expressions in the same way that
7976 * they are used in location paths. It is an error if the expression to
7977 * be filtered does not evaluate to a node-set. The context node list
7978 * used for evaluating the expression in square brackets is the node-set
7979 * to be filtered listed in document order.
7980 */
7981
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007982static void
7983xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7984 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007985 CHECK_ERROR;
7986 SKIP_BLANKS;
7987
7988 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007989 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007990 SKIP_BLANKS;
7991 }
7992
7993
7994}
7995
7996/**
7997 * xmlXPathScanName:
7998 * @ctxt: the XPath Parser context
7999 *
8000 * Trickery: parse an XML name but without consuming the input flow
8001 * Needed to avoid insanity in the parser state.
8002 *
8003 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8004 * CombiningChar | Extender
8005 *
8006 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8007 *
8008 * [6] Names ::= Name (S Name)*
8009 *
8010 * Returns the Name parsed or NULL
8011 */
8012
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008013static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008014xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8015 xmlChar buf[XML_MAX_NAMELEN];
8016 int len = 0;
8017
8018 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008019 if (!IS_ASCII_LETTER(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00008020 (CUR != ':')) {
8021 return(NULL);
8022 }
8023
William M. Brackd1757ab2004-10-02 22:07:48 +00008024 while ((IS_ASCII_LETTER(NXT(len))) || (IS_ASCII_DIGIT(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008025 (NXT(len) == '.') || (NXT(len) == '-') ||
8026 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008027 (IS_COMBINING_CH(NXT(len))) ||
8028 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008029 buf[len] = NXT(len);
8030 len++;
8031 if (len >= XML_MAX_NAMELEN) {
8032 xmlGenericError(xmlGenericErrorContext,
8033 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brackd1757ab2004-10-02 22:07:48 +00008034 while ((IS_ASCII_LETTER(NXT(len))) || (IS_ASCII_DIGIT(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008035 (NXT(len) == '.') || (NXT(len) == '-') ||
8036 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008037 (IS_COMBINING_CH(NXT(len))) ||
8038 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00008039 len++;
8040 break;
8041 }
8042 }
8043 return(xmlStrndup(buf, len));
8044}
8045
8046/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008047 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008048 * @ctxt: the XPath Parser context
8049 *
8050 * [19] PathExpr ::= LocationPath
8051 * | FilterExpr
8052 * | FilterExpr '/' RelativeLocationPath
8053 * | FilterExpr '//' RelativeLocationPath
8054 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008055 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008056 * The / operator and // operators combine an arbitrary expression
8057 * and a relative location path. It is an error if the expression
8058 * does not evaluate to a node-set.
8059 * The / operator does composition in the same way as when / is
8060 * used in a location path. As in location paths, // is short for
8061 * /descendant-or-self::node()/.
8062 */
8063
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008064static void
8065xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008066 int lc = 1; /* Should we branch to LocationPath ? */
8067 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8068
8069 SKIP_BLANKS;
William M. Brackd1757ab2004-10-02 22:07:48 +00008070 if ((CUR == '$') || (CUR == '(') ||
8071 (IS_ASCII_DIGIT(CUR)) ||
8072 (CUR == '\'') || (CUR == '"') ||
8073 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008074 lc = 0;
8075 } else if (CUR == '*') {
8076 /* relative or absolute location path */
8077 lc = 1;
8078 } else if (CUR == '/') {
8079 /* relative or absolute location path */
8080 lc = 1;
8081 } else if (CUR == '@') {
8082 /* relative abbreviated attribute location path */
8083 lc = 1;
8084 } else if (CUR == '.') {
8085 /* relative abbreviated attribute location path */
8086 lc = 1;
8087 } else {
8088 /*
8089 * Problem is finding if we have a name here whether it's:
8090 * - a nodetype
8091 * - a function call in which case it's followed by '('
8092 * - an axis in which case it's followed by ':'
8093 * - a element name
8094 * We do an a priori analysis here rather than having to
8095 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008096 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008097 * read/write/debug.
8098 */
8099 SKIP_BLANKS;
8100 name = xmlXPathScanName(ctxt);
8101 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8102#ifdef DEBUG_STEP
8103 xmlGenericError(xmlGenericErrorContext,
8104 "PathExpr: Axis\n");
8105#endif
8106 lc = 1;
8107 xmlFree(name);
8108 } else if (name != NULL) {
8109 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008110
8111
8112 while (NXT(len) != 0) {
8113 if (NXT(len) == '/') {
8114 /* element name */
8115#ifdef DEBUG_STEP
8116 xmlGenericError(xmlGenericErrorContext,
8117 "PathExpr: AbbrRelLocation\n");
8118#endif
8119 lc = 1;
8120 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008121 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008122 /* ignore blanks */
8123 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008124 } else if (NXT(len) == ':') {
8125#ifdef DEBUG_STEP
8126 xmlGenericError(xmlGenericErrorContext,
8127 "PathExpr: AbbrRelLocation\n");
8128#endif
8129 lc = 1;
8130 break;
8131 } else if ((NXT(len) == '(')) {
8132 /* Note Type or Function */
8133 if (xmlXPathIsNodeType(name)) {
8134#ifdef DEBUG_STEP
8135 xmlGenericError(xmlGenericErrorContext,
8136 "PathExpr: Type search\n");
8137#endif
8138 lc = 1;
8139 } else {
8140#ifdef DEBUG_STEP
8141 xmlGenericError(xmlGenericErrorContext,
8142 "PathExpr: function call\n");
8143#endif
8144 lc = 0;
8145 }
8146 break;
8147 } else if ((NXT(len) == '[')) {
8148 /* element name */
8149#ifdef DEBUG_STEP
8150 xmlGenericError(xmlGenericErrorContext,
8151 "PathExpr: AbbrRelLocation\n");
8152#endif
8153 lc = 1;
8154 break;
8155 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8156 (NXT(len) == '=')) {
8157 lc = 1;
8158 break;
8159 } else {
8160 lc = 1;
8161 break;
8162 }
8163 len++;
8164 }
8165 if (NXT(len) == 0) {
8166#ifdef DEBUG_STEP
8167 xmlGenericError(xmlGenericErrorContext,
8168 "PathExpr: AbbrRelLocation\n");
8169#endif
8170 /* element name */
8171 lc = 1;
8172 }
8173 xmlFree(name);
8174 } else {
William M. Brack08171912003-12-29 02:52:11 +00008175 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008176 XP_ERROR(XPATH_EXPR_ERROR);
8177 }
8178 }
8179
8180 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008181 if (CUR == '/') {
8182 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8183 } else {
8184 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008185 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008186 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008187 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008188 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008189 CHECK_ERROR;
8190 if ((CUR == '/') && (NXT(1) == '/')) {
8191 SKIP(2);
8192 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008193
8194 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8195 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8196 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8197
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008198 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008199 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008200 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008201 }
8202 }
8203 SKIP_BLANKS;
8204}
8205
8206/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008207 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008208 * @ctxt: the XPath Parser context
8209 *
8210 * [18] UnionExpr ::= PathExpr
8211 * | UnionExpr '|' PathExpr
8212 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008213 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008214 */
8215
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008216static void
8217xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8218 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008219 CHECK_ERROR;
8220 SKIP_BLANKS;
8221 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008222 int op1 = ctxt->comp->last;
8223 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008224
8225 NEXT;
8226 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008227 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008228
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008229 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8230
Owen Taylor3473f882001-02-23 17:55:21 +00008231 SKIP_BLANKS;
8232 }
Owen Taylor3473f882001-02-23 17:55:21 +00008233}
8234
8235/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008236 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008237 * @ctxt: the XPath Parser context
8238 *
8239 * [27] UnaryExpr ::= UnionExpr
8240 * | '-' UnaryExpr
8241 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008242 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008243 */
8244
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008245static void
8246xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008247 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008248 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008249
8250 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008251 while (CUR == '-') {
8252 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008253 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008254 NEXT;
8255 SKIP_BLANKS;
8256 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008257
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008258 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008259 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008260 if (found) {
8261 if (minus)
8262 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8263 else
8264 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008265 }
8266}
8267
8268/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008269 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008270 * @ctxt: the XPath Parser context
8271 *
8272 * [26] MultiplicativeExpr ::= UnaryExpr
8273 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8274 * | MultiplicativeExpr 'div' UnaryExpr
8275 * | MultiplicativeExpr 'mod' UnaryExpr
8276 * [34] MultiplyOperator ::= '*'
8277 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008278 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008279 */
8280
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008281static void
8282xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8283 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008284 CHECK_ERROR;
8285 SKIP_BLANKS;
8286 while ((CUR == '*') ||
8287 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8288 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8289 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008290 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008291
8292 if (CUR == '*') {
8293 op = 0;
8294 NEXT;
8295 } else if (CUR == 'd') {
8296 op = 1;
8297 SKIP(3);
8298 } else if (CUR == 'm') {
8299 op = 2;
8300 SKIP(3);
8301 }
8302 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008303 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008304 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008305 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008306 SKIP_BLANKS;
8307 }
8308}
8309
8310/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008311 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008312 * @ctxt: the XPath Parser context
8313 *
8314 * [25] AdditiveExpr ::= MultiplicativeExpr
8315 * | AdditiveExpr '+' MultiplicativeExpr
8316 * | AdditiveExpr '-' MultiplicativeExpr
8317 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008318 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008319 */
8320
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008321static void
8322xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008323
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008324 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008325 CHECK_ERROR;
8326 SKIP_BLANKS;
8327 while ((CUR == '+') || (CUR == '-')) {
8328 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008329 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008330
8331 if (CUR == '+') plus = 1;
8332 else plus = 0;
8333 NEXT;
8334 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008335 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008336 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008337 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008338 SKIP_BLANKS;
8339 }
8340}
8341
8342/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008343 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008344 * @ctxt: the XPath Parser context
8345 *
8346 * [24] RelationalExpr ::= AdditiveExpr
8347 * | RelationalExpr '<' AdditiveExpr
8348 * | RelationalExpr '>' AdditiveExpr
8349 * | RelationalExpr '<=' AdditiveExpr
8350 * | RelationalExpr '>=' AdditiveExpr
8351 *
8352 * A <= B > C is allowed ? Answer from James, yes with
8353 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8354 * which is basically what got implemented.
8355 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008356 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008357 * on the stack
8358 */
8359
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008360static void
8361xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8362 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008363 CHECK_ERROR;
8364 SKIP_BLANKS;
8365 while ((CUR == '<') ||
8366 (CUR == '>') ||
8367 ((CUR == '<') && (NXT(1) == '=')) ||
8368 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008369 int inf, strict;
8370 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008371
8372 if (CUR == '<') inf = 1;
8373 else inf = 0;
8374 if (NXT(1) == '=') strict = 0;
8375 else strict = 1;
8376 NEXT;
8377 if (!strict) NEXT;
8378 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008379 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008380 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008381 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008382 SKIP_BLANKS;
8383 }
8384}
8385
8386/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008387 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008388 * @ctxt: the XPath Parser context
8389 *
8390 * [23] EqualityExpr ::= RelationalExpr
8391 * | EqualityExpr '=' RelationalExpr
8392 * | EqualityExpr '!=' RelationalExpr
8393 *
8394 * A != B != C is allowed ? Answer from James, yes with
8395 * (RelationalExpr = RelationalExpr) = RelationalExpr
8396 * (RelationalExpr != RelationalExpr) != RelationalExpr
8397 * which is basically what got implemented.
8398 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008399 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008400 *
8401 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008402static void
8403xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8404 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008405 CHECK_ERROR;
8406 SKIP_BLANKS;
8407 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008408 int eq;
8409 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008410
8411 if (CUR == '=') eq = 1;
8412 else eq = 0;
8413 NEXT;
8414 if (!eq) NEXT;
8415 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008416 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008417 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008418 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008419 SKIP_BLANKS;
8420 }
8421}
8422
8423/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008424 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008425 * @ctxt: the XPath Parser context
8426 *
8427 * [22] AndExpr ::= EqualityExpr
8428 * | AndExpr 'and' EqualityExpr
8429 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008430 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008431 *
8432 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008433static void
8434xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8435 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008436 CHECK_ERROR;
8437 SKIP_BLANKS;
8438 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008439 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008440 SKIP(3);
8441 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008442 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008443 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008444 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008445 SKIP_BLANKS;
8446 }
8447}
8448
8449/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008450 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008451 * @ctxt: the XPath Parser context
8452 *
8453 * [14] Expr ::= OrExpr
8454 * [21] OrExpr ::= AndExpr
8455 * | OrExpr 'or' AndExpr
8456 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008457 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008458 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008459static void
8460xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8461 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008462 CHECK_ERROR;
8463 SKIP_BLANKS;
8464 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008465 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008466 SKIP(2);
8467 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008468 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008469 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008470 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8471 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008472 SKIP_BLANKS;
8473 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008474 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8475 /* more ops could be optimized too */
8476 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8477 }
Owen Taylor3473f882001-02-23 17:55:21 +00008478}
8479
8480/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008481 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008482 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008483 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008484 *
8485 * [8] Predicate ::= '[' PredicateExpr ']'
8486 * [9] PredicateExpr ::= Expr
8487 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008488 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008489 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008490static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008491xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008492 int op1 = ctxt->comp->last;
8493
8494 SKIP_BLANKS;
8495 if (CUR != '[') {
8496 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8497 }
8498 NEXT;
8499 SKIP_BLANKS;
8500
8501 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008502 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008503 CHECK_ERROR;
8504
8505 if (CUR != ']') {
8506 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8507 }
8508
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008509 if (filter)
8510 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8511 else
8512 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008513
8514 NEXT;
8515 SKIP_BLANKS;
8516}
8517
8518/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008519 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008520 * @ctxt: the XPath Parser context
8521 * @test: pointer to a xmlXPathTestVal
8522 * @type: pointer to a xmlXPathTypeVal
8523 * @prefix: placeholder for a possible name prefix
8524 *
8525 * [7] NodeTest ::= NameTest
8526 * | NodeType '(' ')'
8527 * | 'processing-instruction' '(' Literal ')'
8528 *
8529 * [37] NameTest ::= '*'
8530 * | NCName ':' '*'
8531 * | QName
8532 * [38] NodeType ::= 'comment'
8533 * | 'text'
8534 * | 'processing-instruction'
8535 * | 'node'
8536 *
William M. Brack08171912003-12-29 02:52:11 +00008537 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008538 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008539static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008540xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8541 xmlXPathTypeVal *type, const xmlChar **prefix,
8542 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008543 int blanks;
8544
8545 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8546 STRANGE;
8547 return(NULL);
8548 }
William M. Brack78637da2003-07-31 14:47:38 +00008549 *type = (xmlXPathTypeVal) 0;
8550 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008551 *prefix = NULL;
8552 SKIP_BLANKS;
8553
8554 if ((name == NULL) && (CUR == '*')) {
8555 /*
8556 * All elements
8557 */
8558 NEXT;
8559 *test = NODE_TEST_ALL;
8560 return(NULL);
8561 }
8562
8563 if (name == NULL)
8564 name = xmlXPathParseNCName(ctxt);
8565 if (name == NULL) {
8566 XP_ERROR0(XPATH_EXPR_ERROR);
8567 }
8568
William M. Brack76e95df2003-10-18 16:20:14 +00008569 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008570 SKIP_BLANKS;
8571 if (CUR == '(') {
8572 NEXT;
8573 /*
8574 * NodeType or PI search
8575 */
8576 if (xmlStrEqual(name, BAD_CAST "comment"))
8577 *type = NODE_TYPE_COMMENT;
8578 else if (xmlStrEqual(name, BAD_CAST "node"))
8579 *type = NODE_TYPE_NODE;
8580 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8581 *type = NODE_TYPE_PI;
8582 else if (xmlStrEqual(name, BAD_CAST "text"))
8583 *type = NODE_TYPE_TEXT;
8584 else {
8585 if (name != NULL)
8586 xmlFree(name);
8587 XP_ERROR0(XPATH_EXPR_ERROR);
8588 }
8589
8590 *test = NODE_TEST_TYPE;
8591
8592 SKIP_BLANKS;
8593 if (*type == NODE_TYPE_PI) {
8594 /*
8595 * Specific case: search a PI by name.
8596 */
Owen Taylor3473f882001-02-23 17:55:21 +00008597 if (name != NULL)
8598 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008599 name = NULL;
8600 if (CUR != ')') {
8601 name = xmlXPathParseLiteral(ctxt);
8602 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008603 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008604 SKIP_BLANKS;
8605 }
Owen Taylor3473f882001-02-23 17:55:21 +00008606 }
8607 if (CUR != ')') {
8608 if (name != NULL)
8609 xmlFree(name);
8610 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8611 }
8612 NEXT;
8613 return(name);
8614 }
8615 *test = NODE_TEST_NAME;
8616 if ((!blanks) && (CUR == ':')) {
8617 NEXT;
8618
8619 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008620 * Since currently the parser context don't have a
8621 * namespace list associated:
8622 * The namespace name for this prefix can be computed
8623 * only at evaluation time. The compilation is done
8624 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008625 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008626#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008627 *prefix = xmlXPathNsLookup(ctxt->context, name);
8628 if (name != NULL)
8629 xmlFree(name);
8630 if (*prefix == NULL) {
8631 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8632 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008633#else
8634 *prefix = name;
8635#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008636
8637 if (CUR == '*') {
8638 /*
8639 * All elements
8640 */
8641 NEXT;
8642 *test = NODE_TEST_ALL;
8643 return(NULL);
8644 }
8645
8646 name = xmlXPathParseNCName(ctxt);
8647 if (name == NULL) {
8648 XP_ERROR0(XPATH_EXPR_ERROR);
8649 }
8650 }
8651 return(name);
8652}
8653
8654/**
8655 * xmlXPathIsAxisName:
8656 * @name: a preparsed name token
8657 *
8658 * [6] AxisName ::= 'ancestor'
8659 * | 'ancestor-or-self'
8660 * | 'attribute'
8661 * | 'child'
8662 * | 'descendant'
8663 * | 'descendant-or-self'
8664 * | 'following'
8665 * | 'following-sibling'
8666 * | 'namespace'
8667 * | 'parent'
8668 * | 'preceding'
8669 * | 'preceding-sibling'
8670 * | 'self'
8671 *
8672 * Returns the axis or 0
8673 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008674static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008675xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008676 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008677 switch (name[0]) {
8678 case 'a':
8679 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8680 ret = AXIS_ANCESTOR;
8681 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8682 ret = AXIS_ANCESTOR_OR_SELF;
8683 if (xmlStrEqual(name, BAD_CAST "attribute"))
8684 ret = AXIS_ATTRIBUTE;
8685 break;
8686 case 'c':
8687 if (xmlStrEqual(name, BAD_CAST "child"))
8688 ret = AXIS_CHILD;
8689 break;
8690 case 'd':
8691 if (xmlStrEqual(name, BAD_CAST "descendant"))
8692 ret = AXIS_DESCENDANT;
8693 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8694 ret = AXIS_DESCENDANT_OR_SELF;
8695 break;
8696 case 'f':
8697 if (xmlStrEqual(name, BAD_CAST "following"))
8698 ret = AXIS_FOLLOWING;
8699 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8700 ret = AXIS_FOLLOWING_SIBLING;
8701 break;
8702 case 'n':
8703 if (xmlStrEqual(name, BAD_CAST "namespace"))
8704 ret = AXIS_NAMESPACE;
8705 break;
8706 case 'p':
8707 if (xmlStrEqual(name, BAD_CAST "parent"))
8708 ret = AXIS_PARENT;
8709 if (xmlStrEqual(name, BAD_CAST "preceding"))
8710 ret = AXIS_PRECEDING;
8711 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8712 ret = AXIS_PRECEDING_SIBLING;
8713 break;
8714 case 's':
8715 if (xmlStrEqual(name, BAD_CAST "self"))
8716 ret = AXIS_SELF;
8717 break;
8718 }
8719 return(ret);
8720}
8721
8722/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008723 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008724 * @ctxt: the XPath Parser context
8725 *
8726 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8727 * | AbbreviatedStep
8728 *
8729 * [12] AbbreviatedStep ::= '.' | '..'
8730 *
8731 * [5] AxisSpecifier ::= AxisName '::'
8732 * | AbbreviatedAxisSpecifier
8733 *
8734 * [13] AbbreviatedAxisSpecifier ::= '@'?
8735 *
8736 * Modified for XPtr range support as:
8737 *
8738 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8739 * | AbbreviatedStep
8740 * | 'range-to' '(' Expr ')' Predicate*
8741 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008742 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008743 * A location step of . is short for self::node(). This is
8744 * particularly useful in conjunction with //. For example, the
8745 * location path .//para is short for
8746 * self::node()/descendant-or-self::node()/child::para
8747 * and so will select all para descendant elements of the context
8748 * node.
8749 * Similarly, a location step of .. is short for parent::node().
8750 * For example, ../title is short for parent::node()/child::title
8751 * and so will select the title children of the parent of the context
8752 * node.
8753 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008754static void
8755xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008756#ifdef LIBXML_XPTR_ENABLED
8757 int rangeto = 0;
8758 int op2 = -1;
8759#endif
8760
Owen Taylor3473f882001-02-23 17:55:21 +00008761 SKIP_BLANKS;
8762 if ((CUR == '.') && (NXT(1) == '.')) {
8763 SKIP(2);
8764 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008765 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8766 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008767 } else if (CUR == '.') {
8768 NEXT;
8769 SKIP_BLANKS;
8770 } else {
8771 xmlChar *name = NULL;
8772 const xmlChar *prefix = NULL;
8773 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008774 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008775 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008776 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008777
8778 /*
8779 * The modification needed for XPointer change to the production
8780 */
8781#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008782 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008783 name = xmlXPathParseNCName(ctxt);
8784 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008785 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008786 xmlFree(name);
8787 SKIP_BLANKS;
8788 if (CUR != '(') {
8789 XP_ERROR(XPATH_EXPR_ERROR);
8790 }
8791 NEXT;
8792 SKIP_BLANKS;
8793
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008794 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008795 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008796 CHECK_ERROR;
8797
8798 SKIP_BLANKS;
8799 if (CUR != ')') {
8800 XP_ERROR(XPATH_EXPR_ERROR);
8801 }
8802 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008803 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008804 goto eval_predicates;
8805 }
8806 }
8807#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008808 if (CUR == '*') {
8809 axis = AXIS_CHILD;
8810 } else {
8811 if (name == NULL)
8812 name = xmlXPathParseNCName(ctxt);
8813 if (name != NULL) {
8814 axis = xmlXPathIsAxisName(name);
8815 if (axis != 0) {
8816 SKIP_BLANKS;
8817 if ((CUR == ':') && (NXT(1) == ':')) {
8818 SKIP(2);
8819 xmlFree(name);
8820 name = NULL;
8821 } else {
8822 /* an element name can conflict with an axis one :-\ */
8823 axis = AXIS_CHILD;
8824 }
Owen Taylor3473f882001-02-23 17:55:21 +00008825 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008826 axis = AXIS_CHILD;
8827 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008828 } else if (CUR == '@') {
8829 NEXT;
8830 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008831 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008832 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008833 }
Owen Taylor3473f882001-02-23 17:55:21 +00008834 }
8835
8836 CHECK_ERROR;
8837
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008838 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008839 if (test == 0)
8840 return;
8841
8842#ifdef DEBUG_STEP
8843 xmlGenericError(xmlGenericErrorContext,
8844 "Basis : computing new set\n");
8845#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008846
Owen Taylor3473f882001-02-23 17:55:21 +00008847#ifdef DEBUG_STEP
8848 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008849 if (ctxt->value == NULL)
8850 xmlGenericError(xmlGenericErrorContext, "no value\n");
8851 else if (ctxt->value->nodesetval == NULL)
8852 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8853 else
8854 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008855#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008856
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008857#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008858eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008859#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008860 op1 = ctxt->comp->last;
8861 ctxt->comp->last = -1;
8862
Owen Taylor3473f882001-02-23 17:55:21 +00008863 SKIP_BLANKS;
8864 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008865 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008866 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008867
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008868#ifdef LIBXML_XPTR_ENABLED
8869 if (rangeto) {
8870 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8871 } else
8872#endif
8873 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8874 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008875
Owen Taylor3473f882001-02-23 17:55:21 +00008876 }
8877#ifdef DEBUG_STEP
8878 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008879 if (ctxt->value == NULL)
8880 xmlGenericError(xmlGenericErrorContext, "no value\n");
8881 else if (ctxt->value->nodesetval == NULL)
8882 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8883 else
8884 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8885 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008886#endif
8887}
8888
8889/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008890 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008891 * @ctxt: the XPath Parser context
8892 *
8893 * [3] RelativeLocationPath ::= Step
8894 * | RelativeLocationPath '/' Step
8895 * | AbbreviatedRelativeLocationPath
8896 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8897 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008898 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008899 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008900static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008901xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008902(xmlXPathParserContextPtr ctxt) {
8903 SKIP_BLANKS;
8904 if ((CUR == '/') && (NXT(1) == '/')) {
8905 SKIP(2);
8906 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008907 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8908 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008909 } else if (CUR == '/') {
8910 NEXT;
8911 SKIP_BLANKS;
8912 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008913 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008914 SKIP_BLANKS;
8915 while (CUR == '/') {
8916 if ((CUR == '/') && (NXT(1) == '/')) {
8917 SKIP(2);
8918 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008919 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008920 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008921 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008922 } else if (CUR == '/') {
8923 NEXT;
8924 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008925 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008926 }
8927 SKIP_BLANKS;
8928 }
8929}
8930
8931/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008932 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008933 * @ctxt: the XPath Parser context
8934 *
8935 * [1] LocationPath ::= RelativeLocationPath
8936 * | AbsoluteLocationPath
8937 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8938 * | AbbreviatedAbsoluteLocationPath
8939 * [10] AbbreviatedAbsoluteLocationPath ::=
8940 * '//' RelativeLocationPath
8941 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008942 * Compile a location path
8943 *
Owen Taylor3473f882001-02-23 17:55:21 +00008944 * // is short for /descendant-or-self::node()/. For example,
8945 * //para is short for /descendant-or-self::node()/child::para and
8946 * so will select any para element in the document (even a para element
8947 * that is a document element will be selected by //para since the
8948 * document element node is a child of the root node); div//para is
8949 * short for div/descendant-or-self::node()/child::para and so will
8950 * select all para descendants of div children.
8951 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008952static void
8953xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008954 SKIP_BLANKS;
8955 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008956 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008957 } else {
8958 while (CUR == '/') {
8959 if ((CUR == '/') && (NXT(1) == '/')) {
8960 SKIP(2);
8961 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008962 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8963 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008964 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008965 } else if (CUR == '/') {
8966 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008967 SKIP_BLANKS;
8968 if ((CUR != 0 ) &&
William M. Brackd1757ab2004-10-02 22:07:48 +00008969 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008970 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008971 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008972 }
8973 }
8974 }
8975}
8976
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008977/************************************************************************
8978 * *
8979 * XPath precompiled expression evaluation *
8980 * *
8981 ************************************************************************/
8982
Daniel Veillardf06307e2001-07-03 10:35:50 +00008983static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008984xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8985
8986/**
8987 * xmlXPathNodeCollectAndTest:
8988 * @ctxt: the XPath Parser context
8989 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008990 * @first: pointer to the first element in document order
8991 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008992 *
8993 * This is the function implementing a step: based on the current list
8994 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008995 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008996 *
8997 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008998 *
William M. Brack08171912003-12-29 02:52:11 +00008999 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009000 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00009001static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009002xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009003 xmlXPathStepOpPtr op,
9004 xmlNodePtr * first, xmlNodePtr * last)
9005{
William M. Brack78637da2003-07-31 14:47:38 +00009006 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9007 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9008 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009009 const xmlChar *prefix = op->value4;
9010 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009011 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012
9013#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009014 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009015#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009016 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009017 xmlNodeSetPtr ret, list;
9018 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009019 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009020 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009021 xmlNodePtr cur = NULL;
9022 xmlXPathObjectPtr obj;
9023 xmlNodeSetPtr nodelist;
9024 xmlNodePtr tmp;
9025
Daniel Veillardf06307e2001-07-03 10:35:50 +00009026 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009027 obj = valuePop(ctxt);
9028 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009029 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009030 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009031 URI = xmlXPathNsLookup(ctxt->context, prefix);
9032 if (URI == NULL)
9033 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009034 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009035#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009036 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009037#endif
9038 switch (axis) {
9039 case AXIS_ANCESTOR:
9040#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009041 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009042#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009043 first = NULL;
9044 next = xmlXPathNextAncestor;
9045 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009046 case AXIS_ANCESTOR_OR_SELF:
9047#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009048 xmlGenericError(xmlGenericErrorContext,
9049 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009050#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009051 first = NULL;
9052 next = xmlXPathNextAncestorOrSelf;
9053 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 case AXIS_ATTRIBUTE:
9055#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009057#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 first = NULL;
9059 last = NULL;
9060 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009061 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009062 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009063 case AXIS_CHILD:
9064#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009065 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009066#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009067 last = NULL;
9068 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009069 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009070 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009071 case AXIS_DESCENDANT:
9072#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009073 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009074#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009075 last = NULL;
9076 next = xmlXPathNextDescendant;
9077 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009078 case AXIS_DESCENDANT_OR_SELF:
9079#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009080 xmlGenericError(xmlGenericErrorContext,
9081 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009082#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009083 last = NULL;
9084 next = xmlXPathNextDescendantOrSelf;
9085 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009086 case AXIS_FOLLOWING:
9087#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009088 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009089#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009090 last = NULL;
9091 next = xmlXPathNextFollowing;
9092 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009093 case AXIS_FOLLOWING_SIBLING:
9094#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009095 xmlGenericError(xmlGenericErrorContext,
9096 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009097#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009098 last = NULL;
9099 next = xmlXPathNextFollowingSibling;
9100 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009101 case AXIS_NAMESPACE:
9102#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 first = NULL;
9106 last = NULL;
9107 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009108 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009109 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009110 case AXIS_PARENT:
9111#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009113#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009114 first = NULL;
9115 next = xmlXPathNextParent;
9116 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009117 case AXIS_PRECEDING:
9118#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009119 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009120#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009121 first = NULL;
9122 next = xmlXPathNextPrecedingInternal;
9123 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009124 case AXIS_PRECEDING_SIBLING:
9125#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009126 xmlGenericError(xmlGenericErrorContext,
9127 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009128#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009129 first = NULL;
9130 next = xmlXPathNextPrecedingSibling;
9131 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132 case AXIS_SELF:
9133#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009136 first = NULL;
9137 last = NULL;
9138 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009139 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009140 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141 }
9142 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009143 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009144
9145 nodelist = obj->nodesetval;
9146 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009147 xmlXPathFreeObject(obj);
9148 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9149 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009150 }
9151 addNode = xmlXPathNodeSetAddUnique;
9152 ret = NULL;
9153#ifdef DEBUG_STEP
9154 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009155 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009156 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009157 case NODE_TEST_NONE:
9158 xmlGenericError(xmlGenericErrorContext,
9159 " searching for none !!!\n");
9160 break;
9161 case NODE_TEST_TYPE:
9162 xmlGenericError(xmlGenericErrorContext,
9163 " searching for type %d\n", type);
9164 break;
9165 case NODE_TEST_PI:
9166 xmlGenericError(xmlGenericErrorContext,
9167 " searching for PI !!!\n");
9168 break;
9169 case NODE_TEST_ALL:
9170 xmlGenericError(xmlGenericErrorContext,
9171 " searching for *\n");
9172 break;
9173 case NODE_TEST_NS:
9174 xmlGenericError(xmlGenericErrorContext,
9175 " searching for namespace %s\n",
9176 prefix);
9177 break;
9178 case NODE_TEST_NAME:
9179 xmlGenericError(xmlGenericErrorContext,
9180 " searching for name %s\n", name);
9181 if (prefix != NULL)
9182 xmlGenericError(xmlGenericErrorContext,
9183 " with namespace %s\n", prefix);
9184 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009185 }
9186 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9187#endif
9188 /*
9189 * 2.3 Node Tests
9190 * - For the attribute axis, the principal node type is attribute.
9191 * - For the namespace axis, the principal node type is namespace.
9192 * - For other axes, the principal node type is element.
9193 *
9194 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009195 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009196 * select all element children of the context node
9197 */
9198 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009199 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009200 ctxt->context->node = nodelist->nodeTab[i];
9201
Daniel Veillardf06307e2001-07-03 10:35:50 +00009202 cur = NULL;
9203 list = xmlXPathNodeSetCreate(NULL);
9204 do {
9205 cur = next(ctxt, cur);
9206 if (cur == NULL)
9207 break;
9208 if ((first != NULL) && (*first == cur))
9209 break;
9210 if (((t % 256) == 0) &&
9211 (first != NULL) && (*first != NULL) &&
9212 (xmlXPathCmpNodes(*first, cur) >= 0))
9213 break;
9214 if ((last != NULL) && (*last == cur))
9215 break;
9216 if (((t % 256) == 0) &&
9217 (last != NULL) && (*last != NULL) &&
9218 (xmlXPathCmpNodes(cur, *last) >= 0))
9219 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009220 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009221#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009222 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9223#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009224 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009225 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009226 ctxt->context->node = tmp;
9227 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009228 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009229 if ((cur->type == type) ||
9230 ((type == NODE_TYPE_NODE) &&
9231 ((cur->type == XML_DOCUMENT_NODE) ||
9232 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9233 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009234 (cur->type == XML_NAMESPACE_DECL) ||
9235 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 (cur->type == XML_PI_NODE) ||
9237 (cur->type == XML_COMMENT_NODE) ||
9238 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009239 (cur->type == XML_TEXT_NODE))) ||
9240 ((type == NODE_TYPE_TEXT) &&
9241 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009242#ifdef DEBUG_STEP
9243 n++;
9244#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009245 addNode(list, cur);
9246 }
9247 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009248 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009249 if (cur->type == XML_PI_NODE) {
9250 if ((name != NULL) &&
9251 (!xmlStrEqual(name, cur->name)))
9252 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009253#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009254 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009255#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009256 addNode(list, cur);
9257 }
9258 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009259 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009260 if (axis == AXIS_ATTRIBUTE) {
9261 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009262#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009263 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009264#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 addNode(list, cur);
9266 }
9267 } else if (axis == AXIS_NAMESPACE) {
9268 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009269#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009270 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009271#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009272 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9273 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009274 }
9275 } else {
9276 if (cur->type == XML_ELEMENT_NODE) {
9277 if (prefix == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009278#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009279 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009280#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009281 addNode(list, cur);
9282 } else if ((cur->ns != NULL) &&
9283 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009284#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009285 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009286#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009287 addNode(list, cur);
9288 }
9289 }
9290 }
9291 break;
9292 case NODE_TEST_NS:{
9293 TODO;
9294 break;
9295 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009296 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009297 switch (cur->type) {
9298 case XML_ELEMENT_NODE:
9299 if (xmlStrEqual(name, cur->name)) {
9300 if (prefix == NULL) {
9301 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009302#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009303 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009304#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009305 addNode(list, cur);
9306 }
9307 } else {
9308 if ((cur->ns != NULL) &&
9309 (xmlStrEqual(URI,
9310 cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009311#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009312 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009313#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009314 addNode(list, cur);
9315 }
9316 }
9317 }
9318 break;
9319 case XML_ATTRIBUTE_NODE:{
9320 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009321
Daniel Veillardf06307e2001-07-03 10:35:50 +00009322 if (xmlStrEqual(name, attr->name)) {
9323 if (prefix == NULL) {
9324 if ((attr->ns == NULL) ||
9325 (attr->ns->prefix == NULL)) {
9326#ifdef DEBUG_STEP
9327 n++;
9328#endif
9329 addNode(list,
9330 (xmlNodePtr) attr);
9331 }
9332 } else {
9333 if ((attr->ns != NULL) &&
9334 (xmlStrEqual(URI,
9335 attr->ns->
9336 href))) {
9337#ifdef DEBUG_STEP
9338 n++;
9339#endif
9340 addNode(list,
9341 (xmlNodePtr) attr);
9342 }
9343 }
9344 }
9345 break;
9346 }
9347 case XML_NAMESPACE_DECL:
9348 if (cur->type == XML_NAMESPACE_DECL) {
9349 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009350
Daniel Veillardf06307e2001-07-03 10:35:50 +00009351 if ((ns->prefix != NULL) && (name != NULL)
9352 && (xmlStrEqual(ns->prefix, name))) {
9353#ifdef DEBUG_STEP
9354 n++;
9355#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009356 xmlXPathNodeSetAddNs(list,
9357 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009358 }
9359 }
9360 break;
9361 default:
9362 break;
9363 }
9364 break;
9365 break;
9366 }
9367 } while (cur != NULL);
9368
9369 /*
9370 * If there is some predicate filtering do it now
9371 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009372 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009373 xmlXPathObjectPtr obj2;
9374
9375 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9376 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9377 CHECK_TYPE0(XPATH_NODESET);
9378 obj2 = valuePop(ctxt);
9379 list = obj2->nodesetval;
9380 obj2->nodesetval = NULL;
9381 xmlXPathFreeObject(obj2);
9382 }
9383 if (ret == NULL) {
9384 ret = list;
9385 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009386 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009387 xmlXPathFreeNodeSet(list);
9388 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009389 }
9390 ctxt->context->node = tmp;
9391#ifdef DEBUG_STEP
9392 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009393 "\nExamined %d nodes, found %d nodes at that step\n",
9394 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009395#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009396 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009397 if ((obj->boolval) && (obj->user != NULL)) {
9398 ctxt->value->boolval = 1;
9399 ctxt->value->user = obj->user;
9400 obj->user = NULL;
9401 obj->boolval = 0;
9402 }
9403 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009404 return(t);
9405}
9406
9407/**
9408 * xmlXPathNodeCollectAndTestNth:
9409 * @ctxt: the XPath Parser context
9410 * @op: the XPath precompiled step operation
9411 * @indx: the index to collect
9412 * @first: pointer to the first element in document order
9413 * @last: pointer to the last element in document order
9414 *
9415 * This is the function implementing a step: based on the current list
9416 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009417 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009418 *
9419 * Pushes the new NodeSet resulting from the search.
9420 * Returns the number of node traversed
9421 */
9422static int
9423xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9424 xmlXPathStepOpPtr op, int indx,
9425 xmlNodePtr * first, xmlNodePtr * last)
9426{
William M. Brack78637da2003-07-31 14:47:38 +00009427 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9428 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9429 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009430 const xmlChar *prefix = op->value4;
9431 const xmlChar *name = op->value5;
9432 const xmlChar *URI = NULL;
9433 int n = 0, t = 0;
9434
9435 int i;
9436 xmlNodeSetPtr list;
9437 xmlXPathTraversalFunction next = NULL;
9438 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9439 xmlNodePtr cur = NULL;
9440 xmlXPathObjectPtr obj;
9441 xmlNodeSetPtr nodelist;
9442 xmlNodePtr tmp;
9443
9444 CHECK_TYPE0(XPATH_NODESET);
9445 obj = valuePop(ctxt);
9446 addNode = xmlXPathNodeSetAdd;
9447 if (prefix != NULL) {
9448 URI = xmlXPathNsLookup(ctxt->context, prefix);
9449 if (URI == NULL)
9450 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9451 }
9452#ifdef DEBUG_STEP_NTH
9453 xmlGenericError(xmlGenericErrorContext, "new step : ");
9454 if (first != NULL) {
9455 if (*first != NULL)
9456 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9457 (*first)->name);
9458 else
9459 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9460 }
9461 if (last != NULL) {
9462 if (*last != NULL)
9463 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9464 (*last)->name);
9465 else
9466 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9467 }
9468#endif
9469 switch (axis) {
9470 case AXIS_ANCESTOR:
9471#ifdef DEBUG_STEP_NTH
9472 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9473#endif
9474 first = NULL;
9475 next = xmlXPathNextAncestor;
9476 break;
9477 case AXIS_ANCESTOR_OR_SELF:
9478#ifdef DEBUG_STEP_NTH
9479 xmlGenericError(xmlGenericErrorContext,
9480 "axis 'ancestors-or-self' ");
9481#endif
9482 first = NULL;
9483 next = xmlXPathNextAncestorOrSelf;
9484 break;
9485 case AXIS_ATTRIBUTE:
9486#ifdef DEBUG_STEP_NTH
9487 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9488#endif
9489 first = NULL;
9490 last = NULL;
9491 next = xmlXPathNextAttribute;
9492 break;
9493 case AXIS_CHILD:
9494#ifdef DEBUG_STEP_NTH
9495 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9496#endif
9497 last = NULL;
9498 next = xmlXPathNextChild;
9499 break;
9500 case AXIS_DESCENDANT:
9501#ifdef DEBUG_STEP_NTH
9502 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9503#endif
9504 last = NULL;
9505 next = xmlXPathNextDescendant;
9506 break;
9507 case AXIS_DESCENDANT_OR_SELF:
9508#ifdef DEBUG_STEP_NTH
9509 xmlGenericError(xmlGenericErrorContext,
9510 "axis 'descendant-or-self' ");
9511#endif
9512 last = NULL;
9513 next = xmlXPathNextDescendantOrSelf;
9514 break;
9515 case AXIS_FOLLOWING:
9516#ifdef DEBUG_STEP_NTH
9517 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9518#endif
9519 last = NULL;
9520 next = xmlXPathNextFollowing;
9521 break;
9522 case AXIS_FOLLOWING_SIBLING:
9523#ifdef DEBUG_STEP_NTH
9524 xmlGenericError(xmlGenericErrorContext,
9525 "axis 'following-siblings' ");
9526#endif
9527 last = NULL;
9528 next = xmlXPathNextFollowingSibling;
9529 break;
9530 case AXIS_NAMESPACE:
9531#ifdef DEBUG_STEP_NTH
9532 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9533#endif
9534 last = NULL;
9535 first = NULL;
9536 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9537 break;
9538 case AXIS_PARENT:
9539#ifdef DEBUG_STEP_NTH
9540 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9541#endif
9542 first = NULL;
9543 next = xmlXPathNextParent;
9544 break;
9545 case AXIS_PRECEDING:
9546#ifdef DEBUG_STEP_NTH
9547 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9548#endif
9549 first = NULL;
9550 next = xmlXPathNextPrecedingInternal;
9551 break;
9552 case AXIS_PRECEDING_SIBLING:
9553#ifdef DEBUG_STEP_NTH
9554 xmlGenericError(xmlGenericErrorContext,
9555 "axis 'preceding-sibling' ");
9556#endif
9557 first = NULL;
9558 next = xmlXPathNextPrecedingSibling;
9559 break;
9560 case AXIS_SELF:
9561#ifdef DEBUG_STEP_NTH
9562 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9563#endif
9564 first = NULL;
9565 last = NULL;
9566 next = xmlXPathNextSelf;
9567 break;
9568 }
9569 if (next == NULL)
9570 return(0);
9571
9572 nodelist = obj->nodesetval;
9573 if (nodelist == NULL) {
9574 xmlXPathFreeObject(obj);
9575 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9576 return(0);
9577 }
9578 addNode = xmlXPathNodeSetAddUnique;
9579#ifdef DEBUG_STEP_NTH
9580 xmlGenericError(xmlGenericErrorContext,
9581 " context contains %d nodes\n", nodelist->nodeNr);
9582 switch (test) {
9583 case NODE_TEST_NONE:
9584 xmlGenericError(xmlGenericErrorContext,
9585 " searching for none !!!\n");
9586 break;
9587 case NODE_TEST_TYPE:
9588 xmlGenericError(xmlGenericErrorContext,
9589 " searching for type %d\n", type);
9590 break;
9591 case NODE_TEST_PI:
9592 xmlGenericError(xmlGenericErrorContext,
9593 " searching for PI !!!\n");
9594 break;
9595 case NODE_TEST_ALL:
9596 xmlGenericError(xmlGenericErrorContext,
9597 " searching for *\n");
9598 break;
9599 case NODE_TEST_NS:
9600 xmlGenericError(xmlGenericErrorContext,
9601 " searching for namespace %s\n",
9602 prefix);
9603 break;
9604 case NODE_TEST_NAME:
9605 xmlGenericError(xmlGenericErrorContext,
9606 " searching for name %s\n", name);
9607 if (prefix != NULL)
9608 xmlGenericError(xmlGenericErrorContext,
9609 " with namespace %s\n", prefix);
9610 break;
9611 }
9612 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9613#endif
9614 /*
9615 * 2.3 Node Tests
9616 * - For the attribute axis, the principal node type is attribute.
9617 * - For the namespace axis, the principal node type is namespace.
9618 * - For other axes, the principal node type is element.
9619 *
9620 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009621 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009622 * select all element children of the context node
9623 */
9624 tmp = ctxt->context->node;
9625 list = xmlXPathNodeSetCreate(NULL);
9626 for (i = 0; i < nodelist->nodeNr; i++) {
9627 ctxt->context->node = nodelist->nodeTab[i];
9628
9629 cur = NULL;
9630 n = 0;
9631 do {
9632 cur = next(ctxt, cur);
9633 if (cur == NULL)
9634 break;
9635 if ((first != NULL) && (*first == cur))
9636 break;
9637 if (((t % 256) == 0) &&
9638 (first != NULL) && (*first != NULL) &&
9639 (xmlXPathCmpNodes(*first, cur) >= 0))
9640 break;
9641 if ((last != NULL) && (*last == cur))
9642 break;
9643 if (((t % 256) == 0) &&
9644 (last != NULL) && (*last != NULL) &&
9645 (xmlXPathCmpNodes(cur, *last) >= 0))
9646 break;
9647 t++;
9648 switch (test) {
9649 case NODE_TEST_NONE:
9650 ctxt->context->node = tmp;
9651 STRANGE return(0);
9652 case NODE_TEST_TYPE:
9653 if ((cur->type == type) ||
9654 ((type == NODE_TYPE_NODE) &&
9655 ((cur->type == XML_DOCUMENT_NODE) ||
9656 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9657 (cur->type == XML_ELEMENT_NODE) ||
9658 (cur->type == XML_PI_NODE) ||
9659 (cur->type == XML_COMMENT_NODE) ||
9660 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009661 (cur->type == XML_TEXT_NODE))) ||
9662 ((type == NODE_TYPE_TEXT) &&
9663 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009664 n++;
9665 if (n == indx)
9666 addNode(list, cur);
9667 }
9668 break;
9669 case NODE_TEST_PI:
9670 if (cur->type == XML_PI_NODE) {
9671 if ((name != NULL) &&
9672 (!xmlStrEqual(name, cur->name)))
9673 break;
9674 n++;
9675 if (n == indx)
9676 addNode(list, cur);
9677 }
9678 break;
9679 case NODE_TEST_ALL:
9680 if (axis == AXIS_ATTRIBUTE) {
9681 if (cur->type == XML_ATTRIBUTE_NODE) {
9682 n++;
9683 if (n == indx)
9684 addNode(list, cur);
9685 }
9686 } else if (axis == AXIS_NAMESPACE) {
9687 if (cur->type == XML_NAMESPACE_DECL) {
9688 n++;
9689 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009690 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9691 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009692 }
9693 } else {
9694 if (cur->type == XML_ELEMENT_NODE) {
9695 if (prefix == NULL) {
9696 n++;
9697 if (n == indx)
9698 addNode(list, cur);
9699 } else if ((cur->ns != NULL) &&
9700 (xmlStrEqual(URI, cur->ns->href))) {
9701 n++;
9702 if (n == indx)
9703 addNode(list, cur);
9704 }
9705 }
9706 }
9707 break;
9708 case NODE_TEST_NS:{
9709 TODO;
9710 break;
9711 }
9712 case NODE_TEST_NAME:
9713 switch (cur->type) {
9714 case XML_ELEMENT_NODE:
9715 if (xmlStrEqual(name, cur->name)) {
9716 if (prefix == NULL) {
9717 if (cur->ns == NULL) {
9718 n++;
9719 if (n == indx)
9720 addNode(list, cur);
9721 }
9722 } else {
9723 if ((cur->ns != NULL) &&
9724 (xmlStrEqual(URI,
9725 cur->ns->href))) {
9726 n++;
9727 if (n == indx)
9728 addNode(list, cur);
9729 }
9730 }
9731 }
9732 break;
9733 case XML_ATTRIBUTE_NODE:{
9734 xmlAttrPtr attr = (xmlAttrPtr) cur;
9735
9736 if (xmlStrEqual(name, attr->name)) {
9737 if (prefix == NULL) {
9738 if ((attr->ns == NULL) ||
9739 (attr->ns->prefix == NULL)) {
9740 n++;
9741 if (n == indx)
9742 addNode(list, cur);
9743 }
9744 } else {
9745 if ((attr->ns != NULL) &&
9746 (xmlStrEqual(URI,
9747 attr->ns->
9748 href))) {
9749 n++;
9750 if (n == indx)
9751 addNode(list, cur);
9752 }
9753 }
9754 }
9755 break;
9756 }
9757 case XML_NAMESPACE_DECL:
9758 if (cur->type == XML_NAMESPACE_DECL) {
9759 xmlNsPtr ns = (xmlNsPtr) cur;
9760
9761 if ((ns->prefix != NULL) && (name != NULL)
9762 && (xmlStrEqual(ns->prefix, name))) {
9763 n++;
9764 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009765 xmlXPathNodeSetAddNs(list,
9766 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009767 }
9768 }
9769 break;
9770 default:
9771 break;
9772 }
9773 break;
9774 break;
9775 }
9776 } while (n < indx);
9777 }
9778 ctxt->context->node = tmp;
9779#ifdef DEBUG_STEP_NTH
9780 xmlGenericError(xmlGenericErrorContext,
9781 "\nExamined %d nodes, found %d nodes at that step\n",
9782 t, list->nodeNr);
9783#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009784 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009785 if ((obj->boolval) && (obj->user != NULL)) {
9786 ctxt->value->boolval = 1;
9787 ctxt->value->user = obj->user;
9788 obj->user = NULL;
9789 obj->boolval = 0;
9790 }
9791 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009792 return(t);
9793}
9794
9795/**
9796 * xmlXPathCompOpEvalFirst:
9797 * @ctxt: the XPath parser context with the compiled expression
9798 * @op: an XPath compiled operation
9799 * @first: the first elem found so far
9800 *
9801 * Evaluate the Precompiled XPath operation searching only the first
9802 * element in document order
9803 *
9804 * Returns the number of examined objects.
9805 */
9806static int
9807xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9808 xmlXPathStepOpPtr op, xmlNodePtr * first)
9809{
9810 int total = 0, cur;
9811 xmlXPathCompExprPtr comp;
9812 xmlXPathObjectPtr arg1, arg2;
9813
Daniel Veillard556c6682001-10-06 09:59:51 +00009814 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009815 comp = ctxt->comp;
9816 switch (op->op) {
9817 case XPATH_OP_END:
9818 return (0);
9819 case XPATH_OP_UNION:
9820 total =
9821 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9822 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009823 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009824 if ((ctxt->value != NULL)
9825 && (ctxt->value->type == XPATH_NODESET)
9826 && (ctxt->value->nodesetval != NULL)
9827 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9828 /*
9829 * limit tree traversing to first node in the result
9830 */
9831 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9832 *first = ctxt->value->nodesetval->nodeTab[0];
9833 }
9834 cur =
9835 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9836 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009837 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009838 CHECK_TYPE0(XPATH_NODESET);
9839 arg2 = valuePop(ctxt);
9840
9841 CHECK_TYPE0(XPATH_NODESET);
9842 arg1 = valuePop(ctxt);
9843
9844 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9845 arg2->nodesetval);
9846 valuePush(ctxt, arg1);
9847 xmlXPathFreeObject(arg2);
9848 /* optimizer */
9849 if (total > cur)
9850 xmlXPathCompSwap(op);
9851 return (total + cur);
9852 case XPATH_OP_ROOT:
9853 xmlXPathRoot(ctxt);
9854 return (0);
9855 case XPATH_OP_NODE:
9856 if (op->ch1 != -1)
9857 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009858 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009859 if (op->ch2 != -1)
9860 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009861 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009862 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9863 return (total);
9864 case XPATH_OP_RESET:
9865 if (op->ch1 != -1)
9866 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009867 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009868 if (op->ch2 != -1)
9869 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009870 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009871 ctxt->context->node = NULL;
9872 return (total);
9873 case XPATH_OP_COLLECT:{
9874 if (op->ch1 == -1)
9875 return (total);
9876
9877 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009878 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009879
9880 /*
9881 * Optimization for [n] selection where n is a number
9882 */
9883 if ((op->ch2 != -1) &&
9884 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9885 (comp->steps[op->ch2].ch1 == -1) &&
9886 (comp->steps[op->ch2].ch2 != -1) &&
9887 (comp->steps[comp->steps[op->ch2].ch2].op ==
9888 XPATH_OP_VALUE)) {
9889 xmlXPathObjectPtr val;
9890
9891 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9892 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9893 int indx = (int) val->floatval;
9894
9895 if (val->floatval == (float) indx) {
9896 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9897 first, NULL);
9898 return (total);
9899 }
9900 }
9901 }
9902 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9903 return (total);
9904 }
9905 case XPATH_OP_VALUE:
9906 valuePush(ctxt,
9907 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9908 return (0);
9909 case XPATH_OP_SORT:
9910 if (op->ch1 != -1)
9911 total +=
9912 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9913 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009914 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009915 if ((ctxt->value != NULL)
9916 && (ctxt->value->type == XPATH_NODESET)
9917 && (ctxt->value->nodesetval != NULL))
9918 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9919 return (total);
9920 default:
9921 return (xmlXPathCompOpEval(ctxt, op));
9922 }
9923}
9924
9925/**
9926 * xmlXPathCompOpEvalLast:
9927 * @ctxt: the XPath parser context with the compiled expression
9928 * @op: an XPath compiled operation
9929 * @last: the last elem found so far
9930 *
9931 * Evaluate the Precompiled XPath operation searching only the last
9932 * element in document order
9933 *
William M. Brack08171912003-12-29 02:52:11 +00009934 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009935 */
9936static int
9937xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9938 xmlNodePtr * last)
9939{
9940 int total = 0, cur;
9941 xmlXPathCompExprPtr comp;
9942 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009943 xmlNodePtr bak;
9944 xmlDocPtr bakd;
9945 int pp;
9946 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009947
Daniel Veillard556c6682001-10-06 09:59:51 +00009948 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009949 comp = ctxt->comp;
9950 switch (op->op) {
9951 case XPATH_OP_END:
9952 return (0);
9953 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009954 bakd = ctxt->context->doc;
9955 bak = ctxt->context->node;
9956 pp = ctxt->context->proximityPosition;
9957 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009958 total =
9959 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009960 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009961 if ((ctxt->value != NULL)
9962 && (ctxt->value->type == XPATH_NODESET)
9963 && (ctxt->value->nodesetval != NULL)
9964 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9965 /*
9966 * limit tree traversing to first node in the result
9967 */
9968 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9969 *last =
9970 ctxt->value->nodesetval->nodeTab[ctxt->value->
9971 nodesetval->nodeNr -
9972 1];
9973 }
William M. Brackce4fc562004-01-22 02:47:18 +00009974 ctxt->context->doc = bakd;
9975 ctxt->context->node = bak;
9976 ctxt->context->proximityPosition = pp;
9977 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009978 cur =
9979 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009980 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009981 if ((ctxt->value != NULL)
9982 && (ctxt->value->type == XPATH_NODESET)
9983 && (ctxt->value->nodesetval != NULL)
9984 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9985 }
9986 CHECK_TYPE0(XPATH_NODESET);
9987 arg2 = valuePop(ctxt);
9988
9989 CHECK_TYPE0(XPATH_NODESET);
9990 arg1 = valuePop(ctxt);
9991
9992 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9993 arg2->nodesetval);
9994 valuePush(ctxt, arg1);
9995 xmlXPathFreeObject(arg2);
9996 /* optimizer */
9997 if (total > cur)
9998 xmlXPathCompSwap(op);
9999 return (total + cur);
10000 case XPATH_OP_ROOT:
10001 xmlXPathRoot(ctxt);
10002 return (0);
10003 case XPATH_OP_NODE:
10004 if (op->ch1 != -1)
10005 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010006 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010007 if (op->ch2 != -1)
10008 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010009 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010010 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10011 return (total);
10012 case XPATH_OP_RESET:
10013 if (op->ch1 != -1)
10014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010015 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010016 if (op->ch2 != -1)
10017 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010018 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010019 ctxt->context->node = NULL;
10020 return (total);
10021 case XPATH_OP_COLLECT:{
10022 if (op->ch1 == -1)
10023 return (0);
10024
10025 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010026 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010027
10028 /*
10029 * Optimization for [n] selection where n is a number
10030 */
10031 if ((op->ch2 != -1) &&
10032 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10033 (comp->steps[op->ch2].ch1 == -1) &&
10034 (comp->steps[op->ch2].ch2 != -1) &&
10035 (comp->steps[comp->steps[op->ch2].ch2].op ==
10036 XPATH_OP_VALUE)) {
10037 xmlXPathObjectPtr val;
10038
10039 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10040 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10041 int indx = (int) val->floatval;
10042
10043 if (val->floatval == (float) indx) {
10044 total +=
10045 xmlXPathNodeCollectAndTestNth(ctxt, op,
10046 indx, NULL,
10047 last);
10048 return (total);
10049 }
10050 }
10051 }
10052 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10053 return (total);
10054 }
10055 case XPATH_OP_VALUE:
10056 valuePush(ctxt,
10057 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10058 return (0);
10059 case XPATH_OP_SORT:
10060 if (op->ch1 != -1)
10061 total +=
10062 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10063 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010064 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010065 if ((ctxt->value != NULL)
10066 && (ctxt->value->type == XPATH_NODESET)
10067 && (ctxt->value->nodesetval != NULL))
10068 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10069 return (total);
10070 default:
10071 return (xmlXPathCompOpEval(ctxt, op));
10072 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010073}
10074
Owen Taylor3473f882001-02-23 17:55:21 +000010075/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010076 * xmlXPathCompOpEval:
10077 * @ctxt: the XPath parser context with the compiled expression
10078 * @op: an XPath compiled operation
10079 *
10080 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010081 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010082 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010083static int
10084xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10085{
10086 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010087 int equal, ret;
10088 xmlXPathCompExprPtr comp;
10089 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010090 xmlNodePtr bak;
10091 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010092 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010093 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010094
Daniel Veillard556c6682001-10-06 09:59:51 +000010095 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010096 comp = ctxt->comp;
10097 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010098 case XPATH_OP_END:
10099 return (0);
10100 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010101 bakd = ctxt->context->doc;
10102 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010103 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010104 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010105 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010106 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010107 xmlXPathBooleanFunction(ctxt, 1);
10108 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10109 return (total);
10110 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010111 ctxt->context->doc = bakd;
10112 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010113 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010114 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010115 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010116 if (ctxt->error) {
10117 xmlXPathFreeObject(arg2);
10118 return(0);
10119 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010120 xmlXPathBooleanFunction(ctxt, 1);
10121 arg1 = valuePop(ctxt);
10122 arg1->boolval &= arg2->boolval;
10123 valuePush(ctxt, arg1);
10124 xmlXPathFreeObject(arg2);
10125 return (total);
10126 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010127 bakd = ctxt->context->doc;
10128 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010129 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010130 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010132 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010133 xmlXPathBooleanFunction(ctxt, 1);
10134 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10135 return (total);
10136 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010137 ctxt->context->doc = bakd;
10138 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010139 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010140 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010142 if (ctxt->error) {
10143 xmlXPathFreeObject(arg2);
10144 return(0);
10145 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010146 xmlXPathBooleanFunction(ctxt, 1);
10147 arg1 = valuePop(ctxt);
10148 arg1->boolval |= arg2->boolval;
10149 valuePush(ctxt, arg1);
10150 xmlXPathFreeObject(arg2);
10151 return (total);
10152 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010153 bakd = ctxt->context->doc;
10154 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010155 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010156 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010157 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010158 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010159 ctxt->context->doc = bakd;
10160 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010161 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010162 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010163 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010164 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010165 if (op->value)
10166 equal = xmlXPathEqualValues(ctxt);
10167 else
10168 equal = xmlXPathNotEqualValues(ctxt);
10169 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010170 return (total);
10171 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010172 bakd = ctxt->context->doc;
10173 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010174 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010175 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010176 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010177 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010178 ctxt->context->doc = bakd;
10179 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010180 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010181 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010182 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010183 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010184 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10185 valuePush(ctxt, xmlXPathNewBoolean(ret));
10186 return (total);
10187 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010188 bakd = ctxt->context->doc;
10189 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010190 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010191 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010192 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010193 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010194 if (op->ch2 != -1) {
10195 ctxt->context->doc = bakd;
10196 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010197 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010198 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010199 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010200 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010201 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010202 if (op->value == 0)
10203 xmlXPathSubValues(ctxt);
10204 else if (op->value == 1)
10205 xmlXPathAddValues(ctxt);
10206 else if (op->value == 2)
10207 xmlXPathValueFlipSign(ctxt);
10208 else if (op->value == 3) {
10209 CAST_TO_NUMBER;
10210 CHECK_TYPE0(XPATH_NUMBER);
10211 }
10212 return (total);
10213 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010214 bakd = ctxt->context->doc;
10215 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010216 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010217 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010218 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010219 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010220 ctxt->context->doc = bakd;
10221 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010222 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010223 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010224 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010225 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010226 if (op->value == 0)
10227 xmlXPathMultValues(ctxt);
10228 else if (op->value == 1)
10229 xmlXPathDivValues(ctxt);
10230 else if (op->value == 2)
10231 xmlXPathModValues(ctxt);
10232 return (total);
10233 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010234 bakd = ctxt->context->doc;
10235 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010236 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010237 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010239 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010240 ctxt->context->doc = bakd;
10241 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010242 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010243 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010244 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010245 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010246 CHECK_TYPE0(XPATH_NODESET);
10247 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010248
Daniel Veillardf06307e2001-07-03 10:35:50 +000010249 CHECK_TYPE0(XPATH_NODESET);
10250 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010251
Daniel Veillardf06307e2001-07-03 10:35:50 +000010252 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10253 arg2->nodesetval);
10254 valuePush(ctxt, arg1);
10255 xmlXPathFreeObject(arg2);
10256 return (total);
10257 case XPATH_OP_ROOT:
10258 xmlXPathRoot(ctxt);
10259 return (total);
10260 case XPATH_OP_NODE:
10261 if (op->ch1 != -1)
10262 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010263 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010264 if (op->ch2 != -1)
10265 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010266 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010267 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10268 return (total);
10269 case XPATH_OP_RESET:
10270 if (op->ch1 != -1)
10271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010272 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010273 if (op->ch2 != -1)
10274 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010275 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 ctxt->context->node = NULL;
10277 return (total);
10278 case XPATH_OP_COLLECT:{
10279 if (op->ch1 == -1)
10280 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010281
Daniel Veillardf06307e2001-07-03 10:35:50 +000010282 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010283 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010284
Daniel Veillardf06307e2001-07-03 10:35:50 +000010285 /*
10286 * Optimization for [n] selection where n is a number
10287 */
10288 if ((op->ch2 != -1) &&
10289 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10290 (comp->steps[op->ch2].ch1 == -1) &&
10291 (comp->steps[op->ch2].ch2 != -1) &&
10292 (comp->steps[comp->steps[op->ch2].ch2].op ==
10293 XPATH_OP_VALUE)) {
10294 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010295
Daniel Veillardf06307e2001-07-03 10:35:50 +000010296 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10297 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10298 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010299
Daniel Veillardf06307e2001-07-03 10:35:50 +000010300 if (val->floatval == (float) indx) {
10301 total +=
10302 xmlXPathNodeCollectAndTestNth(ctxt, op,
10303 indx, NULL,
10304 NULL);
10305 return (total);
10306 }
10307 }
10308 }
10309 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10310 return (total);
10311 }
10312 case XPATH_OP_VALUE:
10313 valuePush(ctxt,
10314 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10315 return (total);
10316 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010317 xmlXPathObjectPtr val;
10318
Daniel Veillardf06307e2001-07-03 10:35:50 +000010319 if (op->ch1 != -1)
10320 total +=
10321 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010322 if (op->value5 == NULL) {
10323 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10324 if (val == NULL) {
10325 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10326 return(0);
10327 }
10328 valuePush(ctxt, val);
10329 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010330 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010331
Daniel Veillardf06307e2001-07-03 10:35:50 +000010332 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10333 if (URI == NULL) {
10334 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010335 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010336 op->value4, op->value5);
10337 return (total);
10338 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010339 val = xmlXPathVariableLookupNS(ctxt->context,
10340 op->value4, URI);
10341 if (val == NULL) {
10342 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10343 return(0);
10344 }
10345 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010346 }
10347 return (total);
10348 }
10349 case XPATH_OP_FUNCTION:{
10350 xmlXPathFunction func;
10351 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010352 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010353
10354 if (op->ch1 != -1)
10355 total +=
10356 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010357 if (ctxt->valueNr < op->value) {
10358 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010359 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010360 ctxt->error = XPATH_INVALID_OPERAND;
10361 return (total);
10362 }
10363 for (i = 0; i < op->value; i++)
10364 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10365 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010366 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010367 ctxt->error = XPATH_INVALID_OPERAND;
10368 return (total);
10369 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010370 if (op->cache != NULL)
10371 func = (xmlXPathFunction) op->cache;
10372 else {
10373 const xmlChar *URI = NULL;
10374
10375 if (op->value5 == NULL)
10376 func =
10377 xmlXPathFunctionLookup(ctxt->context,
10378 op->value4);
10379 else {
10380 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10381 if (URI == NULL) {
10382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010383 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 op->value4, op->value5);
10385 return (total);
10386 }
10387 func = xmlXPathFunctionLookupNS(ctxt->context,
10388 op->value4, URI);
10389 }
10390 if (func == NULL) {
10391 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010392 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010393 op->value4);
10394 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010395 }
10396 op->cache = (void *) func;
10397 op->cacheURI = (void *) URI;
10398 }
10399 oldFunc = ctxt->context->function;
10400 oldFuncURI = ctxt->context->functionURI;
10401 ctxt->context->function = op->value4;
10402 ctxt->context->functionURI = op->cacheURI;
10403 func(ctxt, op->value);
10404 ctxt->context->function = oldFunc;
10405 ctxt->context->functionURI = oldFuncURI;
10406 return (total);
10407 }
10408 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010409 bakd = ctxt->context->doc;
10410 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010411 if (op->ch1 != -1)
10412 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010413 ctxt->context->doc = bakd;
10414 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010415 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010416 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010417 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010418 ctxt->context->doc = bakd;
10419 ctxt->context->node = bak;
10420 CHECK_ERROR0;
10421 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 return (total);
10423 case XPATH_OP_PREDICATE:
10424 case XPATH_OP_FILTER:{
10425 xmlXPathObjectPtr res;
10426 xmlXPathObjectPtr obj, tmp;
10427 xmlNodeSetPtr newset = NULL;
10428 xmlNodeSetPtr oldset;
10429 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010430 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010431 int i;
10432
10433 /*
10434 * Optimization for ()[1] selection i.e. the first elem
10435 */
10436 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10437 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10438 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10439 xmlXPathObjectPtr val;
10440
10441 val = comp->steps[op->ch2].value4;
10442 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10443 (val->floatval == 1.0)) {
10444 xmlNodePtr first = NULL;
10445
10446 total +=
10447 xmlXPathCompOpEvalFirst(ctxt,
10448 &comp->steps[op->ch1],
10449 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010450 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010451 /*
10452 * The nodeset should be in document order,
10453 * Keep only the first value
10454 */
10455 if ((ctxt->value != NULL) &&
10456 (ctxt->value->type == XPATH_NODESET) &&
10457 (ctxt->value->nodesetval != NULL) &&
10458 (ctxt->value->nodesetval->nodeNr > 1))
10459 ctxt->value->nodesetval->nodeNr = 1;
10460 return (total);
10461 }
10462 }
10463 /*
10464 * Optimization for ()[last()] selection i.e. the last elem
10465 */
10466 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10467 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10468 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10469 int f = comp->steps[op->ch2].ch1;
10470
10471 if ((f != -1) &&
10472 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10473 (comp->steps[f].value5 == NULL) &&
10474 (comp->steps[f].value == 0) &&
10475 (comp->steps[f].value4 != NULL) &&
10476 (xmlStrEqual
10477 (comp->steps[f].value4, BAD_CAST "last"))) {
10478 xmlNodePtr last = NULL;
10479
10480 total +=
10481 xmlXPathCompOpEvalLast(ctxt,
10482 &comp->steps[op->ch1],
10483 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010484 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010485 /*
10486 * The nodeset should be in document order,
10487 * Keep only the last value
10488 */
10489 if ((ctxt->value != NULL) &&
10490 (ctxt->value->type == XPATH_NODESET) &&
10491 (ctxt->value->nodesetval != NULL) &&
10492 (ctxt->value->nodesetval->nodeTab != NULL) &&
10493 (ctxt->value->nodesetval->nodeNr > 1)) {
10494 ctxt->value->nodesetval->nodeTab[0] =
10495 ctxt->value->nodesetval->nodeTab[ctxt->
10496 value->
10497 nodesetval->
10498 nodeNr -
10499 1];
10500 ctxt->value->nodesetval->nodeNr = 1;
10501 }
10502 return (total);
10503 }
10504 }
10505
10506 if (op->ch1 != -1)
10507 total +=
10508 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010509 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010510 if (op->ch2 == -1)
10511 return (total);
10512 if (ctxt->value == NULL)
10513 return (total);
10514
10515 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010516
10517#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010518 /*
10519 * Hum are we filtering the result of an XPointer expression
10520 */
10521 if (ctxt->value->type == XPATH_LOCATIONSET) {
10522 xmlLocationSetPtr newlocset = NULL;
10523 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010524
Daniel Veillardf06307e2001-07-03 10:35:50 +000010525 /*
10526 * Extract the old locset, and then evaluate the result of the
10527 * expression for all the element in the locset. use it to grow
10528 * up a new locset.
10529 */
10530 CHECK_TYPE0(XPATH_LOCATIONSET);
10531 obj = valuePop(ctxt);
10532 oldlocset = obj->user;
10533 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010534
Daniel Veillardf06307e2001-07-03 10:35:50 +000010535 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10536 ctxt->context->contextSize = 0;
10537 ctxt->context->proximityPosition = 0;
10538 if (op->ch2 != -1)
10539 total +=
10540 xmlXPathCompOpEval(ctxt,
10541 &comp->steps[op->ch2]);
10542 res = valuePop(ctxt);
10543 if (res != NULL)
10544 xmlXPathFreeObject(res);
10545 valuePush(ctxt, obj);
10546 CHECK_ERROR0;
10547 return (total);
10548 }
10549 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010550
Daniel Veillardf06307e2001-07-03 10:35:50 +000010551 for (i = 0; i < oldlocset->locNr; i++) {
10552 /*
10553 * Run the evaluation with a node list made of a
10554 * single item in the nodelocset.
10555 */
10556 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010557 ctxt->context->contextSize = oldlocset->locNr;
10558 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010559 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10560 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010561
Daniel Veillardf06307e2001-07-03 10:35:50 +000010562 if (op->ch2 != -1)
10563 total +=
10564 xmlXPathCompOpEval(ctxt,
10565 &comp->steps[op->ch2]);
10566 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010567
Daniel Veillardf06307e2001-07-03 10:35:50 +000010568 /*
10569 * The result of the evaluation need to be tested to
10570 * decided whether the filter succeeded or not
10571 */
10572 res = valuePop(ctxt);
10573 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10574 xmlXPtrLocationSetAdd(newlocset,
10575 xmlXPathObjectCopy
10576 (oldlocset->locTab[i]));
10577 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010578
Daniel Veillardf06307e2001-07-03 10:35:50 +000010579 /*
10580 * Cleanup
10581 */
10582 if (res != NULL)
10583 xmlXPathFreeObject(res);
10584 if (ctxt->value == tmp) {
10585 res = valuePop(ctxt);
10586 xmlXPathFreeObject(res);
10587 }
10588
10589 ctxt->context->node = NULL;
10590 }
10591
10592 /*
10593 * The result is used as the new evaluation locset.
10594 */
10595 xmlXPathFreeObject(obj);
10596 ctxt->context->node = NULL;
10597 ctxt->context->contextSize = -1;
10598 ctxt->context->proximityPosition = -1;
10599 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10600 ctxt->context->node = oldnode;
10601 return (total);
10602 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010603#endif /* LIBXML_XPTR_ENABLED */
10604
Daniel Veillardf06307e2001-07-03 10:35:50 +000010605 /*
10606 * Extract the old set, and then evaluate the result of the
10607 * expression for all the element in the set. use it to grow
10608 * up a new set.
10609 */
10610 CHECK_TYPE0(XPATH_NODESET);
10611 obj = valuePop(ctxt);
10612 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010613
Daniel Veillardf06307e2001-07-03 10:35:50 +000010614 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010615 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010616 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010617
Daniel Veillardf06307e2001-07-03 10:35:50 +000010618 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10619 ctxt->context->contextSize = 0;
10620 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010621/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010622 if (op->ch2 != -1)
10623 total +=
10624 xmlXPathCompOpEval(ctxt,
10625 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010626 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010627 res = valuePop(ctxt);
10628 if (res != NULL)
10629 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010630*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010631 valuePush(ctxt, obj);
10632 ctxt->context->node = oldnode;
10633 CHECK_ERROR0;
10634 } else {
10635 /*
10636 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010637 * Also set the xpath document in case things like
10638 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010639 */
10640 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010641
Daniel Veillardf06307e2001-07-03 10:35:50 +000010642 for (i = 0; i < oldset->nodeNr; i++) {
10643 /*
10644 * Run the evaluation with a node list made of
10645 * a single item in the nodeset.
10646 */
10647 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010648 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10649 (oldset->nodeTab[i]->doc != NULL))
10650 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010651 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10652 valuePush(ctxt, tmp);
10653 ctxt->context->contextSize = oldset->nodeNr;
10654 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010655
Daniel Veillardf06307e2001-07-03 10:35:50 +000010656 if (op->ch2 != -1)
10657 total +=
10658 xmlXPathCompOpEval(ctxt,
10659 &comp->steps[op->ch2]);
10660 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010661
Daniel Veillardf06307e2001-07-03 10:35:50 +000010662 /*
William M. Brack08171912003-12-29 02:52:11 +000010663 * The result of the evaluation needs to be tested to
10664 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010665 */
10666 res = valuePop(ctxt);
10667 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10668 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10669 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010670
Daniel Veillardf06307e2001-07-03 10:35:50 +000010671 /*
10672 * Cleanup
10673 */
10674 if (res != NULL)
10675 xmlXPathFreeObject(res);
10676 if (ctxt->value == tmp) {
10677 res = valuePop(ctxt);
10678 xmlXPathFreeObject(res);
10679 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010680
Daniel Veillardf06307e2001-07-03 10:35:50 +000010681 ctxt->context->node = NULL;
10682 }
10683
10684 /*
10685 * The result is used as the new evaluation set.
10686 */
10687 xmlXPathFreeObject(obj);
10688 ctxt->context->node = NULL;
10689 ctxt->context->contextSize = -1;
10690 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010691 /* may want to move this past the '}' later */
10692 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010693 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10694 }
10695 ctxt->context->node = oldnode;
10696 return (total);
10697 }
10698 case XPATH_OP_SORT:
10699 if (op->ch1 != -1)
10700 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010701 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010702 if ((ctxt->value != NULL) &&
10703 (ctxt->value->type == XPATH_NODESET) &&
10704 (ctxt->value->nodesetval != NULL))
10705 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10706 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010707#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010708 case XPATH_OP_RANGETO:{
10709 xmlXPathObjectPtr range;
10710 xmlXPathObjectPtr res, obj;
10711 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010712 xmlLocationSetPtr newlocset = NULL;
10713 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010714 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010715 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010716
Daniel Veillardf06307e2001-07-03 10:35:50 +000010717 if (op->ch1 != -1)
10718 total +=
10719 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10720 if (op->ch2 == -1)
10721 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010722
William M. Brack08171912003-12-29 02:52:11 +000010723 if (ctxt->value->type == XPATH_LOCATIONSET) {
10724 /*
10725 * Extract the old locset, and then evaluate the result of the
10726 * expression for all the element in the locset. use it to grow
10727 * up a new locset.
10728 */
10729 CHECK_TYPE0(XPATH_LOCATIONSET);
10730 obj = valuePop(ctxt);
10731 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010732
William M. Brack08171912003-12-29 02:52:11 +000010733 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010734 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010735 ctxt->context->contextSize = 0;
10736 ctxt->context->proximityPosition = 0;
10737 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10738 res = valuePop(ctxt);
10739 if (res != NULL)
10740 xmlXPathFreeObject(res);
10741 valuePush(ctxt, obj);
10742 CHECK_ERROR0;
10743 return (total);
10744 }
10745 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010746
William M. Brack08171912003-12-29 02:52:11 +000010747 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010748 /*
William M. Brack08171912003-12-29 02:52:11 +000010749 * Run the evaluation with a node list made of a
10750 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010751 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010752 ctxt->context->node = oldlocset->locTab[i]->user;
10753 ctxt->context->contextSize = oldlocset->locNr;
10754 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010755 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10756 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010757
Daniel Veillardf06307e2001-07-03 10:35:50 +000010758 if (op->ch2 != -1)
10759 total +=
10760 xmlXPathCompOpEval(ctxt,
10761 &comp->steps[op->ch2]);
10762 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010763
Daniel Veillardf06307e2001-07-03 10:35:50 +000010764 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010765 if (res->type == XPATH_LOCATIONSET) {
10766 xmlLocationSetPtr rloc =
10767 (xmlLocationSetPtr)res->user;
10768 for (j=0; j<rloc->locNr; j++) {
10769 range = xmlXPtrNewRange(
10770 oldlocset->locTab[i]->user,
10771 oldlocset->locTab[i]->index,
10772 rloc->locTab[j]->user2,
10773 rloc->locTab[j]->index2);
10774 if (range != NULL) {
10775 xmlXPtrLocationSetAdd(newlocset, range);
10776 }
10777 }
10778 } else {
10779 range = xmlXPtrNewRangeNodeObject(
10780 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10781 if (range != NULL) {
10782 xmlXPtrLocationSetAdd(newlocset,range);
10783 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010784 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010785
Daniel Veillardf06307e2001-07-03 10:35:50 +000010786 /*
10787 * Cleanup
10788 */
10789 if (res != NULL)
10790 xmlXPathFreeObject(res);
10791 if (ctxt->value == tmp) {
10792 res = valuePop(ctxt);
10793 xmlXPathFreeObject(res);
10794 }
10795
10796 ctxt->context->node = NULL;
10797 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010798 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010799 CHECK_TYPE0(XPATH_NODESET);
10800 obj = valuePop(ctxt);
10801 oldset = obj->nodesetval;
10802 ctxt->context->node = NULL;
10803
10804 newlocset = xmlXPtrLocationSetCreate(NULL);
10805
10806 if (oldset != NULL) {
10807 for (i = 0; i < oldset->nodeNr; i++) {
10808 /*
10809 * Run the evaluation with a node list made of a single item
10810 * in the nodeset.
10811 */
10812 ctxt->context->node = oldset->nodeTab[i];
10813 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10814 valuePush(ctxt, tmp);
10815
10816 if (op->ch2 != -1)
10817 total +=
10818 xmlXPathCompOpEval(ctxt,
10819 &comp->steps[op->ch2]);
10820 CHECK_ERROR0;
10821
William M. Brack08171912003-12-29 02:52:11 +000010822 res = valuePop(ctxt);
10823 range =
10824 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10825 res);
10826 if (range != NULL) {
10827 xmlXPtrLocationSetAdd(newlocset, range);
10828 }
10829
10830 /*
10831 * Cleanup
10832 */
10833 if (res != NULL)
10834 xmlXPathFreeObject(res);
10835 if (ctxt->value == tmp) {
10836 res = valuePop(ctxt);
10837 xmlXPathFreeObject(res);
10838 }
10839
10840 ctxt->context->node = NULL;
10841 }
10842 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010843 }
10844
10845 /*
10846 * The result is used as the new evaluation set.
10847 */
10848 xmlXPathFreeObject(obj);
10849 ctxt->context->node = NULL;
10850 ctxt->context->contextSize = -1;
10851 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010852 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010853 return (total);
10854 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010855#endif /* LIBXML_XPTR_ENABLED */
10856 }
10857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010858 "XPath: unknown precompiled operation %d\n", op->op);
10859 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010860}
10861
10862/**
10863 * xmlXPathRunEval:
10864 * @ctxt: the XPath parser context with the compiled expression
10865 *
10866 * Evaluate the Precompiled XPath expression in the given context.
10867 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010868static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010869xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10870 xmlXPathCompExprPtr comp;
10871
10872 if ((ctxt == NULL) || (ctxt->comp == NULL))
10873 return;
10874
10875 if (ctxt->valueTab == NULL) {
10876 /* Allocate the value stack */
10877 ctxt->valueTab = (xmlXPathObjectPtr *)
10878 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10879 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010880 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010881 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010882 }
10883 ctxt->valueNr = 0;
10884 ctxt->valueMax = 10;
10885 ctxt->value = NULL;
10886 }
10887 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010888 if(comp->last < 0) {
10889 xmlGenericError(xmlGenericErrorContext,
10890 "xmlXPathRunEval: last is less than zero\n");
10891 return;
10892 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010893 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10894}
10895
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010896/************************************************************************
10897 * *
10898 * Public interfaces *
10899 * *
10900 ************************************************************************/
10901
10902/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010903 * xmlXPathEvalPredicate:
10904 * @ctxt: the XPath context
10905 * @res: the Predicate Expression evaluation result
10906 *
10907 * Evaluate a predicate result for the current node.
10908 * A PredicateExpr is evaluated by evaluating the Expr and converting
10909 * the result to a boolean. If the result is a number, the result will
10910 * be converted to true if the number is equal to the position of the
10911 * context node in the context node list (as returned by the position
10912 * function) and will be converted to false otherwise; if the result
10913 * is not a number, then the result will be converted as if by a call
10914 * to the boolean function.
10915 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010916 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010917 */
10918int
10919xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10920 if (res == NULL) return(0);
10921 switch (res->type) {
10922 case XPATH_BOOLEAN:
10923 return(res->boolval);
10924 case XPATH_NUMBER:
10925 return(res->floatval == ctxt->proximityPosition);
10926 case XPATH_NODESET:
10927 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010928 if (res->nodesetval == NULL)
10929 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010930 return(res->nodesetval->nodeNr != 0);
10931 case XPATH_STRING:
10932 return((res->stringval != NULL) &&
10933 (xmlStrlen(res->stringval) != 0));
10934 default:
10935 STRANGE
10936 }
10937 return(0);
10938}
10939
10940/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010941 * xmlXPathEvaluatePredicateResult:
10942 * @ctxt: the XPath Parser context
10943 * @res: the Predicate Expression evaluation result
10944 *
10945 * Evaluate a predicate result for the current node.
10946 * A PredicateExpr is evaluated by evaluating the Expr and converting
10947 * the result to a boolean. If the result is a number, the result will
10948 * be converted to true if the number is equal to the position of the
10949 * context node in the context node list (as returned by the position
10950 * function) and will be converted to false otherwise; if the result
10951 * is not a number, then the result will be converted as if by a call
10952 * to the boolean function.
10953 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010954 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010955 */
10956int
10957xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10958 xmlXPathObjectPtr res) {
10959 if (res == NULL) return(0);
10960 switch (res->type) {
10961 case XPATH_BOOLEAN:
10962 return(res->boolval);
10963 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010964#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010965 return((res->floatval == ctxt->context->proximityPosition) &&
10966 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000010967#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010968 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000010969#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010970 case XPATH_NODESET:
10971 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010972 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010973 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010974 return(res->nodesetval->nodeNr != 0);
10975 case XPATH_STRING:
10976 return((res->stringval != NULL) &&
10977 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010978#ifdef LIBXML_XPTR_ENABLED
10979 case XPATH_LOCATIONSET:{
10980 xmlLocationSetPtr ptr = res->user;
10981 if (ptr == NULL)
10982 return(0);
10983 return (ptr->locNr != 0);
10984 }
10985#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010986 default:
10987 STRANGE
10988 }
10989 return(0);
10990}
10991
10992/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010993 * xmlXPathCtxtCompile:
10994 * @ctxt: an XPath context
10995 * @str: the XPath expression
10996 *
10997 * Compile an XPath expression
10998 *
10999 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
11000 * the caller has to free the object.
11001 */
11002xmlXPathCompExprPtr
11003xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11004 xmlXPathParserContextPtr pctxt;
11005 xmlXPathCompExprPtr comp;
11006
11007 xmlXPathInit();
11008
11009 pctxt = xmlXPathNewParserContext(str, ctxt);
11010 xmlXPathCompileExpr(pctxt);
11011
11012 if( pctxt->error != XPATH_EXPRESSION_OK )
11013 {
11014 xmlXPathFreeParserContext(pctxt);
11015 return (0);
11016 }
11017
11018 if (*pctxt->cur != 0) {
11019 /*
11020 * aleksey: in some cases this line prints *second* error message
11021 * (see bug #78858) and probably this should be fixed.
11022 * However, we are not sure that all error messages are printed
11023 * out in other places. It's not critical so we leave it as-is for now
11024 */
11025 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11026 comp = NULL;
11027 } else {
11028 comp = pctxt->comp;
11029 pctxt->comp = NULL;
11030 }
11031 xmlXPathFreeParserContext(pctxt);
11032 if (comp != NULL) {
11033 comp->expr = xmlStrdup(str);
11034#ifdef DEBUG_EVAL_COUNTS
11035 comp->string = xmlStrdup(str);
11036 comp->nb = 0;
11037#endif
11038 }
11039 return(comp);
11040}
11041
11042/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011043 * xmlXPathCompile:
11044 * @str: the XPath expression
11045 *
11046 * Compile an XPath expression
11047 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011048 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011049 * the caller has to free the object.
11050 */
11051xmlXPathCompExprPtr
11052xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011053 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011054}
11055
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011056/**
11057 * xmlXPathCompiledEval:
11058 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011059 * @ctx: the XPath context
11060 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011061 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011062 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011063 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011064 * the caller has to free the object.
11065 */
11066xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011067xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011068 xmlXPathParserContextPtr ctxt;
11069 xmlXPathObjectPtr res, tmp, init = NULL;
11070 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011071#ifndef LIBXML_THREAD_ENABLED
11072 static int reentance = 0;
11073#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011074
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011075 if ((comp == NULL) || (ctx == NULL))
11076 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011077 xmlXPathInit();
11078
11079 CHECK_CONTEXT(ctx)
11080
Daniel Veillard81463942001-10-16 12:34:39 +000011081#ifndef LIBXML_THREAD_ENABLED
11082 reentance++;
11083 if (reentance > 1)
11084 xmlXPathDisableOptimizer = 1;
11085#endif
11086
Daniel Veillardf06307e2001-07-03 10:35:50 +000011087#ifdef DEBUG_EVAL_COUNTS
11088 comp->nb++;
11089 if ((comp->string != NULL) && (comp->nb > 100)) {
11090 fprintf(stderr, "100 x %s\n", comp->string);
11091 comp->nb = 0;
11092 }
11093#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011094 ctxt = xmlXPathCompParserContext(comp, ctx);
11095 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011096
11097 if (ctxt->value == NULL) {
11098 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011099 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011100 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011101 } else {
11102 res = valuePop(ctxt);
11103 }
11104
Daniel Veillardf06307e2001-07-03 10:35:50 +000011105
Owen Taylor3473f882001-02-23 17:55:21 +000011106 do {
11107 tmp = valuePop(ctxt);
11108 if (tmp != NULL) {
11109 if (tmp != init)
11110 stack++;
11111 xmlXPathFreeObject(tmp);
11112 }
11113 } while (tmp != NULL);
11114 if ((stack != 0) && (res != NULL)) {
11115 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011116 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011117 stack);
11118 }
11119 if (ctxt->error != XPATH_EXPRESSION_OK) {
11120 xmlXPathFreeObject(res);
11121 res = NULL;
11122 }
11123
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011124
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011125 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011126 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011127#ifndef LIBXML_THREAD_ENABLED
11128 reentance--;
11129#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011130 return(res);
11131}
11132
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011133/**
11134 * xmlXPathEvalExpr:
11135 * @ctxt: the XPath Parser context
11136 *
11137 * Parse and evaluate an XPath expression in the given context,
11138 * then push the result on the context stack
11139 */
11140void
11141xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11142 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011143 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011144 xmlXPathRunEval(ctxt);
11145}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011146
11147/**
11148 * xmlXPathEval:
11149 * @str: the XPath expression
11150 * @ctx: the XPath context
11151 *
11152 * Evaluate the XPath Location Path in the given context.
11153 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011154 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011155 * the caller has to free the object.
11156 */
11157xmlXPathObjectPtr
11158xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11159 xmlXPathParserContextPtr ctxt;
11160 xmlXPathObjectPtr res, tmp, init = NULL;
11161 int stack = 0;
11162
11163 xmlXPathInit();
11164
11165 CHECK_CONTEXT(ctx)
11166
11167 ctxt = xmlXPathNewParserContext(str, ctx);
11168 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011169
11170 if (ctxt->value == NULL) {
11171 xmlGenericError(xmlGenericErrorContext,
11172 "xmlXPathEval: evaluation failed\n");
11173 res = NULL;
11174 } else if (*ctxt->cur != 0) {
11175 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11176 res = NULL;
11177 } else {
11178 res = valuePop(ctxt);
11179 }
11180
11181 do {
11182 tmp = valuePop(ctxt);
11183 if (tmp != NULL) {
11184 if (tmp != init)
11185 stack++;
11186 xmlXPathFreeObject(tmp);
11187 }
11188 } while (tmp != NULL);
11189 if ((stack != 0) && (res != NULL)) {
11190 xmlGenericError(xmlGenericErrorContext,
11191 "xmlXPathEval: %d object left on the stack\n",
11192 stack);
11193 }
11194 if (ctxt->error != XPATH_EXPRESSION_OK) {
11195 xmlXPathFreeObject(res);
11196 res = NULL;
11197 }
11198
Owen Taylor3473f882001-02-23 17:55:21 +000011199 xmlXPathFreeParserContext(ctxt);
11200 return(res);
11201}
11202
11203/**
11204 * xmlXPathEvalExpression:
11205 * @str: the XPath expression
11206 * @ctxt: the XPath context
11207 *
11208 * Evaluate the XPath expression in the given context.
11209 *
11210 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11211 * the caller has to free the object.
11212 */
11213xmlXPathObjectPtr
11214xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11215 xmlXPathParserContextPtr pctxt;
11216 xmlXPathObjectPtr res, tmp;
11217 int stack = 0;
11218
11219 xmlXPathInit();
11220
11221 CHECK_CONTEXT(ctxt)
11222
11223 pctxt = xmlXPathNewParserContext(str, ctxt);
11224 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011225
11226 if (*pctxt->cur != 0) {
11227 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11228 res = NULL;
11229 } else {
11230 res = valuePop(pctxt);
11231 }
11232 do {
11233 tmp = valuePop(pctxt);
11234 if (tmp != NULL) {
11235 xmlXPathFreeObject(tmp);
11236 stack++;
11237 }
11238 } while (tmp != NULL);
11239 if ((stack != 0) && (res != NULL)) {
11240 xmlGenericError(xmlGenericErrorContext,
11241 "xmlXPathEvalExpression: %d object left on the stack\n",
11242 stack);
11243 }
11244 xmlXPathFreeParserContext(pctxt);
11245 return(res);
11246}
11247
Daniel Veillard42766c02002-08-22 20:52:17 +000011248/************************************************************************
11249 * *
11250 * Extra functions not pertaining to the XPath spec *
11251 * *
11252 ************************************************************************/
11253/**
11254 * xmlXPathEscapeUriFunction:
11255 * @ctxt: the XPath Parser context
11256 * @nargs: the number of arguments
11257 *
11258 * Implement the escape-uri() XPath function
11259 * string escape-uri(string $str, bool $escape-reserved)
11260 *
11261 * This function applies the URI escaping rules defined in section 2 of [RFC
11262 * 2396] to the string supplied as $uri-part, which typically represents all
11263 * or part of a URI. The effect of the function is to replace any special
11264 * character in the string by an escape sequence of the form %xx%yy...,
11265 * where xxyy... is the hexadecimal representation of the octets used to
11266 * represent the character in UTF-8.
11267 *
11268 * The set of characters that are escaped depends on the setting of the
11269 * boolean argument $escape-reserved.
11270 *
11271 * If $escape-reserved is true, all characters are escaped other than lower
11272 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11273 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11274 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11275 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11276 * A-F).
11277 *
11278 * If $escape-reserved is false, the behavior differs in that characters
11279 * referred to in [RFC 2396] as reserved characters are not escaped. These
11280 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11281 *
11282 * [RFC 2396] does not define whether escaped URIs should use lower case or
11283 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11284 * compared using string comparison functions, this function must always use
11285 * the upper-case letters A-F.
11286 *
11287 * Generally, $escape-reserved should be set to true when escaping a string
11288 * that is to form a single part of a URI, and to false when escaping an
11289 * entire URI or URI reference.
11290 *
11291 * In the case of non-ascii characters, the string is encoded according to
11292 * utf-8 and then converted according to RFC 2396.
11293 *
11294 * Examples
11295 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11296 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11297 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11298 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11299 *
11300 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011301static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011302xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11303 xmlXPathObjectPtr str;
11304 int escape_reserved;
11305 xmlBufferPtr target;
11306 xmlChar *cptr;
11307 xmlChar escape[4];
11308
11309 CHECK_ARITY(2);
11310
11311 escape_reserved = xmlXPathPopBoolean(ctxt);
11312
11313 CAST_TO_STRING;
11314 str = valuePop(ctxt);
11315
11316 target = xmlBufferCreate();
11317
11318 escape[0] = '%';
11319 escape[3] = 0;
11320
11321 if (target) {
11322 for (cptr = str->stringval; *cptr; cptr++) {
11323 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11324 (*cptr >= 'a' && *cptr <= 'z') ||
11325 (*cptr >= '0' && *cptr <= '9') ||
11326 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11327 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11328 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11329 (*cptr == '%' &&
11330 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11331 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11332 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11333 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11334 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11335 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11336 (!escape_reserved &&
11337 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11338 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11339 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11340 *cptr == ','))) {
11341 xmlBufferAdd(target, cptr, 1);
11342 } else {
11343 if ((*cptr >> 4) < 10)
11344 escape[1] = '0' + (*cptr >> 4);
11345 else
11346 escape[1] = 'A' - 10 + (*cptr >> 4);
11347 if ((*cptr & 0xF) < 10)
11348 escape[2] = '0' + (*cptr & 0xF);
11349 else
11350 escape[2] = 'A' - 10 + (*cptr & 0xF);
11351
11352 xmlBufferAdd(target, &escape[0], 3);
11353 }
11354 }
11355 }
11356 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11357 xmlBufferFree(target);
11358 xmlXPathFreeObject(str);
11359}
11360
Owen Taylor3473f882001-02-23 17:55:21 +000011361/**
11362 * xmlXPathRegisterAllFunctions:
11363 * @ctxt: the XPath context
11364 *
11365 * Registers all default XPath functions in this context
11366 */
11367void
11368xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11369{
11370 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11371 xmlXPathBooleanFunction);
11372 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11373 xmlXPathCeilingFunction);
11374 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11375 xmlXPathCountFunction);
11376 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11377 xmlXPathConcatFunction);
11378 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11379 xmlXPathContainsFunction);
11380 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11381 xmlXPathIdFunction);
11382 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11383 xmlXPathFalseFunction);
11384 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11385 xmlXPathFloorFunction);
11386 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11387 xmlXPathLastFunction);
11388 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11389 xmlXPathLangFunction);
11390 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11391 xmlXPathLocalNameFunction);
11392 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11393 xmlXPathNotFunction);
11394 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11395 xmlXPathNameFunction);
11396 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11397 xmlXPathNamespaceURIFunction);
11398 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11399 xmlXPathNormalizeFunction);
11400 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11401 xmlXPathNumberFunction);
11402 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11403 xmlXPathPositionFunction);
11404 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11405 xmlXPathRoundFunction);
11406 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11407 xmlXPathStringFunction);
11408 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11409 xmlXPathStringLengthFunction);
11410 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11411 xmlXPathStartsWithFunction);
11412 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11413 xmlXPathSubstringFunction);
11414 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11415 xmlXPathSubstringBeforeFunction);
11416 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11417 xmlXPathSubstringAfterFunction);
11418 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11419 xmlXPathSumFunction);
11420 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11421 xmlXPathTrueFunction);
11422 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11423 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011424
11425 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11426 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11427 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011428}
11429
11430#endif /* LIBXML_XPATH_ENABLED */