blob: 986673626275a091427e80d4389d8cbe08b68fdb [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
Daniel Veillard4432df22003-09-28 18:58:27 +000060#if defined(LIBXML_SCHEMAS_ENABLED) || defined(LIBXML_XPATH_ENABLED)
Daniel Veillard9e7160d2001-03-18 23:17:47 +000061/************************************************************************
62 * *
63 * Floating point stuff *
64 * *
65 ************************************************************************/
66
Daniel Veillardc0631a62001-09-20 13:56:06 +000067#ifndef TRIO_REPLACE_STDIO
Daniel Veillardcda96922001-08-21 10:56:31 +000068#define TRIO_PUBLIC static
Daniel Veillardc0631a62001-09-20 13:56:06 +000069#endif
Daniel Veillardcda96922001-08-21 10:56:31 +000070#include "trionan.c"
71
Owen Taylor3473f882001-02-23 17:55:21 +000072/*
Owen Taylor3473f882001-02-23 17:55:21 +000073 * The lack of portability of this section of the libc is annoying !
74 */
75double xmlXPathNAN = 0;
76double xmlXPathPINF = 1;
77double xmlXPathNINF = -1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +000078double xmlXPathNZERO = 0;
Daniel Veillard20ee8c02001-10-05 09:18:14 +000079static int xmlXPathInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +000080
Owen Taylor3473f882001-02-23 17:55:21 +000081/**
82 * xmlXPathInit:
83 *
84 * Initialize the XPath environment
85 */
86void
87xmlXPathInit(void) {
Daniel Veillard20ee8c02001-10-05 09:18:14 +000088 if (xmlXPathInitialized) return;
Owen Taylor3473f882001-02-23 17:55:21 +000089
Bjorn Reese45029602001-08-21 09:23:53 +000090 xmlXPathPINF = trio_pinf();
91 xmlXPathNINF = trio_ninf();
92 xmlXPathNAN = trio_nan();
Daniel Veillard5fc1f082002-03-27 09:05:40 +000093 xmlXPathNZERO = trio_nzero();
Owen Taylor3473f882001-02-23 17:55:21 +000094
Daniel Veillard20ee8c02001-10-05 09:18:14 +000095 xmlXPathInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +000096}
97
Daniel Veillardcda96922001-08-21 10:56:31 +000098/**
99 * xmlXPathIsNaN:
100 * @val: a double value
101 *
102 * Provides a portable isnan() function to detect whether a double
103 * is a NotaNumber. Based on trio code
104 * http://sourceforge.net/projects/ctrio/
105 *
106 * Returns 1 if the value is a NaN, 0 otherwise
107 */
108int
109xmlXPathIsNaN(double val) {
110 return(trio_isnan(val));
111}
112
113/**
114 * xmlXPathIsInf:
115 * @val: a double value
116 *
117 * Provides a portable isinf() function to detect whether a double
118 * is a +Infinite or -Infinite. Based on trio code
119 * http://sourceforge.net/projects/ctrio/
120 *
121 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
122 */
123int
124xmlXPathIsInf(double val) {
125 return(trio_isinf(val));
126}
127
Daniel Veillard4432df22003-09-28 18:58:27 +0000128#endif /* SCHEMAS or XPATH */
129#ifdef LIBXML_XPATH_ENABLED
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000130/**
131 * xmlXPathGetSign:
132 * @val: a double value
133 *
134 * Provides a portable function to detect the sign of a double
135 * Modified from trio code
136 * http://sourceforge.net/projects/ctrio/
137 *
138 * Returns 1 if the value is Negative, 0 if positive
139 */
Daniel Veillard21458c82002-03-27 16:12:22 +0000140static int
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000141xmlXPathGetSign(double val) {
Daniel Veillard21458c82002-03-27 16:12:22 +0000142 return(trio_signbit(val));
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000143}
144
145
Daniel Veillardd9d32ae2003-07-05 20:32:43 +0000146/*
147 * TODO: when compatibility allows remove all "fake node libxslt" strings
148 * the test should just be name[0] = ' '
149 */
150/* #define DEBUG */
151/* #define DEBUG_STEP */
152/* #define DEBUG_STEP_NTH */
153/* #define DEBUG_EXPR */
154/* #define DEBUG_EVAL_COUNTS */
155
156static xmlNs xmlXPathXMLNamespaceStruct = {
157 NULL,
158 XML_NAMESPACE_DECL,
159 XML_XML_NAMESPACE,
160 BAD_CAST "xml",
161 NULL
162};
163static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
164#ifndef LIBXML_THREAD_ENABLED
165/*
166 * Optimizer is disabled only when threaded apps are detected while
167 * the library ain't compiled for thread safety.
168 */
169static int xmlXPathDisableOptimizer = 0;
170#endif
171
Owen Taylor3473f882001-02-23 17:55:21 +0000172/************************************************************************
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000173 * *
174 * Error handling routines *
175 * *
176 ************************************************************************/
177
William M. Brack08171912003-12-29 02:52:11 +0000178/*
179 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
180 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000181static const char *xmlXPathErrorMessages[] = {
182 "Ok\n",
183 "Number encoding\n",
184 "Unfinished literal\n",
185 "Start of literal\n",
186 "Expected $ for variable reference\n",
187 "Undefined variable\n",
188 "Invalid predicate\n",
189 "Invalid expression\n",
190 "Missing closing curly brace\n",
191 "Unregistered function\n",
192 "Invalid operand\n",
193 "Invalid type\n",
194 "Invalid number of arguments\n",
195 "Invalid context size\n",
196 "Invalid context position\n",
197 "Memory allocation error\n",
198 "Syntax error\n",
199 "Resource error\n",
200 "Sub resource error\n",
201 "Undefined namespace prefix\n",
202 "Encoding error\n",
203 "Char out of XML range\n"
204};
205
206
207/**
208 * xmlXPathErrMemory:
209 * @ctxt: an XPath context
210 * @extra: extra informations
211 *
212 * Handle a redefinition of attribute error
213 */
214static void
215xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
216{
217 if (ctxt != NULL) {
218 if (extra) {
219 xmlChar buf[200];
220
221 xmlStrPrintf(buf, 200,
222 BAD_CAST "Memory allocation failed : %s\n",
223 extra);
224 ctxt->lastError.message = (char *) xmlStrdup(buf);
225 } else {
226 ctxt->lastError.message = (char *)
227 xmlStrdup(BAD_CAST "Memory allocation failed\n");
228 }
229 ctxt->lastError.domain = XML_FROM_XPATH;
230 ctxt->lastError.code = XML_ERR_NO_MEMORY;
231 if (ctxt->error != NULL)
232 ctxt->error(ctxt->userData, &ctxt->lastError);
233 } else {
234 if (extra)
Daniel Veillard659e71e2003-10-10 14:10:40 +0000235 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000236 NULL, NULL, XML_FROM_XPATH,
237 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
238 extra, NULL, NULL, 0, 0,
239 "Memory allocation failed : %s\n", extra);
240 else
Daniel Veillard659e71e2003-10-10 14:10:40 +0000241 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000242 NULL, NULL, XML_FROM_XPATH,
243 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
244 NULL, NULL, NULL, 0, 0,
245 "Memory allocation failed\n");
246 }
247}
248
249/**
250 * xmlXPathErrMemory:
251 * @ctxt: an XPath parser context
252 * @extra: extra informations
253 *
254 * Handle a redefinition of attribute error
255 */
256static void
257xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
258{
259 ctxt->error = XPATH_MEMORY_ERROR;
260 if (ctxt == NULL)
261 xmlXPathErrMemory(NULL, extra);
262 else
263 xmlXPathErrMemory(ctxt->context, extra);
264}
265
266/**
267 * xmlXPathErr:
268 * @ctxt: a XPath parser context
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000269 * @error: the error code
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000270 *
271 * Handle a Relax NG Parsing error
272 */
273void
274xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
275{
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000276 if (ctxt == NULL) {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000277 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000278 NULL, NULL, XML_FROM_XPATH,
279 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
280 XML_ERR_ERROR, NULL, 0,
281 NULL, NULL, NULL, 0, 0,
282 xmlXPathErrorMessages[error]);
283 return;
284 }
Daniel Veillardf88d8cf2003-12-08 10:25:02 +0000285 ctxt->error = error;
286 if (ctxt->context == NULL) {
287 __xmlRaiseError(NULL, NULL, NULL,
288 NULL, NULL, XML_FROM_XPATH,
289 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
290 XML_ERR_ERROR, NULL, 0,
291 (const char *) ctxt->base, NULL, NULL,
292 ctxt->cur - ctxt->base, 0,
293 xmlXPathErrorMessages[error]);
294 return;
295 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000296 ctxt->context->lastError.domain = XML_FROM_XPATH;
297 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
298 XPATH_EXPRESSION_OK;
Daniel Veillardfcf719c2003-10-10 11:42:17 +0000299 ctxt->context->lastError.level = XML_ERR_ERROR;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000300 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
301 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
302 ctxt->context->lastError.node = ctxt->context->debugNode;
303 if (ctxt->context->error != NULL) {
304 ctxt->context->error(ctxt->context->userData,
305 &ctxt->context->lastError);
306 } else {
Daniel Veillard659e71e2003-10-10 14:10:40 +0000307 __xmlRaiseError(NULL, NULL, NULL,
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000308 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
309 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
310 XML_ERR_ERROR, NULL, 0,
311 (const char *) ctxt->base, NULL, NULL,
312 ctxt->cur - ctxt->base, 0,
313 xmlXPathErrorMessages[error]);
314 }
315
316}
317
318/**
319 * xmlXPatherror:
320 * @ctxt: the XPath Parser context
321 * @file: the file name
322 * @line: the line number
323 * @no: the error number
324 *
325 * Formats an error message.
326 */
327void
328xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
329 int line ATTRIBUTE_UNUSED, int no) {
330 xmlXPathErr(ctxt, no);
331}
332
333
334/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000335 * *
336 * Parser Types *
337 * *
338 ************************************************************************/
339
340/*
341 * Types are private:
342 */
343
344typedef enum {
345 XPATH_OP_END=0,
346 XPATH_OP_AND,
347 XPATH_OP_OR,
348 XPATH_OP_EQUAL,
349 XPATH_OP_CMP,
350 XPATH_OP_PLUS,
351 XPATH_OP_MULT,
352 XPATH_OP_UNION,
353 XPATH_OP_ROOT,
354 XPATH_OP_NODE,
355 XPATH_OP_RESET,
356 XPATH_OP_COLLECT,
357 XPATH_OP_VALUE,
358 XPATH_OP_VARIABLE,
359 XPATH_OP_FUNCTION,
360 XPATH_OP_ARG,
361 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000362 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000363 XPATH_OP_SORT
364#ifdef LIBXML_XPTR_ENABLED
365 ,XPATH_OP_RANGETO
366#endif
367} xmlXPathOp;
368
369typedef enum {
370 AXIS_ANCESTOR = 1,
371 AXIS_ANCESTOR_OR_SELF,
372 AXIS_ATTRIBUTE,
373 AXIS_CHILD,
374 AXIS_DESCENDANT,
375 AXIS_DESCENDANT_OR_SELF,
376 AXIS_FOLLOWING,
377 AXIS_FOLLOWING_SIBLING,
378 AXIS_NAMESPACE,
379 AXIS_PARENT,
380 AXIS_PRECEDING,
381 AXIS_PRECEDING_SIBLING,
382 AXIS_SELF
383} xmlXPathAxisVal;
384
385typedef enum {
386 NODE_TEST_NONE = 0,
387 NODE_TEST_TYPE = 1,
388 NODE_TEST_PI = 2,
389 NODE_TEST_ALL = 3,
390 NODE_TEST_NS = 4,
391 NODE_TEST_NAME = 5
392} xmlXPathTestVal;
393
394typedef enum {
395 NODE_TYPE_NODE = 0,
396 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
397 NODE_TYPE_TEXT = XML_TEXT_NODE,
398 NODE_TYPE_PI = XML_PI_NODE
399} xmlXPathTypeVal;
400
401
402typedef struct _xmlXPathStepOp xmlXPathStepOp;
403typedef xmlXPathStepOp *xmlXPathStepOpPtr;
404struct _xmlXPathStepOp {
William M. Brack08171912003-12-29 02:52:11 +0000405 xmlXPathOp op; /* The identifier of the operation */
406 int ch1; /* First child */
407 int ch2; /* Second child */
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000408 int value;
409 int value2;
410 int value3;
411 void *value4;
412 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000413 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000414 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000415};
416
417struct _xmlXPathCompExpr {
William M. Brack08171912003-12-29 02:52:11 +0000418 int nbStep; /* Number of steps in this expression */
419 int maxStep; /* Maximum number of steps allocated */
420 xmlXPathStepOp *steps; /* ops for computation of this expression */
421 int last; /* index of last step in expression */
422 xmlChar *expr; /* the expression being computed */
Daniel Veillard4773df22004-01-23 13:15:13 +0000423 xmlDictPtr dict; /* the dictionnary to use if any */
Daniel Veillardf06307e2001-07-03 10:35:50 +0000424#ifdef DEBUG_EVAL_COUNTS
425 int nb;
426 xmlChar *string;
427#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000428};
429
430/************************************************************************
431 * *
432 * Parser Type functions *
433 * *
434 ************************************************************************/
435
436/**
437 * xmlXPathNewCompExpr:
438 *
439 * Create a new Xpath component
440 *
441 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
442 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000444xmlXPathNewCompExpr(void) {
445 xmlXPathCompExprPtr cur;
446
447 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
448 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000449 xmlXPathErrMemory(NULL, "allocating component\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000450 return(NULL);
451 }
452 memset(cur, 0, sizeof(xmlXPathCompExpr));
453 cur->maxStep = 10;
454 cur->nbStep = 0;
455 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
456 sizeof(xmlXPathStepOp));
457 if (cur->steps == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000458 xmlXPathErrMemory(NULL, "allocating steps\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000459 xmlFree(cur);
460 return(NULL);
461 }
462 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
463 cur->last = -1;
Daniel Veillardf06307e2001-07-03 10:35:50 +0000464#ifdef DEBUG_EVAL_COUNTS
465 cur->nb = 0;
466#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000467 return(cur);
468}
469
470/**
471 * xmlXPathFreeCompExpr:
472 * @comp: an XPATH comp
473 *
474 * Free up the memory allocated by @comp
475 */
476void
Daniel Veillardf06307e2001-07-03 10:35:50 +0000477xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
478{
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000479 xmlXPathStepOpPtr op;
480 int i;
481
482 if (comp == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +0000483 return;
Daniel Veillard4773df22004-01-23 13:15:13 +0000484 if (comp->dict == NULL) {
485 for (i = 0; i < comp->nbStep; i++) {
486 op = &comp->steps[i];
487 if (op->value4 != NULL) {
488 if (op->op == XPATH_OP_VALUE)
489 xmlXPathFreeObject(op->value4);
490 else
491 xmlFree(op->value4);
492 }
493 if (op->value5 != NULL)
494 xmlFree(op->value5);
495 }
496 } else {
497 for (i = 0; i < comp->nbStep; i++) {
498 op = &comp->steps[i];
499 if (op->value4 != NULL) {
500 if (op->op == XPATH_OP_VALUE)
501 xmlXPathFreeObject(op->value4);
502 }
503 }
504 xmlDictFree(comp->dict);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000505 }
506 if (comp->steps != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +0000507 xmlFree(comp->steps);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000508 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000509#ifdef DEBUG_EVAL_COUNTS
510 if (comp->string != NULL) {
511 xmlFree(comp->string);
512 }
513#endif
Daniel Veillard118aed72002-09-24 14:13:13 +0000514 if (comp->expr != NULL) {
515 xmlFree(comp->expr);
516 }
Daniel Veillardf06307e2001-07-03 10:35:50 +0000517
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000518 xmlFree(comp);
519}
520
521/**
522 * xmlXPathCompExprAdd:
523 * @comp: the compiled expression
524 * @ch1: first child index
525 * @ch2: second child index
526 * @op: an op
527 * @value: the first int value
528 * @value2: the second int value
529 * @value3: the third int value
530 * @value4: the first string value
531 * @value5: the second string value
532 *
William M. Brack08171912003-12-29 02:52:11 +0000533 * Add a step to an XPath Compiled Expression
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000534 *
535 * Returns -1 in case of failure, the index otherwise
536 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000537static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000538xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
539 xmlXPathOp op, int value,
540 int value2, int value3, void *value4, void *value5) {
541 if (comp->nbStep >= comp->maxStep) {
542 xmlXPathStepOp *real;
543
544 comp->maxStep *= 2;
545 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
546 comp->maxStep * sizeof(xmlXPathStepOp));
547 if (real == NULL) {
548 comp->maxStep /= 2;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000549 xmlXPathErrMemory(NULL, "adding step\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000550 return(-1);
551 }
552 comp->steps = real;
553 }
554 comp->last = comp->nbStep;
555 comp->steps[comp->nbStep].ch1 = ch1;
556 comp->steps[comp->nbStep].ch2 = ch2;
557 comp->steps[comp->nbStep].op = op;
558 comp->steps[comp->nbStep].value = value;
559 comp->steps[comp->nbStep].value2 = value2;
560 comp->steps[comp->nbStep].value3 = value3;
Daniel Veillard4773df22004-01-23 13:15:13 +0000561 if ((comp->dict != NULL) &&
562 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
563 (op == XPATH_OP_COLLECT))) {
564 if (value4 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000565 comp->steps[comp->nbStep].value4 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000566 (void *)xmlDictLookup(comp->dict, value4, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000567 xmlFree(value4);
568 } else
569 comp->steps[comp->nbStep].value4 = NULL;
570 if (value5 != NULL) {
Daniel Veillardb3377952004-02-09 12:48:55 +0000571 comp->steps[comp->nbStep].value5 = (xmlChar *)
William M. Brackc07ed5e2004-01-30 07:52:48 +0000572 (void *)xmlDictLookup(comp->dict, value5, -1);
Daniel Veillard4773df22004-01-23 13:15:13 +0000573 xmlFree(value5);
574 } else
575 comp->steps[comp->nbStep].value5 = NULL;
576 } else {
577 comp->steps[comp->nbStep].value4 = value4;
578 comp->steps[comp->nbStep].value5 = value5;
579 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000580 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000581 return(comp->nbStep++);
582}
583
Daniel Veillardf06307e2001-07-03 10:35:50 +0000584/**
585 * xmlXPathCompSwap:
586 * @comp: the compiled expression
587 * @op: operation index
588 *
589 * Swaps 2 operations in the compiled expression
Daniel Veillardf06307e2001-07-03 10:35:50 +0000590 */
591static void
592xmlXPathCompSwap(xmlXPathStepOpPtr op) {
593 int tmp;
594
Daniel Veillardbc6f7592002-04-16 07:49:59 +0000595#ifndef LIBXML_THREAD_ENABLED
Daniel Veillard81463942001-10-16 12:34:39 +0000596 /*
597 * Since this manipulates possibly shared variables, this is
William M. Brack08171912003-12-29 02:52:11 +0000598 * disabled if one detects that the library is used in a multithreaded
Daniel Veillard81463942001-10-16 12:34:39 +0000599 * application
600 */
601 if (xmlXPathDisableOptimizer)
602 return;
603#endif
604
Daniel Veillardf06307e2001-07-03 10:35:50 +0000605 tmp = op->ch1;
606 op->ch1 = op->ch2;
607 op->ch2 = tmp;
608}
609
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000610#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
611 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
612 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000613#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
614 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
615 (op), (val), (val2), (val3), (val4), (val5))
616
617#define PUSH_LEAVE_EXPR(op, val, val2) \
618xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
619
620#define PUSH_UNARY_EXPR(op, ch, val, val2) \
621xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
622
623#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
William M. Brack08171912003-12-29 02:52:11 +0000624xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
625 (val), (val2), 0 ,NULL ,NULL)
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000626
627/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000628 * *
629 * Debugging related functions *
630 * *
631 ************************************************************************/
632
Owen Taylor3473f882001-02-23 17:55:21 +0000633#define STRANGE \
634 xmlGenericError(xmlGenericErrorContext, \
635 "Internal error at %s:%d\n", \
636 __FILE__, __LINE__);
637
638#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000639static void
640xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000641 int i;
642 char shift[100];
643
644 for (i = 0;((i < depth) && (i < 25));i++)
645 shift[2 * i] = shift[2 * i + 1] = ' ';
646 shift[2 * i] = shift[2 * i + 1] = 0;
647 if (cur == NULL) {
648 fprintf(output, shift);
649 fprintf(output, "Node is NULL !\n");
650 return;
651
652 }
653
654 if ((cur->type == XML_DOCUMENT_NODE) ||
655 (cur->type == XML_HTML_DOCUMENT_NODE)) {
656 fprintf(output, shift);
657 fprintf(output, " /\n");
658 } else if (cur->type == XML_ATTRIBUTE_NODE)
659 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
660 else
661 xmlDebugDumpOneNode(output, cur, depth);
662}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000663static void
664xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000665 xmlNodePtr tmp;
666 int i;
667 char shift[100];
668
669 for (i = 0;((i < depth) && (i < 25));i++)
670 shift[2 * i] = shift[2 * i + 1] = ' ';
671 shift[2 * i] = shift[2 * i + 1] = 0;
672 if (cur == NULL) {
673 fprintf(output, shift);
674 fprintf(output, "Node is NULL !\n");
675 return;
676
677 }
678
679 while (cur != NULL) {
680 tmp = cur;
681 cur = cur->next;
682 xmlDebugDumpOneNode(output, tmp, depth);
683 }
684}
Owen Taylor3473f882001-02-23 17:55:21 +0000685
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000686static void
687xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000688 int i;
689 char shift[100];
690
691 for (i = 0;((i < depth) && (i < 25));i++)
692 shift[2 * i] = shift[2 * i + 1] = ' ';
693 shift[2 * i] = shift[2 * i + 1] = 0;
694
695 if (cur == NULL) {
696 fprintf(output, shift);
697 fprintf(output, "NodeSet is NULL !\n");
698 return;
699
700 }
701
Daniel Veillard911f49a2001-04-07 15:39:35 +0000702 if (cur != NULL) {
703 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
704 for (i = 0;i < cur->nodeNr;i++) {
705 fprintf(output, shift);
706 fprintf(output, "%d", i + 1);
707 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
708 }
Owen Taylor3473f882001-02-23 17:55:21 +0000709 }
710}
711
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000712static void
713xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000714 int i;
715 char shift[100];
716
717 for (i = 0;((i < depth) && (i < 25));i++)
718 shift[2 * i] = shift[2 * i + 1] = ' ';
719 shift[2 * i] = shift[2 * i + 1] = 0;
720
721 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
722 fprintf(output, shift);
723 fprintf(output, "Value Tree is NULL !\n");
724 return;
725
726 }
727
728 fprintf(output, shift);
729 fprintf(output, "%d", i + 1);
730 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
731}
Owen Taylor3473f882001-02-23 17:55:21 +0000732#if defined(LIBXML_XPTR_ENABLED)
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000733static void
734xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000735 int i;
736 char shift[100];
737
738 for (i = 0;((i < depth) && (i < 25));i++)
739 shift[2 * i] = shift[2 * i + 1] = ' ';
740 shift[2 * i] = shift[2 * i + 1] = 0;
741
742 if (cur == NULL) {
743 fprintf(output, shift);
744 fprintf(output, "LocationSet is NULL !\n");
745 return;
746
747 }
748
749 for (i = 0;i < cur->locNr;i++) {
750 fprintf(output, shift);
751 fprintf(output, "%d : ", i + 1);
752 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
753 }
754}
Daniel Veillard017b1082001-06-21 11:20:21 +0000755#endif /* LIBXML_XPTR_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000756
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000757/**
758 * xmlXPathDebugDumpObject:
759 * @output: the FILE * to dump the output
760 * @cur: the object to inspect
761 * @depth: indentation level
762 *
763 * Dump the content of the object for debugging purposes
764 */
765void
766xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000767 int i;
768 char shift[100];
769
770 for (i = 0;((i < depth) && (i < 25));i++)
771 shift[2 * i] = shift[2 * i + 1] = ' ';
772 shift[2 * i] = shift[2 * i + 1] = 0;
773
774 fprintf(output, shift);
775
776 if (cur == NULL) {
777 fprintf(output, "Object is empty (NULL)\n");
778 return;
779 }
780 switch(cur->type) {
781 case XPATH_UNDEFINED:
782 fprintf(output, "Object is uninitialized\n");
783 break;
784 case XPATH_NODESET:
785 fprintf(output, "Object is a Node Set :\n");
786 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
787 break;
788 case XPATH_XSLT_TREE:
789 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000790 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000791 break;
792 case XPATH_BOOLEAN:
793 fprintf(output, "Object is a Boolean : ");
794 if (cur->boolval) fprintf(output, "true\n");
795 else fprintf(output, "false\n");
796 break;
797 case XPATH_NUMBER:
Daniel Veillardcda96922001-08-21 10:56:31 +0000798 switch (xmlXPathIsInf(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000799 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +0000800 fprintf(output, "Object is a number : Infinity\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000801 break;
802 case -1:
803 fprintf(output, "Object is a number : -Infinity\n");
804 break;
805 default:
Daniel Veillardcda96922001-08-21 10:56:31 +0000806 if (xmlXPathIsNaN(cur->floatval)) {
Daniel Veillard357c9602001-05-03 10:49:20 +0000807 fprintf(output, "Object is a number : NaN\n");
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000808 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
809 fprintf(output, "Object is a number : 0\n");
Daniel Veillard357c9602001-05-03 10:49:20 +0000810 } else {
811 fprintf(output, "Object is a number : %0g\n", cur->floatval);
812 }
813 }
Owen Taylor3473f882001-02-23 17:55:21 +0000814 break;
815 case XPATH_STRING:
816 fprintf(output, "Object is a string : ");
817 xmlDebugDumpString(output, cur->stringval);
818 fprintf(output, "\n");
819 break;
820 case XPATH_POINT:
821 fprintf(output, "Object is a point : index %d in node", cur->index);
822 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
823 fprintf(output, "\n");
824 break;
825 case XPATH_RANGE:
826 if ((cur->user2 == NULL) ||
827 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
828 fprintf(output, "Object is a collapsed range :\n");
829 fprintf(output, shift);
830 if (cur->index >= 0)
831 fprintf(output, "index %d in ", cur->index);
832 fprintf(output, "node\n");
833 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
834 depth + 1);
835 } else {
836 fprintf(output, "Object is a range :\n");
837 fprintf(output, shift);
838 fprintf(output, "From ");
839 if (cur->index >= 0)
840 fprintf(output, "index %d in ", cur->index);
841 fprintf(output, "node\n");
842 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
843 depth + 1);
844 fprintf(output, shift);
845 fprintf(output, "To ");
846 if (cur->index2 >= 0)
847 fprintf(output, "index %d in ", cur->index2);
848 fprintf(output, "node\n");
849 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
850 depth + 1);
851 fprintf(output, "\n");
852 }
853 break;
854 case XPATH_LOCATIONSET:
855#if defined(LIBXML_XPTR_ENABLED)
856 fprintf(output, "Object is a Location Set:\n");
857 xmlXPathDebugDumpLocationSet(output,
858 (xmlLocationSetPtr) cur->user, depth);
859#endif
860 break;
861 case XPATH_USERS:
862 fprintf(output, "Object is user defined\n");
863 break;
864 }
865}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000866
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000867static void
868xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000869 xmlXPathStepOpPtr op, int depth) {
870 int i;
871 char shift[100];
872
873 for (i = 0;((i < depth) && (i < 25));i++)
874 shift[2 * i] = shift[2 * i + 1] = ' ';
875 shift[2 * i] = shift[2 * i + 1] = 0;
876
877 fprintf(output, shift);
878 if (op == NULL) {
879 fprintf(output, "Step is NULL\n");
880 return;
881 }
882 switch (op->op) {
883 case XPATH_OP_END:
884 fprintf(output, "END"); break;
885 case XPATH_OP_AND:
886 fprintf(output, "AND"); break;
887 case XPATH_OP_OR:
888 fprintf(output, "OR"); break;
889 case XPATH_OP_EQUAL:
890 if (op->value)
891 fprintf(output, "EQUAL =");
892 else
893 fprintf(output, "EQUAL !=");
894 break;
895 case XPATH_OP_CMP:
896 if (op->value)
897 fprintf(output, "CMP <");
898 else
899 fprintf(output, "CMP >");
900 if (!op->value2)
901 fprintf(output, "=");
902 break;
903 case XPATH_OP_PLUS:
904 if (op->value == 0)
905 fprintf(output, "PLUS -");
906 else if (op->value == 1)
907 fprintf(output, "PLUS +");
908 else if (op->value == 2)
909 fprintf(output, "PLUS unary -");
910 else if (op->value == 3)
911 fprintf(output, "PLUS unary - -");
912 break;
913 case XPATH_OP_MULT:
914 if (op->value == 0)
915 fprintf(output, "MULT *");
916 else if (op->value == 1)
917 fprintf(output, "MULT div");
918 else
919 fprintf(output, "MULT mod");
920 break;
921 case XPATH_OP_UNION:
922 fprintf(output, "UNION"); break;
923 case XPATH_OP_ROOT:
924 fprintf(output, "ROOT"); break;
925 case XPATH_OP_NODE:
926 fprintf(output, "NODE"); break;
927 case XPATH_OP_RESET:
928 fprintf(output, "RESET"); break;
929 case XPATH_OP_SORT:
930 fprintf(output, "SORT"); break;
931 case XPATH_OP_COLLECT: {
William M. Brack78637da2003-07-31 14:47:38 +0000932 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
933 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
934 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000935 const xmlChar *prefix = op->value4;
936 const xmlChar *name = op->value5;
937
938 fprintf(output, "COLLECT ");
939 switch (axis) {
940 case AXIS_ANCESTOR:
941 fprintf(output, " 'ancestors' "); break;
942 case AXIS_ANCESTOR_OR_SELF:
943 fprintf(output, " 'ancestors-or-self' "); break;
944 case AXIS_ATTRIBUTE:
945 fprintf(output, " 'attributes' "); break;
946 case AXIS_CHILD:
947 fprintf(output, " 'child' "); break;
948 case AXIS_DESCENDANT:
949 fprintf(output, " 'descendant' "); break;
950 case AXIS_DESCENDANT_OR_SELF:
951 fprintf(output, " 'descendant-or-self' "); break;
952 case AXIS_FOLLOWING:
953 fprintf(output, " 'following' "); break;
954 case AXIS_FOLLOWING_SIBLING:
955 fprintf(output, " 'following-siblings' "); break;
956 case AXIS_NAMESPACE:
957 fprintf(output, " 'namespace' "); break;
958 case AXIS_PARENT:
959 fprintf(output, " 'parent' "); break;
960 case AXIS_PRECEDING:
961 fprintf(output, " 'preceding' "); break;
962 case AXIS_PRECEDING_SIBLING:
963 fprintf(output, " 'preceding-sibling' "); break;
964 case AXIS_SELF:
965 fprintf(output, " 'self' "); break;
966 }
967 switch (test) {
968 case NODE_TEST_NONE:
969 fprintf(output, "'none' "); break;
970 case NODE_TEST_TYPE:
971 fprintf(output, "'type' "); break;
972 case NODE_TEST_PI:
973 fprintf(output, "'PI' "); break;
974 case NODE_TEST_ALL:
975 fprintf(output, "'all' "); break;
976 case NODE_TEST_NS:
977 fprintf(output, "'namespace' "); break;
978 case NODE_TEST_NAME:
979 fprintf(output, "'name' "); break;
980 }
981 switch (type) {
982 case NODE_TYPE_NODE:
983 fprintf(output, "'node' "); break;
984 case NODE_TYPE_COMMENT:
985 fprintf(output, "'comment' "); break;
986 case NODE_TYPE_TEXT:
987 fprintf(output, "'text' "); break;
988 case NODE_TYPE_PI:
989 fprintf(output, "'PI' "); break;
990 }
991 if (prefix != NULL)
992 fprintf(output, "%s:", prefix);
993 if (name != NULL)
Daniel Veillard580ced82003-03-21 21:22:48 +0000994 fprintf(output, "%s", (const char *) name);
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000995 break;
996
997 }
998 case XPATH_OP_VALUE: {
999 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1000
1001 fprintf(output, "ELEM ");
1002 xmlXPathDebugDumpObject(output, object, 0);
1003 goto finish;
1004 }
1005 case XPATH_OP_VARIABLE: {
1006 const xmlChar *prefix = op->value5;
1007 const xmlChar *name = op->value4;
1008
1009 if (prefix != NULL)
1010 fprintf(output, "VARIABLE %s:%s", prefix, name);
1011 else
1012 fprintf(output, "VARIABLE %s", name);
1013 break;
1014 }
1015 case XPATH_OP_FUNCTION: {
1016 int nbargs = op->value;
1017 const xmlChar *prefix = op->value5;
1018 const xmlChar *name = op->value4;
1019
1020 if (prefix != NULL)
1021 fprintf(output, "FUNCTION %s:%s(%d args)",
1022 prefix, name, nbargs);
1023 else
1024 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1025 break;
1026 }
1027 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1028 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001029 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00001030#ifdef LIBXML_XPTR_ENABLED
1031 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1032#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001033 default:
1034 fprintf(output, "UNKNOWN %d\n", op->op); return;
1035 }
1036 fprintf(output, "\n");
1037finish:
1038 if (op->ch1 >= 0)
1039 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1040 if (op->ch2 >= 0)
1041 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1042}
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001043
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001044/**
1045 * xmlXPathDebugDumpCompExpr:
1046 * @output: the FILE * for the output
1047 * @comp: the precompiled XPath expression
1048 * @depth: the indentation level.
1049 *
1050 * Dumps the tree of the compiled XPath expression.
1051 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001052void
1053xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1054 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00001055 int i;
1056 char shift[100];
1057
1058 for (i = 0;((i < depth) && (i < 25));i++)
1059 shift[2 * i] = shift[2 * i + 1] = ' ';
1060 shift[2 * i] = shift[2 * i + 1] = 0;
1061
1062 fprintf(output, shift);
1063
1064 if (comp == NULL) {
1065 fprintf(output, "Compiled Expression is NULL\n");
1066 return;
1067 }
1068 fprintf(output, "Compiled Expression : %d elements\n",
1069 comp->nbStep);
1070 i = comp->last;
1071 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1072}
Daniel Veillard017b1082001-06-21 11:20:21 +00001073#endif /* LIBXML_DEBUG_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001074
1075/************************************************************************
1076 * *
1077 * Parser stacks related functions and macros *
1078 * *
1079 ************************************************************************/
1080
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001081/**
1082 * valuePop:
1083 * @ctxt: an XPath evaluation context
1084 *
1085 * Pops the top XPath object from the value stack
1086 *
1087 * Returns the XPath object just removed
1088 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001089extern xmlXPathObjectPtr
1090valuePop(xmlXPathParserContextPtr ctxt)
1091{
1092 xmlXPathObjectPtr ret;
1093
1094 if (ctxt->valueNr <= 0)
1095 return (0);
1096 ctxt->valueNr--;
1097 if (ctxt->valueNr > 0)
1098 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1099 else
1100 ctxt->value = NULL;
1101 ret = ctxt->valueTab[ctxt->valueNr];
1102 ctxt->valueTab[ctxt->valueNr] = 0;
1103 return (ret);
1104}
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001105/**
1106 * valuePush:
1107 * @ctxt: an XPath evaluation context
1108 * @value: the XPath object
1109 *
1110 * Pushes a new XPath object on top of the value stack
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001111 *
1112 * returns the number of items on the value stack
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001113 */
Daniel Veillard1c732d22002-11-30 11:22:59 +00001114extern int
1115valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1116{
1117 if (ctxt->valueNr >= ctxt->valueMax) {
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001118 xmlXPathObjectPtr *tmp;
1119
1120 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1121 2 * ctxt->valueMax *
Daniel Veillard1c732d22002-11-30 11:22:59 +00001122 sizeof(ctxt->valueTab[0]));
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001123 if (tmp == NULL) {
Daniel Veillard1c732d22002-11-30 11:22:59 +00001124 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1125 return (0);
1126 }
Daniel Veillarda918b5b2004-09-26 14:25:37 +00001127 ctxt->valueMax *= 2;
1128 ctxt->valueTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +00001129 }
1130 ctxt->valueTab[ctxt->valueNr] = value;
1131 ctxt->value = value;
1132 return (ctxt->valueNr++);
1133}
Owen Taylor3473f882001-02-23 17:55:21 +00001134
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001135/**
1136 * xmlXPathPopBoolean:
1137 * @ctxt: an XPath parser context
1138 *
1139 * Pops a boolean from the stack, handling conversion if needed.
1140 * Check error with #xmlXPathCheckError.
1141 *
1142 * Returns the boolean
1143 */
1144int
1145xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
1146 xmlXPathObjectPtr obj;
1147 int ret;
1148
1149 obj = valuePop(ctxt);
1150 if (obj == NULL) {
1151 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1152 return(0);
1153 }
William M. Brack08171912003-12-29 02:52:11 +00001154 if (obj->type != XPATH_BOOLEAN)
1155 ret = xmlXPathCastToBoolean(obj);
1156 else
1157 ret = obj->boolval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001158 xmlXPathFreeObject(obj);
1159 return(ret);
1160}
1161
1162/**
1163 * xmlXPathPopNumber:
1164 * @ctxt: an XPath parser context
1165 *
1166 * Pops a number from the stack, handling conversion if needed.
1167 * Check error with #xmlXPathCheckError.
1168 *
1169 * Returns the number
1170 */
1171double
1172xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
1173 xmlXPathObjectPtr obj;
1174 double ret;
1175
1176 obj = valuePop(ctxt);
1177 if (obj == NULL) {
1178 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1179 return(0);
1180 }
William M. Brack08171912003-12-29 02:52:11 +00001181 if (obj->type != XPATH_NUMBER)
1182 ret = xmlXPathCastToNumber(obj);
1183 else
1184 ret = obj->floatval;
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001185 xmlXPathFreeObject(obj);
1186 return(ret);
1187}
1188
1189/**
1190 * xmlXPathPopString:
1191 * @ctxt: an XPath parser context
1192 *
1193 * Pops a string from the stack, handling conversion if needed.
1194 * Check error with #xmlXPathCheckError.
1195 *
1196 * Returns the string
1197 */
1198xmlChar *
1199xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1200 xmlXPathObjectPtr obj;
1201 xmlChar * ret;
1202
1203 obj = valuePop(ctxt);
1204 if (obj == NULL) {
1205 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1206 return(NULL);
1207 }
William M. Brack08171912003-12-29 02:52:11 +00001208 ret = xmlXPathCastToString(obj); /* this does required strdup */
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001209 /* TODO: needs refactoring somewhere else */
1210 if (obj->stringval == ret)
1211 obj->stringval = NULL;
1212 xmlXPathFreeObject(obj);
1213 return(ret);
1214}
1215
1216/**
1217 * xmlXPathPopNodeSet:
1218 * @ctxt: an XPath parser context
1219 *
1220 * Pops a node-set from the stack, handling conversion if needed.
1221 * Check error with #xmlXPathCheckError.
1222 *
1223 * Returns the node-set
1224 */
1225xmlNodeSetPtr
1226xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1227 xmlXPathObjectPtr obj;
1228 xmlNodeSetPtr ret;
1229
1230 if (ctxt->value == NULL) {
1231 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1232 return(NULL);
1233 }
1234 if (!xmlXPathStackIsNodeSet(ctxt)) {
1235 xmlXPathSetTypeError(ctxt);
1236 return(NULL);
1237 }
1238 obj = valuePop(ctxt);
1239 ret = obj->nodesetval;
William M. Bracke9449c52004-07-11 14:41:20 +00001240#if 0
Daniel Veillard9deb2422003-07-28 20:40:59 +00001241 /* to fix memory leak of not clearing obj->user */
1242 if (obj->boolval && obj->user != NULL)
1243 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00001244#endif
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001245 xmlXPathFreeNodeSetList(obj);
1246 return(ret);
1247}
1248
1249/**
1250 * xmlXPathPopExternal:
1251 * @ctxt: an XPath parser context
1252 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001253 * Pops an external object from the stack, handling conversion if needed.
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001254 * Check error with #xmlXPathCheckError.
1255 *
1256 * Returns the object
1257 */
1258void *
1259xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1260 xmlXPathObjectPtr obj;
1261 void * ret;
1262
1263 if (ctxt->value == NULL) {
1264 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1265 return(NULL);
1266 }
1267 if (ctxt->value->type != XPATH_USERS) {
1268 xmlXPathSetTypeError(ctxt);
1269 return(NULL);
1270 }
1271 obj = valuePop(ctxt);
1272 ret = obj->user;
1273 xmlXPathFreeObject(obj);
1274 return(ret);
1275}
1276
Owen Taylor3473f882001-02-23 17:55:21 +00001277/*
1278 * Macros for accessing the content. Those should be used only by the parser,
1279 * and not exported.
1280 *
1281 * Dirty macros, i.e. one need to make assumption on the context to use them
1282 *
1283 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1284 * CUR returns the current xmlChar value, i.e. a 8 bit value
1285 * in ISO-Latin or UTF-8.
1286 * This should be used internally by the parser
1287 * only to compare to ASCII values otherwise it would break when
1288 * running with UTF-8 encoding.
1289 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1290 * to compare on ASCII based substring.
1291 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1292 * strings within the parser.
1293 * CURRENT Returns the current char value, with the full decoding of
1294 * UTF-8 if we are using this mode. It returns an int.
1295 * NEXT Skip to the next character, this does the proper decoding
1296 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1297 * It returns the pointer to the current xmlChar.
1298 */
1299
1300#define CUR (*ctxt->cur)
1301#define SKIP(val) ctxt->cur += (val)
1302#define NXT(val) ctxt->cur[(val)]
1303#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +00001304#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1305
1306#define COPY_BUF(l,b,i,v) \
1307 if (l == 1) b[i++] = (xmlChar) v; \
1308 else i += xmlCopyChar(l,&b[i],v)
1309
1310#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +00001311
1312#define SKIP_BLANKS \
William M. Brack76e95df2003-10-18 16:20:14 +00001313 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
Owen Taylor3473f882001-02-23 17:55:21 +00001314
1315#define CURRENT (*ctxt->cur)
1316#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1317
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001318
1319#ifndef DBL_DIG
1320#define DBL_DIG 16
1321#endif
1322#ifndef DBL_EPSILON
1323#define DBL_EPSILON 1E-9
1324#endif
1325
1326#define UPPER_DOUBLE 1E9
1327#define LOWER_DOUBLE 1E-5
1328
1329#define INTEGER_DIGITS DBL_DIG
1330#define FRACTION_DIGITS (DBL_DIG + 1)
1331#define EXPONENT_DIGITS (3 + 2)
1332
1333/**
1334 * xmlXPathFormatNumber:
1335 * @number: number to format
1336 * @buffer: output buffer
1337 * @buffersize: size of output buffer
1338 *
1339 * Convert the number into a string representation.
1340 */
1341static void
1342xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1343{
Daniel Veillardcda96922001-08-21 10:56:31 +00001344 switch (xmlXPathIsInf(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001345 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00001346 if (buffersize > (int)sizeof("Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001347 snprintf(buffer, buffersize, "Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001348 break;
1349 case -1:
1350 if (buffersize > (int)sizeof("-Infinity"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001351 snprintf(buffer, buffersize, "-Infinity");
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001352 break;
1353 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00001354 if (xmlXPathIsNaN(number)) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001355 if (buffersize > (int)sizeof("NaN"))
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001356 snprintf(buffer, buffersize, "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00001357 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001358 snprintf(buffer, buffersize, "0");
Daniel Veillard28cac6b2002-03-19 11:25:30 +00001359 } else if (number == ((int) number)) {
1360 char work[30];
1361 char *ptr, *cur;
1362 int res, value = (int) number;
1363
1364 ptr = &buffer[0];
1365 if (value < 0) {
1366 *ptr++ = '-';
1367 value = -value;
1368 }
1369 if (value == 0) {
1370 *ptr++ = '0';
1371 } else {
1372 cur = &work[0];
1373 while (value != 0) {
1374 res = value % 10;
1375 value = value / 10;
1376 *cur++ = '0' + res;
1377 }
1378 cur--;
1379 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1380 *ptr++ = *cur--;
1381 }
1382 }
1383 if (ptr - buffer < buffersize) {
1384 *ptr = 0;
1385 } else if (buffersize > 0) {
1386 ptr--;
1387 *ptr = 0;
1388 }
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001389 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +00001390 /* 3 is sign, decimal point, and terminating zero */
1391 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1392 int integer_place, fraction_place;
1393 char *ptr;
1394 char *after_fraction;
1395 double absolute_value;
1396 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001397
Bjorn Reese70a9da52001-04-21 16:57:29 +00001398 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001399
Bjorn Reese70a9da52001-04-21 16:57:29 +00001400 /*
1401 * First choose format - scientific or regular floating point.
1402 * In either case, result is in work, and after_fraction points
1403 * just past the fractional part.
1404 */
1405 if ( ((absolute_value > UPPER_DOUBLE) ||
1406 (absolute_value < LOWER_DOUBLE)) &&
1407 (absolute_value != 0.0) ) {
1408 /* Use scientific notation */
1409 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1410 fraction_place = DBL_DIG - 1;
1411 snprintf(work, sizeof(work),"%*.*e",
1412 integer_place, fraction_place, number);
1413 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001414 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001415 else {
1416 /* Use regular notation */
Daniel Veillard56f06462001-06-24 21:34:03 +00001417 if (absolute_value > 0.0)
1418 integer_place = 1 + (int)log10(absolute_value);
1419 else
Daniel Veillarda3067d12001-06-24 21:39:39 +00001420 integer_place = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00001421 fraction_place = (integer_place > 0)
1422 ? DBL_DIG - integer_place
1423 : DBL_DIG;
1424 size = snprintf(work, sizeof(work), "%0.*f",
1425 fraction_place, number);
1426 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001427 }
1428
Bjorn Reese70a9da52001-04-21 16:57:29 +00001429 /* Remove fractional trailing zeroes */
1430 ptr = after_fraction;
1431 while (*(--ptr) == '0')
1432 ;
1433 if (*ptr != '.')
1434 ptr++;
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001435 while ((*ptr++ = *after_fraction++) != 0);
Bjorn Reese70a9da52001-04-21 16:57:29 +00001436
1437 /* Finally copy result back to caller */
1438 size = strlen(work) + 1;
1439 if (size > buffersize) {
1440 work[buffersize - 1] = 0;
1441 size = buffersize;
1442 }
Daniel Veillard5dd3c962003-09-12 15:32:16 +00001443 memmove(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001444 }
1445 break;
1446 }
1447}
1448
Owen Taylor3473f882001-02-23 17:55:21 +00001449
1450/************************************************************************
1451 * *
1452 * Routines to handle NodeSets *
1453 * *
1454 ************************************************************************/
1455
1456/**
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001457 * xmlXPathOrderDocElems:
1458 * @doc: an input document
1459 *
1460 * Call this routine to speed up XPath computation on static documents.
1461 * This stamps all the element nodes with the document order
1462 * Like for line information, the order is kept in the element->content
William M. Brack08171912003-12-29 02:52:11 +00001463 * field, the value stored is actually - the node number (starting at -1)
1464 * to be able to differentiate from line numbers.
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001465 *
William M. Brack08171912003-12-29 02:52:11 +00001466 * Returns the number of elements found in the document or -1 in case
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001467 * of error.
1468 */
1469long
1470xmlXPathOrderDocElems(xmlDocPtr doc) {
1471 long count = 0;
1472 xmlNodePtr cur;
1473
1474 if (doc == NULL)
1475 return(-1);
1476 cur = doc->children;
1477 while (cur != NULL) {
1478 if (cur->type == XML_ELEMENT_NODE) {
1479 cur->content = (void *) (-(++count));
1480 if (cur->children != NULL) {
1481 cur = cur->children;
1482 continue;
1483 }
1484 }
1485 if (cur->next != NULL) {
1486 cur = cur->next;
1487 continue;
1488 }
1489 do {
1490 cur = cur->parent;
1491 if (cur == NULL)
1492 break;
1493 if (cur == (xmlNodePtr) doc) {
1494 cur = NULL;
1495 break;
1496 }
1497 if (cur->next != NULL) {
1498 cur = cur->next;
1499 break;
1500 }
1501 } while (cur != NULL);
1502 }
1503 return(count);
1504}
1505
1506/**
Owen Taylor3473f882001-02-23 17:55:21 +00001507 * xmlXPathCmpNodes:
1508 * @node1: the first node
1509 * @node2: the second node
1510 *
1511 * Compare two nodes w.r.t document order
1512 *
1513 * Returns -2 in case of error 1 if first point < second point, 0 if
William M. Brack08171912003-12-29 02:52:11 +00001514 * it's the same node, -1 otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00001515 */
1516int
1517xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1518 int depth1, depth2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001519 int attr1 = 0, attr2 = 0;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001520 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001521 xmlNodePtr cur, root;
1522
1523 if ((node1 == NULL) || (node2 == NULL))
1524 return(-2);
1525 /*
1526 * a couple of optimizations which will avoid computations in most cases
1527 */
Daniel Veillardedfd5882003-03-07 14:20:40 +00001528 if (node1->type == XML_ATTRIBUTE_NODE) {
1529 attr1 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001530 attrNode1 = node1;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001531 node1 = node1->parent;
1532 }
1533 if (node2->type == XML_ATTRIBUTE_NODE) {
1534 attr2 = 1;
William M. Bracke8d1bd92003-12-23 01:28:58 +00001535 attrNode2 = node2;
Daniel Veillardedfd5882003-03-07 14:20:40 +00001536 node2 = node2->parent;
1537 }
1538 if (node1 == node2) {
William M. Bracke8d1bd92003-12-23 01:28:58 +00001539 if (attr1 == attr2) {
1540 /* not required, but we keep attributes in order */
1541 if (attr1 != 0) {
1542 cur = attrNode2->prev;
1543 while (cur != NULL) {
1544 if (cur == attrNode1)
1545 return (1);
1546 cur = cur->prev;
1547 }
1548 return (-1);
1549 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001550 return(0);
William M. Bracke8d1bd92003-12-23 01:28:58 +00001551 }
Daniel Veillardedfd5882003-03-07 14:20:40 +00001552 if (attr2 == 1)
1553 return(1);
1554 return(-1);
1555 }
Daniel Veillardb33c2012001-04-25 12:59:04 +00001556 if ((node1->type == XML_NAMESPACE_DECL) ||
1557 (node2->type == XML_NAMESPACE_DECL))
1558 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001559 if (node1 == node2->prev)
1560 return(1);
1561 if (node1 == node2->next)
1562 return(-1);
1563
1564 /*
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001565 * Speedup using document order if availble.
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001566 */
1567 if ((node1->type == XML_ELEMENT_NODE) &&
1568 (node2->type == XML_ELEMENT_NODE) &&
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001569 (0 > (long) node1->content) &&
1570 (0 > (long) node2->content) &&
1571 (node1->doc == node2->doc)) {
1572 long l1, l2;
1573
1574 l1 = -((long) node1->content);
1575 l2 = -((long) node2->content);
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001576 if (l1 < l2)
1577 return(1);
1578 if (l1 > l2)
1579 return(-1);
1580 }
Daniel Veillarde4fa2932003-03-26 00:38:10 +00001581
Daniel Veillard7216cfd2002-11-08 15:10:00 +00001582 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001583 * compute depth to root
1584 */
1585 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1586 if (cur == node1)
1587 return(1);
1588 depth2++;
1589 }
1590 root = cur;
1591 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1592 if (cur == node2)
1593 return(-1);
1594 depth1++;
1595 }
1596 /*
1597 * Distinct document (or distinct entities :-( ) case.
1598 */
1599 if (root != cur) {
1600 return(-2);
1601 }
1602 /*
1603 * get the nearest common ancestor.
1604 */
1605 while (depth1 > depth2) {
1606 depth1--;
1607 node1 = node1->parent;
1608 }
1609 while (depth2 > depth1) {
1610 depth2--;
1611 node2 = node2->parent;
1612 }
1613 while (node1->parent != node2->parent) {
1614 node1 = node1->parent;
1615 node2 = node2->parent;
1616 /* should not happen but just in case ... */
1617 if ((node1 == NULL) || (node2 == NULL))
1618 return(-2);
1619 }
1620 /*
1621 * Find who's first.
1622 */
Daniel Veillardf49be472004-02-17 11:48:18 +00001623 if (node1 == node2->prev)
1624 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001625 if (node1 == node2->next)
1626 return(-1);
Daniel Veillardf49be472004-02-17 11:48:18 +00001627 /*
1628 * Speedup using document order if availble.
1629 */
1630 if ((node1->type == XML_ELEMENT_NODE) &&
1631 (node2->type == XML_ELEMENT_NODE) &&
1632 (0 > (long) node1->content) &&
1633 (0 > (long) node2->content) &&
1634 (node1->doc == node2->doc)) {
1635 long l1, l2;
1636
1637 l1 = -((long) node1->content);
1638 l2 = -((long) node2->content);
1639 if (l1 < l2)
1640 return(1);
1641 if (l1 > l2)
1642 return(-1);
1643 }
1644
Owen Taylor3473f882001-02-23 17:55:21 +00001645 for (cur = node1->next;cur != NULL;cur = cur->next)
1646 if (cur == node2)
1647 return(1);
1648 return(-1); /* assume there is no sibling list corruption */
1649}
1650
1651/**
1652 * xmlXPathNodeSetSort:
1653 * @set: the node set
1654 *
1655 * Sort the node set in document order
1656 */
1657void
1658xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001659 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001660 xmlNodePtr tmp;
1661
1662 if (set == NULL)
1663 return;
1664
1665 /* Use Shell's sort to sort the node-set */
1666 len = set->nodeNr;
1667 for (incr = len / 2; incr > 0; incr /= 2) {
1668 for (i = incr; i < len; i++) {
1669 j = i - incr;
1670 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001671 if (xmlXPathCmpNodes(set->nodeTab[j],
1672 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001673 tmp = set->nodeTab[j];
1674 set->nodeTab[j] = set->nodeTab[j + incr];
1675 set->nodeTab[j + incr] = tmp;
1676 j -= incr;
1677 } else
1678 break;
1679 }
1680 }
1681 }
1682}
1683
1684#define XML_NODESET_DEFAULT 10
1685/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001686 * xmlXPathNodeSetDupNs:
1687 * @node: the parent node of the namespace XPath node
1688 * @ns: the libxml namespace declaration node.
1689 *
1690 * Namespace node in libxml don't match the XPath semantic. In a node set
1691 * the namespace nodes are duplicated and the next pointer is set to the
1692 * parent node in the XPath semantic.
1693 *
1694 * Returns the newly created object.
1695 */
1696static xmlNodePtr
1697xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1698 xmlNsPtr cur;
1699
1700 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1701 return(NULL);
1702 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1703 return((xmlNodePtr) ns);
1704
1705 /*
1706 * Allocate a new Namespace and fill the fields.
1707 */
1708 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1709 if (cur == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001710 xmlXPathErrMemory(NULL, "duplicating namespace\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001711 return(NULL);
1712 }
1713 memset(cur, 0, sizeof(xmlNs));
1714 cur->type = XML_NAMESPACE_DECL;
1715 if (ns->href != NULL)
1716 cur->href = xmlStrdup(ns->href);
1717 if (ns->prefix != NULL)
1718 cur->prefix = xmlStrdup(ns->prefix);
1719 cur->next = (xmlNsPtr) node;
1720 return((xmlNodePtr) cur);
1721}
1722
1723/**
1724 * xmlXPathNodeSetFreeNs:
1725 * @ns: the XPath namespace node found in a nodeset.
1726 *
William M. Brack08171912003-12-29 02:52:11 +00001727 * Namespace nodes in libxml don't match the XPath semantic. In a node set
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001728 * the namespace nodes are duplicated and the next pointer is set to the
William M. Brack08171912003-12-29 02:52:11 +00001729 * parent node in the XPath semantic. Check if such a node needs to be freed
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001730 */
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00001731void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001732xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1733 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1734 return;
1735
1736 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1737 if (ns->href != NULL)
1738 xmlFree((xmlChar *)ns->href);
1739 if (ns->prefix != NULL)
1740 xmlFree((xmlChar *)ns->prefix);
1741 xmlFree(ns);
1742 }
1743}
1744
1745/**
Owen Taylor3473f882001-02-23 17:55:21 +00001746 * xmlXPathNodeSetCreate:
1747 * @val: an initial xmlNodePtr, or NULL
1748 *
1749 * Create a new xmlNodeSetPtr of type double and of value @val
1750 *
1751 * Returns the newly created object.
1752 */
1753xmlNodeSetPtr
1754xmlXPathNodeSetCreate(xmlNodePtr val) {
1755 xmlNodeSetPtr ret;
1756
1757 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1758 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001759 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001760 return(NULL);
1761 }
1762 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1763 if (val != NULL) {
1764 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1765 sizeof(xmlNodePtr));
1766 if (ret->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001767 xmlXPathErrMemory(NULL, "creating nodeset\n");
1768 xmlFree(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001769 return(NULL);
1770 }
1771 memset(ret->nodeTab, 0 ,
1772 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1773 ret->nodeMax = XML_NODESET_DEFAULT;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001774 if (val->type == XML_NAMESPACE_DECL) {
1775 xmlNsPtr ns = (xmlNsPtr) val;
1776
1777 ret->nodeTab[ret->nodeNr++] =
1778 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1779 } else
1780 ret->nodeTab[ret->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001781 }
1782 return(ret);
1783}
1784
1785/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001786 * xmlXPathNodeSetContains:
1787 * @cur: the node-set
1788 * @val: the node
1789 *
1790 * checks whether @cur contains @val
1791 *
1792 * Returns true (1) if @cur contains @val, false (0) otherwise
1793 */
1794int
1795xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1796 int i;
1797
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001798 if (val->type == XML_NAMESPACE_DECL) {
1799 for (i = 0; i < cur->nodeNr; i++) {
1800 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1801 xmlNsPtr ns1, ns2;
1802
1803 ns1 = (xmlNsPtr) val;
1804 ns2 = (xmlNsPtr) cur->nodeTab[i];
1805 if (ns1 == ns2)
1806 return(1);
1807 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1808 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1809 return(1);
1810 }
1811 }
1812 } else {
1813 for (i = 0; i < cur->nodeNr; i++) {
1814 if (cur->nodeTab[i] == val)
1815 return(1);
1816 }
Thomas Broyerf06a3d82001-07-16 04:52:57 +00001817 }
1818 return(0);
1819}
1820
1821/**
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001822 * xmlXPathNodeSetAddNs:
1823 * @cur: the initial node set
1824 * @node: the hosting node
1825 * @ns: a the namespace node
1826 *
1827 * add a new namespace node to an existing NodeSet
1828 */
Aleksey Sanin79376ba2002-05-14 06:41:32 +00001829void
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001830xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1831 int i;
1832
1833 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1834 (node->type != XML_ELEMENT_NODE))
1835 return;
1836
William M. Brack08171912003-12-29 02:52:11 +00001837 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001838 /*
William M. Brack08171912003-12-29 02:52:11 +00001839 * prevent duplicates
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001840 */
1841 for (i = 0;i < cur->nodeNr;i++) {
1842 if ((cur->nodeTab[i] != NULL) &&
1843 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
Daniel Veillardc62a1472002-03-19 18:35:12 +00001844 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001845 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1846 return;
1847 }
1848
1849 /*
1850 * grow the nodeTab if needed
1851 */
1852 if (cur->nodeMax == 0) {
1853 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1854 sizeof(xmlNodePtr));
1855 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001856 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001857 return;
1858 }
1859 memset(cur->nodeTab, 0 ,
1860 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1861 cur->nodeMax = XML_NODESET_DEFAULT;
1862 } else if (cur->nodeNr == cur->nodeMax) {
1863 xmlNodePtr *temp;
1864
1865 cur->nodeMax *= 2;
1866 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1867 sizeof(xmlNodePtr));
1868 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001869 xmlXPathErrMemory(NULL, "growing nodeset\n");
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001870 return;
1871 }
1872 cur->nodeTab = temp;
1873 }
1874 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1875}
1876
1877/**
Owen Taylor3473f882001-02-23 17:55:21 +00001878 * xmlXPathNodeSetAdd:
1879 * @cur: the initial node set
1880 * @val: a new xmlNodePtr
1881 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001882 * add a new xmlNodePtr to an existing NodeSet
Owen Taylor3473f882001-02-23 17:55:21 +00001883 */
1884void
1885xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1886 int i;
1887
1888 if (val == NULL) return;
1889
Daniel Veillardef0b4502003-03-24 13:57:34 +00001890#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001891 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1892 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001893#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001894
William M. Brack08171912003-12-29 02:52:11 +00001895 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001896 /*
William M. Brack08171912003-12-29 02:52:11 +00001897 * prevent duplcates
Owen Taylor3473f882001-02-23 17:55:21 +00001898 */
1899 for (i = 0;i < cur->nodeNr;i++)
1900 if (cur->nodeTab[i] == val) return;
1901
1902 /*
1903 * grow the nodeTab if needed
1904 */
1905 if (cur->nodeMax == 0) {
1906 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1907 sizeof(xmlNodePtr));
1908 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001909 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001910 return;
1911 }
1912 memset(cur->nodeTab, 0 ,
1913 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1914 cur->nodeMax = XML_NODESET_DEFAULT;
1915 } else if (cur->nodeNr == cur->nodeMax) {
1916 xmlNodePtr *temp;
1917
1918 cur->nodeMax *= 2;
1919 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1920 sizeof(xmlNodePtr));
1921 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001922 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001923 return;
1924 }
1925 cur->nodeTab = temp;
1926 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001927 if (val->type == XML_NAMESPACE_DECL) {
1928 xmlNsPtr ns = (xmlNsPtr) val;
1929
1930 cur->nodeTab[cur->nodeNr++] =
1931 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1932 } else
1933 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001934}
1935
1936/**
1937 * xmlXPathNodeSetAddUnique:
1938 * @cur: the initial node set
1939 * @val: a new xmlNodePtr
1940 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001941 * add a new xmlNodePtr to an existing NodeSet, optimized version
Owen Taylor3473f882001-02-23 17:55:21 +00001942 * when we are sure the node is not already in the set.
1943 */
1944void
1945xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1946 if (val == NULL) return;
1947
Daniel Veillardef0b4502003-03-24 13:57:34 +00001948#if 0
Daniel Veillard652d8a92003-02-04 19:28:49 +00001949 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1950 return; /* an XSLT fake node */
Daniel Veillardef0b4502003-03-24 13:57:34 +00001951#endif
Daniel Veillard652d8a92003-02-04 19:28:49 +00001952
William M. Brack08171912003-12-29 02:52:11 +00001953 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00001954 /*
1955 * grow the nodeTab if needed
1956 */
1957 if (cur->nodeMax == 0) {
1958 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1959 sizeof(xmlNodePtr));
1960 if (cur->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001961 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001962 return;
1963 }
1964 memset(cur->nodeTab, 0 ,
1965 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1966 cur->nodeMax = XML_NODESET_DEFAULT;
1967 } else if (cur->nodeNr == cur->nodeMax) {
1968 xmlNodePtr *temp;
1969
1970 cur->nodeMax *= 2;
1971 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1972 sizeof(xmlNodePtr));
1973 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001974 xmlXPathErrMemory(NULL, "growing nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001975 return;
1976 }
1977 cur->nodeTab = temp;
1978 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00001979 if (val->type == XML_NAMESPACE_DECL) {
1980 xmlNsPtr ns = (xmlNsPtr) val;
1981
1982 cur->nodeTab[cur->nodeNr++] =
1983 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1984 } else
1985 cur->nodeTab[cur->nodeNr++] = val;
Owen Taylor3473f882001-02-23 17:55:21 +00001986}
1987
1988/**
1989 * xmlXPathNodeSetMerge:
1990 * @val1: the first NodeSet or NULL
1991 * @val2: the second NodeSet
1992 *
1993 * Merges two nodesets, all nodes from @val2 are added to @val1
1994 * if @val1 is NULL, a new set is created and copied from @val2
1995 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001996 * Returns @val1 once extended or NULL in case of error.
Owen Taylor3473f882001-02-23 17:55:21 +00001997 */
1998xmlNodeSetPtr
1999xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002000 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00002001
2002 if (val2 == NULL) return(val1);
2003 if (val1 == NULL) {
2004 val1 = xmlXPathNodeSetCreate(NULL);
2005 }
2006
William M. Brack08171912003-12-29 02:52:11 +00002007 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002008 initNr = val1->nodeNr;
2009
2010 for (i = 0;i < val2->nodeNr;i++) {
2011 /*
William M. Brack08171912003-12-29 02:52:11 +00002012 * check against duplicates
Owen Taylor3473f882001-02-23 17:55:21 +00002013 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002014 skip = 0;
2015 for (j = 0; j < initNr; j++) {
2016 if (val1->nodeTab[j] == val2->nodeTab[i]) {
2017 skip = 1;
2018 break;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002019 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
2020 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
2021 xmlNsPtr ns1, ns2;
2022 ns1 = (xmlNsPtr) val1->nodeTab[j];
2023 ns2 = (xmlNsPtr) val2->nodeTab[i];
2024 if ((ns1->next == ns2->next) &&
2025 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
2026 skip = 1;
2027 break;
2028 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00002029 }
2030 }
2031 if (skip)
2032 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00002033
2034 /*
2035 * grow the nodeTab if needed
2036 */
2037 if (val1->nodeMax == 0) {
2038 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2039 sizeof(xmlNodePtr));
2040 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002041 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002042 return(NULL);
2043 }
2044 memset(val1->nodeTab, 0 ,
2045 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2046 val1->nodeMax = XML_NODESET_DEFAULT;
2047 } else if (val1->nodeNr == val1->nodeMax) {
2048 xmlNodePtr *temp;
2049
2050 val1->nodeMax *= 2;
2051 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2052 sizeof(xmlNodePtr));
2053 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002054 xmlXPathErrMemory(NULL, "merging nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002055 return(NULL);
2056 }
2057 val1->nodeTab = temp;
2058 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002059 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2060 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2061
2062 val1->nodeTab[val1->nodeNr++] =
2063 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2064 } else
2065 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
Owen Taylor3473f882001-02-23 17:55:21 +00002066 }
2067
2068 return(val1);
2069}
2070
2071/**
Daniel Veillard75be0132002-03-13 10:03:35 +00002072 * xmlXPathNodeSetMergeUnique:
2073 * @val1: the first NodeSet or NULL
2074 * @val2: the second NodeSet
2075 *
2076 * Merges two nodesets, all nodes from @val2 are added to @val1
2077 * if @val1 is NULL, a new set is created and copied from @val2
2078 *
2079 * Returns @val1 once extended or NULL in case of error.
2080 */
2081static xmlNodeSetPtr
2082xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
William M. Brack78637da2003-07-31 14:47:38 +00002083 int i;
Daniel Veillard75be0132002-03-13 10:03:35 +00002084
2085 if (val2 == NULL) return(val1);
2086 if (val1 == NULL) {
2087 val1 = xmlXPathNodeSetCreate(NULL);
2088 }
2089
William M. Brack08171912003-12-29 02:52:11 +00002090 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard75be0132002-03-13 10:03:35 +00002091
2092 for (i = 0;i < val2->nodeNr;i++) {
2093 /*
2094 * grow the nodeTab if needed
2095 */
2096 if (val1->nodeMax == 0) {
2097 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2098 sizeof(xmlNodePtr));
2099 if (val1->nodeTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002100 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002101 return(NULL);
2102 }
2103 memset(val1->nodeTab, 0 ,
2104 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
2105 val1->nodeMax = XML_NODESET_DEFAULT;
2106 } else if (val1->nodeNr == val1->nodeMax) {
2107 xmlNodePtr *temp;
2108
2109 val1->nodeMax *= 2;
2110 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
2111 sizeof(xmlNodePtr));
2112 if (temp == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002113 xmlXPathErrMemory(NULL, "merging nodeset\n");
Daniel Veillard75be0132002-03-13 10:03:35 +00002114 return(NULL);
2115 }
2116 val1->nodeTab = temp;
2117 }
2118 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2119 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
2120
2121 val1->nodeTab[val1->nodeNr++] =
2122 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2123 } else
2124 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
2125 }
2126
2127 return(val1);
2128}
2129
2130/**
Owen Taylor3473f882001-02-23 17:55:21 +00002131 * xmlXPathNodeSetDel:
2132 * @cur: the initial node set
2133 * @val: an xmlNodePtr
2134 *
2135 * Removes an xmlNodePtr from an existing NodeSet
2136 */
2137void
2138xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2139 int i;
2140
2141 if (cur == NULL) return;
2142 if (val == NULL) return;
2143
2144 /*
William M. Brack08171912003-12-29 02:52:11 +00002145 * find node in nodeTab
Owen Taylor3473f882001-02-23 17:55:21 +00002146 */
2147 for (i = 0;i < cur->nodeNr;i++)
2148 if (cur->nodeTab[i] == val) break;
2149
William M. Brack08171912003-12-29 02:52:11 +00002150 if (i >= cur->nodeNr) { /* not found */
Owen Taylor3473f882001-02-23 17:55:21 +00002151#ifdef DEBUG
2152 xmlGenericError(xmlGenericErrorContext,
2153 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2154 val->name);
2155#endif
2156 return;
2157 }
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002158 if ((cur->nodeTab[i] != NULL) &&
2159 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2160 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002161 cur->nodeNr--;
2162 for (;i < cur->nodeNr;i++)
2163 cur->nodeTab[i] = cur->nodeTab[i + 1];
2164 cur->nodeTab[cur->nodeNr] = NULL;
2165}
2166
2167/**
2168 * xmlXPathNodeSetRemove:
2169 * @cur: the initial node set
2170 * @val: the index to remove
2171 *
2172 * Removes an entry from an existing NodeSet list.
2173 */
2174void
2175xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2176 if (cur == NULL) return;
2177 if (val >= cur->nodeNr) return;
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002178 if ((cur->nodeTab[val] != NULL) &&
2179 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2180 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
Owen Taylor3473f882001-02-23 17:55:21 +00002181 cur->nodeNr--;
2182 for (;val < cur->nodeNr;val++)
2183 cur->nodeTab[val] = cur->nodeTab[val + 1];
2184 cur->nodeTab[cur->nodeNr] = NULL;
2185}
2186
2187/**
2188 * xmlXPathFreeNodeSet:
2189 * @obj: the xmlNodeSetPtr to free
2190 *
2191 * Free the NodeSet compound (not the actual nodes !).
2192 */
2193void
2194xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2195 if (obj == NULL) return;
2196 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002197 int i;
2198
William M. Brack08171912003-12-29 02:52:11 +00002199 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002200 for (i = 0;i < obj->nodeNr;i++)
2201 if ((obj->nodeTab[i] != NULL) &&
2202 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2203 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00002204 xmlFree(obj->nodeTab);
2205 }
Owen Taylor3473f882001-02-23 17:55:21 +00002206 xmlFree(obj);
2207}
2208
2209/**
2210 * xmlXPathFreeValueTree:
2211 * @obj: the xmlNodeSetPtr to free
2212 *
2213 * Free the NodeSet compound and the actual tree, this is different
2214 * from xmlXPathFreeNodeSet()
2215 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002216static void
Owen Taylor3473f882001-02-23 17:55:21 +00002217xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2218 int i;
2219
2220 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002221
2222 if (obj->nodeTab != NULL) {
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002223 for (i = 0;i < obj->nodeNr;i++) {
2224 if (obj->nodeTab[i] != NULL) {
2225 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2226 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2227 } else {
2228 xmlFreeNodeList(obj->nodeTab[i]);
2229 }
2230 }
2231 }
Owen Taylor3473f882001-02-23 17:55:21 +00002232 xmlFree(obj->nodeTab);
2233 }
Owen Taylor3473f882001-02-23 17:55:21 +00002234 xmlFree(obj);
2235}
2236
2237#if defined(DEBUG) || defined(DEBUG_STEP)
2238/**
2239 * xmlGenericErrorContextNodeSet:
2240 * @output: a FILE * for the output
William M. Brack08171912003-12-29 02:52:11 +00002241 * @obj: the xmlNodeSetPtr to display
Owen Taylor3473f882001-02-23 17:55:21 +00002242 *
2243 * Quick display of a NodeSet
2244 */
2245void
2246xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2247 int i;
2248
2249 if (output == NULL) output = xmlGenericErrorContext;
2250 if (obj == NULL) {
2251 fprintf(output, "NodeSet == NULL !\n");
2252 return;
2253 }
2254 if (obj->nodeNr == 0) {
2255 fprintf(output, "NodeSet is empty\n");
2256 return;
2257 }
2258 if (obj->nodeTab == NULL) {
2259 fprintf(output, " nodeTab == NULL !\n");
2260 return;
2261 }
2262 for (i = 0; i < obj->nodeNr; i++) {
2263 if (obj->nodeTab[i] == NULL) {
2264 fprintf(output, " NULL !\n");
2265 return;
2266 }
2267 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2268 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2269 fprintf(output, " /");
2270 else if (obj->nodeTab[i]->name == NULL)
2271 fprintf(output, " noname!");
2272 else fprintf(output, " %s", obj->nodeTab[i]->name);
2273 }
2274 fprintf(output, "\n");
2275}
2276#endif
2277
2278/**
2279 * xmlXPathNewNodeSet:
2280 * @val: the NodePtr value
2281 *
2282 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2283 * it with the single Node @val
2284 *
2285 * Returns the newly created object.
2286 */
2287xmlXPathObjectPtr
2288xmlXPathNewNodeSet(xmlNodePtr val) {
2289 xmlXPathObjectPtr ret;
2290
2291 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2292 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002293 xmlXPathErrMemory(NULL, "creating nodeset\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002294 return(NULL);
2295 }
2296 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2297 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00002298 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002299 ret->nodesetval = xmlXPathNodeSetCreate(val);
William M. Brack08171912003-12-29 02:52:11 +00002300 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(ret);
2302}
2303
2304/**
2305 * xmlXPathNewValueTree:
2306 * @val: the NodePtr value
2307 *
2308 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2309 * it with the tree root @val
2310 *
2311 * Returns the newly created object.
2312 */
2313xmlXPathObjectPtr
2314xmlXPathNewValueTree(xmlNodePtr val) {
2315 xmlXPathObjectPtr ret;
2316
2317 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2318 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002319 xmlXPathErrMemory(NULL, "creating result value tree\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002320 return(NULL);
2321 }
2322 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2323 ret->type = XPATH_XSLT_TREE;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00002324 ret->boolval = 1;
2325 ret->user = (void *) val;
Owen Taylor3473f882001-02-23 17:55:21 +00002326 ret->nodesetval = xmlXPathNodeSetCreate(val);
2327 return(ret);
2328}
2329
2330/**
2331 * xmlXPathNewNodeSetList:
2332 * @val: an existing NodeSet
2333 *
2334 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2335 * it with the Nodeset @val
2336 *
2337 * Returns the newly created object.
2338 */
2339xmlXPathObjectPtr
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002340xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2341{
Owen Taylor3473f882001-02-23 17:55:21 +00002342 xmlXPathObjectPtr ret;
2343 int i;
2344
2345 if (val == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002346 ret = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002347 else if (val->nodeTab == NULL)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002348 ret = xmlXPathNewNodeSet(NULL);
2349 else {
2350 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2351 for (i = 1; i < val->nodeNr; ++i)
2352 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2353 }
Owen Taylor3473f882001-02-23 17:55:21 +00002354
Daniel Veillard044fc6b2002-03-04 17:09:44 +00002355 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002356}
2357
2358/**
2359 * xmlXPathWrapNodeSet:
2360 * @val: the NodePtr value
2361 *
2362 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2363 *
2364 * Returns the newly created object.
2365 */
2366xmlXPathObjectPtr
2367xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2368 xmlXPathObjectPtr ret;
2369
2370 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2371 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00002372 xmlXPathErrMemory(NULL, "creating node set object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002373 return(NULL);
2374 }
2375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2376 ret->type = XPATH_NODESET;
2377 ret->nodesetval = val;
2378 return(ret);
2379}
2380
2381/**
2382 * xmlXPathFreeNodeSetList:
2383 * @obj: an existing NodeSetList object
2384 *
2385 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2386 * the list contrary to xmlXPathFreeObject().
2387 */
2388void
2389xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2390 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00002391 xmlFree(obj);
2392}
2393
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002394/**
2395 * xmlXPathDifference:
2396 * @nodes1: a node-set
2397 * @nodes2: a node-set
2398 *
2399 * Implements the EXSLT - Sets difference() function:
2400 * node-set set:difference (node-set, node-set)
2401 *
2402 * Returns the difference between the two node sets, or nodes1 if
2403 * nodes2 is empty
2404 */
2405xmlNodeSetPtr
2406xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2407 xmlNodeSetPtr ret;
2408 int i, l1;
2409 xmlNodePtr cur;
2410
2411 if (xmlXPathNodeSetIsEmpty(nodes2))
2412 return(nodes1);
2413
2414 ret = xmlXPathNodeSetCreate(NULL);
2415 if (xmlXPathNodeSetIsEmpty(nodes1))
2416 return(ret);
2417
2418 l1 = xmlXPathNodeSetGetLength(nodes1);
2419
2420 for (i = 0; i < l1; i++) {
2421 cur = xmlXPathNodeSetItem(nodes1, i);
2422 if (!xmlXPathNodeSetContains(nodes2, cur))
2423 xmlXPathNodeSetAddUnique(ret, cur);
2424 }
2425 return(ret);
2426}
2427
2428/**
2429 * xmlXPathIntersection:
2430 * @nodes1: a node-set
2431 * @nodes2: a node-set
2432 *
2433 * Implements the EXSLT - Sets intersection() function:
2434 * node-set set:intersection (node-set, node-set)
2435 *
2436 * Returns a node set comprising the nodes that are within both the
2437 * node sets passed as arguments
2438 */
2439xmlNodeSetPtr
2440xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2441 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2442 int i, l1;
2443 xmlNodePtr cur;
2444
2445 if (xmlXPathNodeSetIsEmpty(nodes1))
2446 return(ret);
2447 if (xmlXPathNodeSetIsEmpty(nodes2))
2448 return(ret);
2449
2450 l1 = xmlXPathNodeSetGetLength(nodes1);
2451
2452 for (i = 0; i < l1; i++) {
2453 cur = xmlXPathNodeSetItem(nodes1, i);
2454 if (xmlXPathNodeSetContains(nodes2, cur))
2455 xmlXPathNodeSetAddUnique(ret, cur);
2456 }
2457 return(ret);
2458}
2459
2460/**
2461 * xmlXPathDistinctSorted:
2462 * @nodes: a node-set, sorted by document order
2463 *
2464 * Implements the EXSLT - Sets distinct() function:
2465 * node-set set:distinct (node-set)
2466 *
2467 * Returns a subset of the nodes contained in @nodes, or @nodes if
2468 * it is empty
2469 */
2470xmlNodeSetPtr
2471xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2472 xmlNodeSetPtr ret;
2473 xmlHashTablePtr hash;
2474 int i, l;
2475 xmlChar * strval;
2476 xmlNodePtr cur;
2477
2478 if (xmlXPathNodeSetIsEmpty(nodes))
2479 return(nodes);
2480
2481 ret = xmlXPathNodeSetCreate(NULL);
2482 l = xmlXPathNodeSetGetLength(nodes);
2483 hash = xmlHashCreate (l);
2484 for (i = 0; i < l; i++) {
2485 cur = xmlXPathNodeSetItem(nodes, i);
2486 strval = xmlXPathCastNodeToString(cur);
2487 if (xmlHashLookup(hash, strval) == NULL) {
2488 xmlHashAddEntry(hash, strval, strval);
2489 xmlXPathNodeSetAddUnique(ret, cur);
2490 } else {
2491 xmlFree(strval);
2492 }
2493 }
2494 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2495 return(ret);
2496}
2497
2498/**
2499 * xmlXPathDistinct:
2500 * @nodes: a node-set
2501 *
2502 * Implements the EXSLT - Sets distinct() function:
2503 * node-set set:distinct (node-set)
2504 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2505 * is called with the sorted node-set
2506 *
2507 * Returns a subset of the nodes contained in @nodes, or @nodes if
2508 * it is empty
2509 */
2510xmlNodeSetPtr
2511xmlXPathDistinct (xmlNodeSetPtr nodes) {
2512 if (xmlXPathNodeSetIsEmpty(nodes))
2513 return(nodes);
2514
2515 xmlXPathNodeSetSort(nodes);
2516 return(xmlXPathDistinctSorted(nodes));
2517}
2518
2519/**
2520 * xmlXPathHasSameNodes:
2521 * @nodes1: a node-set
2522 * @nodes2: a node-set
2523 *
2524 * Implements the EXSLT - Sets has-same-nodes function:
2525 * boolean set:has-same-node(node-set, node-set)
2526 *
2527 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2528 * otherwise
2529 */
2530int
2531xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2532 int i, l;
2533 xmlNodePtr cur;
2534
2535 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2536 xmlXPathNodeSetIsEmpty(nodes2))
2537 return(0);
2538
2539 l = xmlXPathNodeSetGetLength(nodes1);
2540 for (i = 0; i < l; i++) {
2541 cur = xmlXPathNodeSetItem(nodes1, i);
2542 if (xmlXPathNodeSetContains(nodes2, cur))
2543 return(1);
2544 }
2545 return(0);
2546}
2547
2548/**
2549 * xmlXPathNodeLeadingSorted:
2550 * @nodes: a node-set, sorted by document order
2551 * @node: a node
2552 *
2553 * Implements the EXSLT - Sets leading() function:
2554 * node-set set:leading (node-set, node-set)
2555 *
2556 * Returns the nodes in @nodes that precede @node in document order,
2557 * @nodes if @node is NULL or an empty node-set if @nodes
2558 * doesn't contain @node
2559 */
2560xmlNodeSetPtr
2561xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2562 int i, l;
2563 xmlNodePtr cur;
2564 xmlNodeSetPtr ret;
2565
2566 if (node == NULL)
2567 return(nodes);
2568
2569 ret = xmlXPathNodeSetCreate(NULL);
2570 if (xmlXPathNodeSetIsEmpty(nodes) ||
2571 (!xmlXPathNodeSetContains(nodes, node)))
2572 return(ret);
2573
2574 l = xmlXPathNodeSetGetLength(nodes);
2575 for (i = 0; i < l; i++) {
2576 cur = xmlXPathNodeSetItem(nodes, i);
2577 if (cur == node)
2578 break;
2579 xmlXPathNodeSetAddUnique(ret, cur);
2580 }
2581 return(ret);
2582}
2583
2584/**
2585 * xmlXPathNodeLeading:
2586 * @nodes: a node-set
2587 * @node: a node
2588 *
2589 * Implements the EXSLT - Sets leading() function:
2590 * node-set set:leading (node-set, node-set)
2591 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2592 * is called.
2593 *
2594 * Returns the nodes in @nodes that precede @node in document order,
2595 * @nodes if @node is NULL or an empty node-set if @nodes
2596 * doesn't contain @node
2597 */
2598xmlNodeSetPtr
2599xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2600 xmlXPathNodeSetSort(nodes);
2601 return(xmlXPathNodeLeadingSorted(nodes, node));
2602}
2603
2604/**
2605 * xmlXPathLeadingSorted:
2606 * @nodes1: a node-set, sorted by document order
2607 * @nodes2: a node-set, sorted by document order
2608 *
2609 * Implements the EXSLT - Sets leading() function:
2610 * node-set set:leading (node-set, node-set)
2611 *
2612 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2613 * in document order, @nodes1 if @nodes2 is NULL or empty or
2614 * an empty node-set if @nodes1 doesn't contain @nodes2
2615 */
2616xmlNodeSetPtr
2617xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2618 if (xmlXPathNodeSetIsEmpty(nodes2))
2619 return(nodes1);
2620 return(xmlXPathNodeLeadingSorted(nodes1,
2621 xmlXPathNodeSetItem(nodes2, 1)));
2622}
2623
2624/**
2625 * xmlXPathLeading:
2626 * @nodes1: a node-set
2627 * @nodes2: a node-set
2628 *
2629 * Implements the EXSLT - Sets leading() function:
2630 * node-set set:leading (node-set, node-set)
2631 * @nodes1 and @nodes2 are sorted by document order, then
2632 * #exslSetsLeadingSorted is called.
2633 *
2634 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2635 * in document order, @nodes1 if @nodes2 is NULL or empty or
2636 * an empty node-set if @nodes1 doesn't contain @nodes2
2637 */
2638xmlNodeSetPtr
2639xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2640 if (xmlXPathNodeSetIsEmpty(nodes2))
2641 return(nodes1);
2642 if (xmlXPathNodeSetIsEmpty(nodes1))
2643 return(xmlXPathNodeSetCreate(NULL));
2644 xmlXPathNodeSetSort(nodes1);
2645 xmlXPathNodeSetSort(nodes2);
2646 return(xmlXPathNodeLeadingSorted(nodes1,
2647 xmlXPathNodeSetItem(nodes2, 1)));
2648}
2649
2650/**
2651 * xmlXPathNodeTrailingSorted:
2652 * @nodes: a node-set, sorted by document order
2653 * @node: a node
2654 *
2655 * Implements the EXSLT - Sets trailing() function:
2656 * node-set set:trailing (node-set, node-set)
2657 *
2658 * Returns the nodes in @nodes that follow @node in document order,
2659 * @nodes if @node is NULL or an empty node-set if @nodes
2660 * doesn't contain @node
2661 */
2662xmlNodeSetPtr
2663xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2664 int i, l;
2665 xmlNodePtr cur;
2666 xmlNodeSetPtr ret;
2667
2668 if (node == NULL)
2669 return(nodes);
2670
2671 ret = xmlXPathNodeSetCreate(NULL);
2672 if (xmlXPathNodeSetIsEmpty(nodes) ||
2673 (!xmlXPathNodeSetContains(nodes, node)))
2674 return(ret);
2675
2676 l = xmlXPathNodeSetGetLength(nodes);
Thomas Broyerf186c822001-07-31 23:30:37 +00002677 for (i = l; i > 0; i--) {
Thomas Broyerf06a3d82001-07-16 04:52:57 +00002678 cur = xmlXPathNodeSetItem(nodes, i);
2679 if (cur == node)
2680 break;
2681 xmlXPathNodeSetAddUnique(ret, cur);
2682 }
2683 return(ret);
2684}
2685
2686/**
2687 * xmlXPathNodeTrailing:
2688 * @nodes: a node-set
2689 * @node: a node
2690 *
2691 * Implements the EXSLT - Sets trailing() function:
2692 * node-set set:trailing (node-set, node-set)
2693 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2694 * is called.
2695 *
2696 * Returns the nodes in @nodes that follow @node in document order,
2697 * @nodes if @node is NULL or an empty node-set if @nodes
2698 * doesn't contain @node
2699 */
2700xmlNodeSetPtr
2701xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2702 xmlXPathNodeSetSort(nodes);
2703 return(xmlXPathNodeTrailingSorted(nodes, node));
2704}
2705
2706/**
2707 * xmlXPathTrailingSorted:
2708 * @nodes1: a node-set, sorted by document order
2709 * @nodes2: a node-set, sorted by document order
2710 *
2711 * Implements the EXSLT - Sets trailing() function:
2712 * node-set set:trailing (node-set, node-set)
2713 *
2714 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2715 * in document order, @nodes1 if @nodes2 is NULL or empty or
2716 * an empty node-set if @nodes1 doesn't contain @nodes2
2717 */
2718xmlNodeSetPtr
2719xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2720 if (xmlXPathNodeSetIsEmpty(nodes2))
2721 return(nodes1);
2722 return(xmlXPathNodeTrailingSorted(nodes1,
2723 xmlXPathNodeSetItem(nodes2, 0)));
2724}
2725
2726/**
2727 * xmlXPathTrailing:
2728 * @nodes1: a node-set
2729 * @nodes2: a node-set
2730 *
2731 * Implements the EXSLT - Sets trailing() function:
2732 * node-set set:trailing (node-set, node-set)
2733 * @nodes1 and @nodes2 are sorted by document order, then
2734 * #xmlXPathTrailingSorted is called.
2735 *
2736 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2737 * in document order, @nodes1 if @nodes2 is NULL or empty or
2738 * an empty node-set if @nodes1 doesn't contain @nodes2
2739 */
2740xmlNodeSetPtr
2741xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2742 if (xmlXPathNodeSetIsEmpty(nodes2))
2743 return(nodes1);
2744 if (xmlXPathNodeSetIsEmpty(nodes1))
2745 return(xmlXPathNodeSetCreate(NULL));
2746 xmlXPathNodeSetSort(nodes1);
2747 xmlXPathNodeSetSort(nodes2);
2748 return(xmlXPathNodeTrailingSorted(nodes1,
2749 xmlXPathNodeSetItem(nodes2, 0)));
2750}
2751
Owen Taylor3473f882001-02-23 17:55:21 +00002752/************************************************************************
2753 * *
2754 * Routines to handle extra functions *
2755 * *
2756 ************************************************************************/
2757
2758/**
2759 * xmlXPathRegisterFunc:
2760 * @ctxt: the XPath context
2761 * @name: the function name
2762 * @f: the function implementation or NULL
2763 *
2764 * Register a new function. If @f is NULL it unregisters the function
2765 *
2766 * Returns 0 in case of success, -1 in case of error
2767 */
2768int
2769xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2770 xmlXPathFunction f) {
2771 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2772}
2773
2774/**
2775 * xmlXPathRegisterFuncNS:
2776 * @ctxt: the XPath context
2777 * @name: the function name
2778 * @ns_uri: the function namespace URI
2779 * @f: the function implementation or NULL
2780 *
2781 * Register a new function. If @f is NULL it unregisters the function
2782 *
2783 * Returns 0 in case of success, -1 in case of error
2784 */
2785int
2786xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2787 const xmlChar *ns_uri, xmlXPathFunction f) {
2788 if (ctxt == NULL)
2789 return(-1);
2790 if (name == NULL)
2791 return(-1);
2792
2793 if (ctxt->funcHash == NULL)
2794 ctxt->funcHash = xmlHashCreate(0);
2795 if (ctxt->funcHash == NULL)
2796 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002797 if (f == NULL)
2798 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
Owen Taylor3473f882001-02-23 17:55:21 +00002799 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2800}
2801
2802/**
Thomas Broyerba4ad322001-07-26 16:55:21 +00002803 * xmlXPathRegisterFuncLookup:
2804 * @ctxt: the XPath context
2805 * @f: the lookup function
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002806 * @funcCtxt: the lookup data
Thomas Broyerba4ad322001-07-26 16:55:21 +00002807 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002808 * Registers an external mechanism to do function lookup.
Thomas Broyerba4ad322001-07-26 16:55:21 +00002809 */
2810void
2811xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2812 xmlXPathFuncLookupFunc f,
2813 void *funcCtxt) {
2814 if (ctxt == NULL)
2815 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002816 ctxt->funcLookupFunc = f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002817 ctxt->funcLookupData = funcCtxt;
2818}
2819
2820/**
Owen Taylor3473f882001-02-23 17:55:21 +00002821 * xmlXPathFunctionLookup:
2822 * @ctxt: the XPath context
2823 * @name: the function name
2824 *
2825 * Search in the Function array of the context for the given
2826 * function.
2827 *
2828 * Returns the xmlXPathFunction or NULL if not found
2829 */
2830xmlXPathFunction
2831xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Thomas Broyerba4ad322001-07-26 16:55:21 +00002832 if (ctxt == NULL)
2833 return (NULL);
2834
2835 if (ctxt->funcLookupFunc != NULL) {
2836 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002837 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002838
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002839 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002840 ret = f(ctxt->funcLookupData, name, NULL);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002841 if (ret != NULL)
2842 return(ret);
2843 }
Owen Taylor3473f882001-02-23 17:55:21 +00002844 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2845}
2846
2847/**
2848 * xmlXPathFunctionLookupNS:
2849 * @ctxt: the XPath context
2850 * @name: the function name
2851 * @ns_uri: the function namespace URI
2852 *
2853 * Search in the Function array of the context for the given
2854 * function.
2855 *
2856 * Returns the xmlXPathFunction or NULL if not found
2857 */
2858xmlXPathFunction
2859xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2860 const xmlChar *ns_uri) {
2861 if (ctxt == NULL)
2862 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002863 if (name == NULL)
2864 return(NULL);
2865
Thomas Broyerba4ad322001-07-26 16:55:21 +00002866 if (ctxt->funcLookupFunc != NULL) {
2867 xmlXPathFunction ret;
Daniel Veillard99e55eb2002-01-21 08:56:29 +00002868 xmlXPathFuncLookupFunc f;
Thomas Broyerba4ad322001-07-26 16:55:21 +00002869
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002870 f = ctxt->funcLookupFunc;
Daniel Veillard963d2ae2002-01-20 22:08:18 +00002871 ret = f(ctxt->funcLookupData, name, ns_uri);
Thomas Broyerba4ad322001-07-26 16:55:21 +00002872 if (ret != NULL)
2873 return(ret);
2874 }
2875
2876 if (ctxt->funcHash == NULL)
2877 return(NULL);
2878
Owen Taylor3473f882001-02-23 17:55:21 +00002879 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2880}
2881
2882/**
2883 * xmlXPathRegisteredFuncsCleanup:
2884 * @ctxt: the XPath context
2885 *
2886 * Cleanup the XPath context data associated to registered functions
2887 */
2888void
2889xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2890 if (ctxt == NULL)
2891 return;
2892
2893 xmlHashFree(ctxt->funcHash, NULL);
2894 ctxt->funcHash = NULL;
2895}
2896
2897/************************************************************************
2898 * *
William M. Brack08171912003-12-29 02:52:11 +00002899 * Routines to handle Variables *
Owen Taylor3473f882001-02-23 17:55:21 +00002900 * *
2901 ************************************************************************/
2902
2903/**
2904 * xmlXPathRegisterVariable:
2905 * @ctxt: the XPath context
2906 * @name: the variable name
2907 * @value: the variable value or NULL
2908 *
2909 * Register a new variable value. If @value is NULL it unregisters
2910 * the variable
2911 *
2912 * Returns 0 in case of success, -1 in case of error
2913 */
2914int
2915xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2916 xmlXPathObjectPtr value) {
2917 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2918}
2919
2920/**
2921 * xmlXPathRegisterVariableNS:
2922 * @ctxt: the XPath context
2923 * @name: the variable name
2924 * @ns_uri: the variable namespace URI
2925 * @value: the variable value or NULL
2926 *
2927 * Register a new variable value. If @value is NULL it unregisters
2928 * the variable
2929 *
2930 * Returns 0 in case of success, -1 in case of error
2931 */
2932int
2933xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2934 const xmlChar *ns_uri,
2935 xmlXPathObjectPtr value) {
2936 if (ctxt == NULL)
2937 return(-1);
2938 if (name == NULL)
2939 return(-1);
2940
2941 if (ctxt->varHash == NULL)
2942 ctxt->varHash = xmlHashCreate(0);
2943 if (ctxt->varHash == NULL)
2944 return(-1);
Daniel Veillard94394cd2003-10-29 17:07:51 +00002945 if (value == NULL)
2946 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
2947 (xmlHashDeallocator)xmlXPathFreeObject));
Owen Taylor3473f882001-02-23 17:55:21 +00002948 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2949 (void *) value,
2950 (xmlHashDeallocator)xmlXPathFreeObject));
2951}
2952
2953/**
2954 * xmlXPathRegisterVariableLookup:
2955 * @ctxt: the XPath context
2956 * @f: the lookup function
2957 * @data: the lookup data
2958 *
2959 * register an external mechanism to do variable lookup
2960 */
2961void
2962xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2963 xmlXPathVariableLookupFunc f, void *data) {
2964 if (ctxt == NULL)
2965 return;
Daniel Veillard6ebf3c42004-08-22 13:11:39 +00002966 ctxt->varLookupFunc = f;
Owen Taylor3473f882001-02-23 17:55:21 +00002967 ctxt->varLookupData = data;
2968}
2969
2970/**
2971 * xmlXPathVariableLookup:
2972 * @ctxt: the XPath context
2973 * @name: the variable name
2974 *
2975 * Search in the Variable array of the context for the given
2976 * variable value.
2977 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00002978 * Returns a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00002979 */
2980xmlXPathObjectPtr
2981xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2982 if (ctxt == NULL)
2983 return(NULL);
2984
2985 if (ctxt->varLookupFunc != NULL) {
2986 xmlXPathObjectPtr ret;
2987
2988 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2989 (ctxt->varLookupData, name, NULL);
Daniel Veillard556c6682001-10-06 09:59:51 +00002990 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002991 }
2992 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2993}
2994
2995/**
2996 * xmlXPathVariableLookupNS:
2997 * @ctxt: the XPath context
2998 * @name: the variable name
2999 * @ns_uri: the variable namespace URI
3000 *
3001 * Search in the Variable array of the context for the given
Daniel Veillard73c9c042001-07-05 20:02:54 +00003002 * variable value.
Owen Taylor3473f882001-02-23 17:55:21 +00003003 *
Daniel Veillard73c9c042001-07-05 20:02:54 +00003004 * Returns the a copy of the value or NULL if not found
Owen Taylor3473f882001-02-23 17:55:21 +00003005 */
3006xmlXPathObjectPtr
3007xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3008 const xmlChar *ns_uri) {
3009 if (ctxt == NULL)
3010 return(NULL);
3011
3012 if (ctxt->varLookupFunc != NULL) {
3013 xmlXPathObjectPtr ret;
3014
3015 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3016 (ctxt->varLookupData, name, ns_uri);
3017 if (ret != NULL) return(ret);
3018 }
3019
3020 if (ctxt->varHash == NULL)
3021 return(NULL);
3022 if (name == NULL)
3023 return(NULL);
3024
Daniel Veillard8c357d52001-07-03 23:43:33 +00003025 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
3026 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
Owen Taylor3473f882001-02-23 17:55:21 +00003027}
3028
3029/**
3030 * xmlXPathRegisteredVariablesCleanup:
3031 * @ctxt: the XPath context
3032 *
3033 * Cleanup the XPath context data associated to registered variables
3034 */
3035void
3036xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
3037 if (ctxt == NULL)
3038 return;
3039
Daniel Veillard76d66f42001-05-16 21:05:17 +00003040 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00003041 ctxt->varHash = NULL;
3042}
3043
3044/**
3045 * xmlXPathRegisterNs:
3046 * @ctxt: the XPath context
3047 * @prefix: the namespace prefix
3048 * @ns_uri: the namespace name
3049 *
3050 * Register a new namespace. If @ns_uri is NULL it unregisters
3051 * the namespace
3052 *
3053 * Returns 0 in case of success, -1 in case of error
3054 */
3055int
3056xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
3057 const xmlChar *ns_uri) {
3058 if (ctxt == NULL)
3059 return(-1);
3060 if (prefix == NULL)
3061 return(-1);
3062
3063 if (ctxt->nsHash == NULL)
3064 ctxt->nsHash = xmlHashCreate(10);
3065 if (ctxt->nsHash == NULL)
3066 return(-1);
Daniel Veillarde991fe92003-10-29 11:18:37 +00003067 if (ns_uri == NULL)
Daniel Veillard94394cd2003-10-29 17:07:51 +00003068 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
Daniel Veillarde991fe92003-10-29 11:18:37 +00003069 (xmlHashDeallocator)xmlFree));
Daniel Veillard42766c02002-08-22 20:52:17 +00003070 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
Owen Taylor3473f882001-02-23 17:55:21 +00003071 (xmlHashDeallocator)xmlFree));
3072}
3073
3074/**
3075 * xmlXPathNsLookup:
3076 * @ctxt: the XPath context
3077 * @prefix: the namespace prefix value
3078 *
3079 * Search in the namespace declaration array of the context for the given
3080 * namespace name associated to the given prefix
3081 *
3082 * Returns the value or NULL if not found
3083 */
3084const xmlChar *
3085xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
3086 if (ctxt == NULL)
3087 return(NULL);
3088 if (prefix == NULL)
3089 return(NULL);
3090
3091#ifdef XML_XML_NAMESPACE
3092 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3093 return(XML_XML_NAMESPACE);
3094#endif
3095
Daniel Veillardc8f620b2001-04-30 20:31:33 +00003096 if (ctxt->namespaces != NULL) {
3097 int i;
3098
3099 for (i = 0;i < ctxt->nsNr;i++) {
3100 if ((ctxt->namespaces[i] != NULL) &&
3101 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
3102 return(ctxt->namespaces[i]->href);
3103 }
3104 }
Owen Taylor3473f882001-02-23 17:55:21 +00003105
3106 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
3107}
3108
3109/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003110 * xmlXPathRegisteredNsCleanup:
Owen Taylor3473f882001-02-23 17:55:21 +00003111 * @ctxt: the XPath context
3112 *
3113 * Cleanup the XPath context data associated to registered variables
3114 */
3115void
3116xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
3117 if (ctxt == NULL)
3118 return;
3119
Daniel Veillard42766c02002-08-22 20:52:17 +00003120 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
Owen Taylor3473f882001-02-23 17:55:21 +00003121 ctxt->nsHash = NULL;
3122}
3123
3124/************************************************************************
3125 * *
3126 * Routines to handle Values *
3127 * *
3128 ************************************************************************/
3129
William M. Brack08171912003-12-29 02:52:11 +00003130/* Allocations are terrible, one needs to optimize all this !!! */
Owen Taylor3473f882001-02-23 17:55:21 +00003131
3132/**
3133 * xmlXPathNewFloat:
3134 * @val: the double value
3135 *
3136 * Create a new xmlXPathObjectPtr of type double and of value @val
3137 *
3138 * Returns the newly created object.
3139 */
3140xmlXPathObjectPtr
3141xmlXPathNewFloat(double val) {
3142 xmlXPathObjectPtr ret;
3143
3144 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3145 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003146 xmlXPathErrMemory(NULL, "creating float object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003147 return(NULL);
3148 }
3149 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3150 ret->type = XPATH_NUMBER;
3151 ret->floatval = val;
3152 return(ret);
3153}
3154
3155/**
3156 * xmlXPathNewBoolean:
3157 * @val: the boolean value
3158 *
3159 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3160 *
3161 * Returns the newly created object.
3162 */
3163xmlXPathObjectPtr
3164xmlXPathNewBoolean(int val) {
3165 xmlXPathObjectPtr ret;
3166
3167 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3168 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003169 xmlXPathErrMemory(NULL, "creating boolean object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003170 return(NULL);
3171 }
3172 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3173 ret->type = XPATH_BOOLEAN;
3174 ret->boolval = (val != 0);
3175 return(ret);
3176}
3177
3178/**
3179 * xmlXPathNewString:
3180 * @val: the xmlChar * value
3181 *
3182 * Create a new xmlXPathObjectPtr of type string and of value @val
3183 *
3184 * Returns the newly created object.
3185 */
3186xmlXPathObjectPtr
3187xmlXPathNewString(const xmlChar *val) {
3188 xmlXPathObjectPtr ret;
3189
3190 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3191 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003192 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003193 return(NULL);
3194 }
3195 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3196 ret->type = XPATH_STRING;
3197 if (val != NULL)
3198 ret->stringval = xmlStrdup(val);
3199 else
3200 ret->stringval = xmlStrdup((const xmlChar *)"");
3201 return(ret);
3202}
3203
3204/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003205 * xmlXPathWrapString:
3206 * @val: the xmlChar * value
3207 *
3208 * Wraps the @val string into an XPath object.
3209 *
3210 * Returns the newly created object.
3211 */
3212xmlXPathObjectPtr
3213xmlXPathWrapString (xmlChar *val) {
3214 xmlXPathObjectPtr ret;
3215
3216 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3217 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003218 xmlXPathErrMemory(NULL, "creating string object\n");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003219 return(NULL);
3220 }
3221 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3222 ret->type = XPATH_STRING;
3223 ret->stringval = val;
3224 return(ret);
3225}
3226
3227/**
Owen Taylor3473f882001-02-23 17:55:21 +00003228 * xmlXPathNewCString:
3229 * @val: the char * value
3230 *
3231 * Create a new xmlXPathObjectPtr of type string and of value @val
3232 *
3233 * Returns the newly created object.
3234 */
3235xmlXPathObjectPtr
3236xmlXPathNewCString(const char *val) {
3237 xmlXPathObjectPtr ret;
3238
3239 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3240 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003241 xmlXPathErrMemory(NULL, "creating string object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003242 return(NULL);
3243 }
3244 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3245 ret->type = XPATH_STRING;
3246 ret->stringval = xmlStrdup(BAD_CAST val);
3247 return(ret);
3248}
3249
3250/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003251 * xmlXPathWrapCString:
3252 * @val: the char * value
3253 *
3254 * Wraps a string into an XPath object.
3255 *
3256 * Returns the newly created object.
3257 */
3258xmlXPathObjectPtr
3259xmlXPathWrapCString (char * val) {
3260 return(xmlXPathWrapString((xmlChar *)(val)));
3261}
3262
3263/**
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003264 * xmlXPathWrapExternal:
3265 * @val: the user data
3266 *
3267 * Wraps the @val data into an XPath object.
3268 *
3269 * Returns the newly created object.
3270 */
3271xmlXPathObjectPtr
3272xmlXPathWrapExternal (void *val) {
3273 xmlXPathObjectPtr ret;
3274
3275 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3276 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003277 xmlXPathErrMemory(NULL, "creating user object\n");
Thomas Broyerf06a3d82001-07-16 04:52:57 +00003278 return(NULL);
3279 }
3280 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3281 ret->type = XPATH_USERS;
3282 ret->user = val;
3283 return(ret);
3284}
3285
3286/**
Owen Taylor3473f882001-02-23 17:55:21 +00003287 * xmlXPathObjectCopy:
3288 * @val: the original object
3289 *
3290 * allocate a new copy of a given object
3291 *
3292 * Returns the newly created object.
3293 */
3294xmlXPathObjectPtr
3295xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3296 xmlXPathObjectPtr ret;
3297
3298 if (val == NULL)
3299 return(NULL);
3300
3301 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3302 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003303 xmlXPathErrMemory(NULL, "copying object\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003304 return(NULL);
3305 }
3306 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3307 switch (val->type) {
3308 case XPATH_BOOLEAN:
3309 case XPATH_NUMBER:
3310 case XPATH_POINT:
3311 case XPATH_RANGE:
3312 break;
3313 case XPATH_STRING:
3314 ret->stringval = xmlStrdup(val->stringval);
3315 break;
3316 case XPATH_XSLT_TREE:
William M. Bracke9449c52004-07-11 14:41:20 +00003317#if 0
3318/*
3319 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
3320 this previous handling is no longer correct, and can cause some serious
3321 problems (ref. bug 145547)
3322*/
Owen Taylor3473f882001-02-23 17:55:21 +00003323 if ((val->nodesetval != NULL) &&
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003324 (val->nodesetval->nodeTab != NULL)) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003325 xmlNodePtr cur, tmp;
3326 xmlDocPtr top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003327
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003328 ret->boolval = 1;
Daniel Veillard9adc0462003-03-24 18:39:54 +00003329 top = xmlNewDoc(NULL);
3330 top->name = (char *)
3331 xmlStrdup(val->nodesetval->nodeTab[0]->name);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003332 ret->user = top;
3333 if (top != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003334 top->doc = top;
Daniel Veillardef0b4502003-03-24 13:57:34 +00003335 cur = val->nodesetval->nodeTab[0]->children;
3336 while (cur != NULL) {
Daniel Veillard9adc0462003-03-24 18:39:54 +00003337 tmp = xmlDocCopyNode(cur, top, 1);
3338 xmlAddChild((xmlNodePtr) top, tmp);
Daniel Veillardef0b4502003-03-24 13:57:34 +00003339 cur = cur->next;
3340 }
3341 }
William M. Bracke9449c52004-07-11 14:41:20 +00003342
Daniel Veillard9adc0462003-03-24 18:39:54 +00003343 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003344 } else
Owen Taylor3473f882001-02-23 17:55:21 +00003345 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003346 /* Deallocate the copied tree value */
Owen Taylor3473f882001-02-23 17:55:21 +00003347 break;
William M. Bracke9449c52004-07-11 14:41:20 +00003348#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003349 case XPATH_NODESET:
3350 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003351 /* Do not deallocate the copied tree value */
3352 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003353 break;
3354 case XPATH_LOCATIONSET:
3355#ifdef LIBXML_XPTR_ENABLED
3356 {
3357 xmlLocationSetPtr loc = val->user;
3358 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3359 break;
3360 }
3361#endif
Thomas Broyer47334c02001-10-07 16:41:52 +00003362 case XPATH_USERS:
3363 ret->user = val->user;
3364 break;
3365 case XPATH_UNDEFINED:
Owen Taylor3473f882001-02-23 17:55:21 +00003366 xmlGenericError(xmlGenericErrorContext,
3367 "xmlXPathObjectCopy: unsupported type %d\n",
3368 val->type);
3369 break;
3370 }
3371 return(ret);
3372}
3373
3374/**
3375 * xmlXPathFreeObject:
3376 * @obj: the object to free
3377 *
3378 * Free up an xmlXPathObjectPtr object.
3379 */
3380void
3381xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3382 if (obj == NULL) return;
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003383 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillard77851712001-02-27 21:54:07 +00003384 if (obj->boolval) {
William M. Bracke9449c52004-07-11 14:41:20 +00003385#if 0
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003386 if (obj->user != NULL) {
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00003387 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillard38bf6f02002-03-16 22:03:31 +00003388 xmlFreeNodeList((xmlNodePtr) obj->user);
William M. Bracke9449c52004-07-11 14:41:20 +00003389 } else
3390#endif
3391 if (obj->nodesetval != NULL)
Daniel Veillard77851712001-02-27 21:54:07 +00003392 xmlXPathFreeValueTree(obj->nodesetval);
3393 } else {
3394 if (obj->nodesetval != NULL)
3395 xmlXPathFreeNodeSet(obj->nodesetval);
3396 }
Owen Taylor3473f882001-02-23 17:55:21 +00003397#ifdef LIBXML_XPTR_ENABLED
3398 } else if (obj->type == XPATH_LOCATIONSET) {
3399 if (obj->user != NULL)
3400 xmlXPtrFreeLocationSet(obj->user);
3401#endif
3402 } else if (obj->type == XPATH_STRING) {
3403 if (obj->stringval != NULL)
3404 xmlFree(obj->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00003405 }
3406
Owen Taylor3473f882001-02-23 17:55:21 +00003407 xmlFree(obj);
3408}
3409
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003410
3411/************************************************************************
3412 * *
3413 * Type Casting Routines *
3414 * *
3415 ************************************************************************/
3416
3417/**
3418 * xmlXPathCastBooleanToString:
3419 * @val: a boolean
3420 *
3421 * Converts a boolean to its string value.
3422 *
3423 * Returns a newly allocated string.
3424 */
3425xmlChar *
3426xmlXPathCastBooleanToString (int val) {
3427 xmlChar *ret;
3428 if (val)
3429 ret = xmlStrdup((const xmlChar *) "true");
3430 else
3431 ret = xmlStrdup((const xmlChar *) "false");
3432 return(ret);
3433}
3434
3435/**
3436 * xmlXPathCastNumberToString:
3437 * @val: a number
3438 *
3439 * Converts a number to its string value.
3440 *
3441 * Returns a newly allocated string.
3442 */
3443xmlChar *
3444xmlXPathCastNumberToString (double val) {
3445 xmlChar *ret;
Daniel Veillardcda96922001-08-21 10:56:31 +00003446 switch (xmlXPathIsInf(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003447 case 1:
Daniel Veillard5fc1f082002-03-27 09:05:40 +00003448 ret = xmlStrdup((const xmlChar *) "Infinity");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003449 break;
3450 case -1:
3451 ret = xmlStrdup((const xmlChar *) "-Infinity");
3452 break;
3453 default:
Daniel Veillardcda96922001-08-21 10:56:31 +00003454 if (xmlXPathIsNaN(val)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003455 ret = xmlStrdup((const xmlChar *) "NaN");
Daniel Veillardd30be4a2002-03-28 18:25:31 +00003456 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3457 ret = xmlStrdup((const xmlChar *) "0");
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003458 } else {
3459 /* could be improved */
3460 char buf[100];
3461 xmlXPathFormatNumber(val, buf, 100);
3462 ret = xmlStrdup((const xmlChar *) buf);
3463 }
3464 }
3465 return(ret);
3466}
3467
3468/**
3469 * xmlXPathCastNodeToString:
3470 * @node: a node
3471 *
3472 * Converts a node to its string value.
3473 *
3474 * Returns a newly allocated string.
3475 */
3476xmlChar *
3477xmlXPathCastNodeToString (xmlNodePtr node) {
3478 return(xmlNodeGetContent(node));
3479}
3480
3481/**
3482 * xmlXPathCastNodeSetToString:
3483 * @ns: a node-set
3484 *
3485 * Converts a node-set to its string value.
3486 *
3487 * Returns a newly allocated string.
3488 */
3489xmlChar *
3490xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3491 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3492 return(xmlStrdup((const xmlChar *) ""));
3493
3494 xmlXPathNodeSetSort(ns);
3495 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3496}
3497
3498/**
3499 * xmlXPathCastToString:
3500 * @val: an XPath object
3501 *
3502 * Converts an existing object to its string() equivalent
3503 *
3504 * Returns the string value of the object, NULL in case of error.
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003505 * A new string is allocated only if needed (@val isn't a
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003506 * string object).
3507 */
3508xmlChar *
3509xmlXPathCastToString(xmlXPathObjectPtr val) {
3510 xmlChar *ret = NULL;
3511
3512 if (val == NULL)
3513 return(xmlStrdup((const xmlChar *) ""));
3514 switch (val->type) {
3515 case XPATH_UNDEFINED:
3516#ifdef DEBUG_EXPR
3517 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3518#endif
3519 ret = xmlStrdup((const xmlChar *) "");
3520 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003521 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003522 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003523 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3524 break;
3525 case XPATH_STRING:
Daniel Veillard4e2df542002-03-22 12:23:14 +00003526 return(xmlStrdup(val->stringval));
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003527 case XPATH_BOOLEAN:
3528 ret = xmlXPathCastBooleanToString(val->boolval);
3529 break;
3530 case XPATH_NUMBER: {
3531 ret = xmlXPathCastNumberToString(val->floatval);
3532 break;
3533 }
3534 case XPATH_USERS:
3535 case XPATH_POINT:
3536 case XPATH_RANGE:
3537 case XPATH_LOCATIONSET:
3538 TODO
3539 ret = xmlStrdup((const xmlChar *) "");
3540 break;
3541 }
3542 return(ret);
3543}
3544
3545/**
3546 * xmlXPathConvertString:
3547 * @val: an XPath object
3548 *
3549 * Converts an existing object to its string() equivalent
3550 *
3551 * Returns the new object, the old one is freed (or the operation
3552 * is done directly on @val)
3553 */
3554xmlXPathObjectPtr
3555xmlXPathConvertString(xmlXPathObjectPtr val) {
3556 xmlChar *res = NULL;
3557
3558 if (val == NULL)
3559 return(xmlXPathNewCString(""));
3560
3561 switch (val->type) {
3562 case XPATH_UNDEFINED:
3563#ifdef DEBUG_EXPR
3564 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3565#endif
3566 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003567 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003568 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003569 res = xmlXPathCastNodeSetToString(val->nodesetval);
3570 break;
3571 case XPATH_STRING:
3572 return(val);
3573 case XPATH_BOOLEAN:
3574 res = xmlXPathCastBooleanToString(val->boolval);
3575 break;
3576 case XPATH_NUMBER:
3577 res = xmlXPathCastNumberToString(val->floatval);
3578 break;
3579 case XPATH_USERS:
3580 case XPATH_POINT:
3581 case XPATH_RANGE:
3582 case XPATH_LOCATIONSET:
3583 TODO;
3584 break;
3585 }
3586 xmlXPathFreeObject(val);
3587 if (res == NULL)
3588 return(xmlXPathNewCString(""));
3589 return(xmlXPathWrapString(res));
3590}
3591
3592/**
3593 * xmlXPathCastBooleanToNumber:
3594 * @val: a boolean
3595 *
3596 * Converts a boolean to its number value
3597 *
3598 * Returns the number value
3599 */
3600double
3601xmlXPathCastBooleanToNumber(int val) {
3602 if (val)
3603 return(1.0);
3604 return(0.0);
3605}
3606
3607/**
3608 * xmlXPathCastStringToNumber:
3609 * @val: a string
3610 *
3611 * Converts a string to its number value
3612 *
3613 * Returns the number value
3614 */
3615double
3616xmlXPathCastStringToNumber(const xmlChar * val) {
3617 return(xmlXPathStringEvalNumber(val));
3618}
3619
3620/**
3621 * xmlXPathCastNodeToNumber:
3622 * @node: a node
3623 *
3624 * Converts a node to its number value
3625 *
3626 * Returns the number value
3627 */
3628double
3629xmlXPathCastNodeToNumber (xmlNodePtr node) {
3630 xmlChar *strval;
3631 double ret;
3632
3633 if (node == NULL)
3634 return(xmlXPathNAN);
3635 strval = xmlXPathCastNodeToString(node);
3636 if (strval == NULL)
3637 return(xmlXPathNAN);
3638 ret = xmlXPathCastStringToNumber(strval);
3639 xmlFree(strval);
3640
3641 return(ret);
3642}
3643
3644/**
3645 * xmlXPathCastNodeSetToNumber:
3646 * @ns: a node-set
3647 *
3648 * Converts a node-set to its number value
3649 *
3650 * Returns the number value
3651 */
3652double
3653xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3654 xmlChar *str;
3655 double ret;
3656
3657 if (ns == NULL)
3658 return(xmlXPathNAN);
3659 str = xmlXPathCastNodeSetToString(ns);
3660 ret = xmlXPathCastStringToNumber(str);
3661 xmlFree(str);
3662 return(ret);
3663}
3664
3665/**
3666 * xmlXPathCastToNumber:
3667 * @val: an XPath object
3668 *
3669 * Converts an XPath object to its number value
3670 *
3671 * Returns the number value
3672 */
3673double
3674xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3675 double ret = 0.0;
3676
3677 if (val == NULL)
3678 return(xmlXPathNAN);
3679 switch (val->type) {
3680 case XPATH_UNDEFINED:
3681#ifdef DEGUB_EXPR
3682 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3683#endif
3684 ret = xmlXPathNAN;
3685 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003686 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003687 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003688 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3689 break;
3690 case XPATH_STRING:
3691 ret = xmlXPathCastStringToNumber(val->stringval);
3692 break;
3693 case XPATH_NUMBER:
3694 ret = val->floatval;
3695 break;
3696 case XPATH_BOOLEAN:
3697 ret = xmlXPathCastBooleanToNumber(val->boolval);
3698 break;
3699 case XPATH_USERS:
3700 case XPATH_POINT:
3701 case XPATH_RANGE:
3702 case XPATH_LOCATIONSET:
3703 TODO;
3704 ret = xmlXPathNAN;
3705 break;
3706 }
3707 return(ret);
3708}
3709
3710/**
3711 * xmlXPathConvertNumber:
3712 * @val: an XPath object
3713 *
3714 * Converts an existing object to its number() equivalent
3715 *
3716 * Returns the new object, the old one is freed (or the operation
3717 * is done directly on @val)
3718 */
3719xmlXPathObjectPtr
3720xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3721 xmlXPathObjectPtr ret;
3722
3723 if (val == NULL)
3724 return(xmlXPathNewFloat(0.0));
3725 if (val->type == XPATH_NUMBER)
3726 return(val);
3727 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3728 xmlXPathFreeObject(val);
3729 return(ret);
3730}
3731
3732/**
3733 * xmlXPathCastNumberToBoolean:
3734 * @val: a number
3735 *
3736 * Converts a number to its boolean value
3737 *
3738 * Returns the boolean value
3739 */
3740int
3741xmlXPathCastNumberToBoolean (double val) {
Daniel Veillardcda96922001-08-21 10:56:31 +00003742 if (xmlXPathIsNaN(val) || (val == 0.0))
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003743 return(0);
3744 return(1);
3745}
3746
3747/**
3748 * xmlXPathCastStringToBoolean:
3749 * @val: a string
3750 *
3751 * Converts a string to its boolean value
3752 *
3753 * Returns the boolean value
3754 */
3755int
3756xmlXPathCastStringToBoolean (const xmlChar *val) {
3757 if ((val == NULL) || (xmlStrlen(val) == 0))
3758 return(0);
3759 return(1);
3760}
3761
3762/**
3763 * xmlXPathCastNodeSetToBoolean:
3764 * @ns: a node-set
3765 *
3766 * Converts a node-set to its boolean value
3767 *
3768 * Returns the boolean value
3769 */
3770int
3771xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3772 if ((ns == NULL) || (ns->nodeNr == 0))
3773 return(0);
3774 return(1);
3775}
3776
3777/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003778 * xmlXPathCastToBoolean:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003779 * @val: an XPath object
3780 *
3781 * Converts an XPath object to its boolean value
3782 *
3783 * Returns the boolean value
3784 */
3785int
3786xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3787 int ret = 0;
3788
3789 if (val == NULL)
3790 return(0);
3791 switch (val->type) {
3792 case XPATH_UNDEFINED:
3793#ifdef DEBUG_EXPR
3794 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3795#endif
3796 ret = 0;
3797 break;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003798 case XPATH_NODESET:
William M. Brack0c022ad2002-07-12 00:56:01 +00003799 case XPATH_XSLT_TREE:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003800 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3801 break;
3802 case XPATH_STRING:
3803 ret = xmlXPathCastStringToBoolean(val->stringval);
3804 break;
3805 case XPATH_NUMBER:
3806 ret = xmlXPathCastNumberToBoolean(val->floatval);
3807 break;
3808 case XPATH_BOOLEAN:
3809 ret = val->boolval;
3810 break;
3811 case XPATH_USERS:
3812 case XPATH_POINT:
3813 case XPATH_RANGE:
3814 case XPATH_LOCATIONSET:
3815 TODO;
3816 ret = 0;
3817 break;
3818 }
3819 return(ret);
3820}
3821
3822
3823/**
3824 * xmlXPathConvertBoolean:
3825 * @val: an XPath object
3826 *
3827 * Converts an existing object to its boolean() equivalent
3828 *
3829 * Returns the new object, the old one is freed (or the operation
3830 * is done directly on @val)
3831 */
3832xmlXPathObjectPtr
3833xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3834 xmlXPathObjectPtr ret;
3835
3836 if (val == NULL)
3837 return(xmlXPathNewBoolean(0));
3838 if (val->type == XPATH_BOOLEAN)
3839 return(val);
3840 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3841 xmlXPathFreeObject(val);
3842 return(ret);
3843}
3844
Owen Taylor3473f882001-02-23 17:55:21 +00003845/************************************************************************
3846 * *
3847 * Routines to handle XPath contexts *
3848 * *
3849 ************************************************************************/
3850
3851/**
3852 * xmlXPathNewContext:
3853 * @doc: the XML document
3854 *
3855 * Create a new xmlXPathContext
3856 *
Daniel Veillardaf43f632002-03-08 15:05:20 +00003857 * Returns the xmlXPathContext just allocated. The caller will need to free it.
Owen Taylor3473f882001-02-23 17:55:21 +00003858 */
3859xmlXPathContextPtr
3860xmlXPathNewContext(xmlDocPtr doc) {
3861 xmlXPathContextPtr ret;
3862
3863 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3864 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003865 xmlXPathErrMemory(NULL, "creating context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003866 return(NULL);
3867 }
3868 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3869 ret->doc = doc;
3870 ret->node = NULL;
3871
3872 ret->varHash = NULL;
3873
3874 ret->nb_types = 0;
3875 ret->max_types = 0;
3876 ret->types = NULL;
3877
3878 ret->funcHash = xmlHashCreate(0);
3879
3880 ret->nb_axis = 0;
3881 ret->max_axis = 0;
3882 ret->axis = NULL;
3883
3884 ret->nsHash = NULL;
3885 ret->user = NULL;
3886
3887 ret->contextSize = -1;
3888 ret->proximityPosition = -1;
3889
3890 xmlXPathRegisterAllFunctions(ret);
3891
3892 return(ret);
3893}
3894
3895/**
3896 * xmlXPathFreeContext:
3897 * @ctxt: the context to free
3898 *
3899 * Free up an xmlXPathContext
3900 */
3901void
3902xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3903 xmlXPathRegisteredNsCleanup(ctxt);
3904 xmlXPathRegisteredFuncsCleanup(ctxt);
3905 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00003906 xmlFree(ctxt);
3907}
3908
3909/************************************************************************
3910 * *
3911 * Routines to handle XPath parser contexts *
3912 * *
3913 ************************************************************************/
3914
3915#define CHECK_CTXT(ctxt) \
3916 if (ctxt == NULL) { \
3917 xmlGenericError(xmlGenericErrorContext, \
3918 "%s:%d Internal error: ctxt == NULL\n", \
3919 __FILE__, __LINE__); \
3920 } \
3921
3922
3923#define CHECK_CONTEXT(ctxt) \
3924 if (ctxt == NULL) { \
3925 xmlGenericError(xmlGenericErrorContext, \
3926 "%s:%d Internal error: no context\n", \
3927 __FILE__, __LINE__); \
3928 } \
3929 else if (ctxt->doc == NULL) { \
3930 xmlGenericError(xmlGenericErrorContext, \
3931 "%s:%d Internal error: no document\n", \
3932 __FILE__, __LINE__); \
3933 } \
3934 else if (ctxt->doc->children == NULL) { \
3935 xmlGenericError(xmlGenericErrorContext, \
3936 "%s:%d Internal error: document without root\n", \
3937 __FILE__, __LINE__); \
3938 } \
3939
3940
3941/**
3942 * xmlXPathNewParserContext:
3943 * @str: the XPath expression
3944 * @ctxt: the XPath context
3945 *
3946 * Create a new xmlXPathParserContext
3947 *
3948 * Returns the xmlXPathParserContext just allocated.
3949 */
3950xmlXPathParserContextPtr
3951xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3952 xmlXPathParserContextPtr ret;
3953
3954 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3955 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003956 xmlXPathErrMemory(ctxt, "creating parser context\n");
Owen Taylor3473f882001-02-23 17:55:21 +00003957 return(NULL);
3958 }
3959 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3960 ret->cur = ret->base = str;
3961 ret->context = ctxt;
3962
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003963 ret->comp = xmlXPathNewCompExpr();
3964 if (ret->comp == NULL) {
3965 xmlFree(ret->valueTab);
3966 xmlFree(ret);
3967 return(NULL);
3968 }
Daniel Veillard4773df22004-01-23 13:15:13 +00003969 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
3970 ret->comp->dict = ctxt->dict;
3971 xmlDictReference(ret->comp->dict);
3972 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003973
3974 return(ret);
3975}
3976
3977/**
3978 * xmlXPathCompParserContext:
3979 * @comp: the XPath compiled expression
3980 * @ctxt: the XPath context
3981 *
3982 * Create a new xmlXPathParserContext when processing a compiled expression
3983 *
3984 * Returns the xmlXPathParserContext just allocated.
3985 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003986static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003987xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3988 xmlXPathParserContextPtr ret;
3989
3990 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3991 if (ret == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00003992 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00003993 return(NULL);
3994 }
3995 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3996
Owen Taylor3473f882001-02-23 17:55:21 +00003997 /* Allocate the value stack */
3998 ret->valueTab = (xmlXPathObjectPtr *)
3999 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004000 if (ret->valueTab == NULL) {
4001 xmlFree(ret);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004002 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004003 return(NULL);
4004 }
Owen Taylor3473f882001-02-23 17:55:21 +00004005 ret->valueNr = 0;
4006 ret->valueMax = 10;
4007 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004008
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004009 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004010 ret->comp = comp;
4011
Owen Taylor3473f882001-02-23 17:55:21 +00004012 return(ret);
4013}
4014
4015/**
4016 * xmlXPathFreeParserContext:
4017 * @ctxt: the context to free
4018 *
4019 * Free up an xmlXPathParserContext
4020 */
4021void
4022xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
4023 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00004024 xmlFree(ctxt->valueTab);
4025 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00004026 if (ctxt->comp)
4027 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00004028 xmlFree(ctxt);
4029}
4030
4031/************************************************************************
4032 * *
4033 * The implicit core function library *
4034 * *
4035 ************************************************************************/
4036
Owen Taylor3473f882001-02-23 17:55:21 +00004037/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004038 * xmlXPathNodeValHash:
Daniel Veillardf06307e2001-07-03 10:35:50 +00004039 * @node: a node pointer
4040 *
4041 * Function computing the beginning of the string value of the node,
4042 * used to speed up comparisons
4043 *
4044 * Returns an int usable as a hash
4045 */
4046static unsigned int
4047xmlXPathNodeValHash(xmlNodePtr node) {
4048 int len = 2;
4049 const xmlChar * string = NULL;
4050 xmlNodePtr tmp = NULL;
4051 unsigned int ret = 0;
4052
4053 if (node == NULL)
4054 return(0);
4055
Daniel Veillard9adc0462003-03-24 18:39:54 +00004056 if (node->type == XML_DOCUMENT_NODE) {
4057 tmp = xmlDocGetRootElement((xmlDocPtr) node);
4058 if (tmp == NULL)
4059 node = node->children;
4060 else
4061 node = tmp;
4062
4063 if (node == NULL)
4064 return(0);
4065 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004066
4067 switch (node->type) {
4068 case XML_COMMENT_NODE:
4069 case XML_PI_NODE:
4070 case XML_CDATA_SECTION_NODE:
4071 case XML_TEXT_NODE:
4072 string = node->content;
4073 if (string == NULL)
4074 return(0);
4075 if (string[0] == 0)
4076 return(0);
4077 return(((unsigned int) string[0]) +
4078 (((unsigned int) string[1]) << 8));
4079 case XML_NAMESPACE_DECL:
4080 string = ((xmlNsPtr)node)->href;
4081 if (string == NULL)
4082 return(0);
4083 if (string[0] == 0)
4084 return(0);
4085 return(((unsigned int) string[0]) +
4086 (((unsigned int) string[1]) << 8));
4087 case XML_ATTRIBUTE_NODE:
4088 tmp = ((xmlAttrPtr) node)->children;
4089 break;
4090 case XML_ELEMENT_NODE:
4091 tmp = node->children;
4092 break;
4093 default:
4094 return(0);
4095 }
4096 while (tmp != NULL) {
4097 switch (tmp->type) {
4098 case XML_COMMENT_NODE:
4099 case XML_PI_NODE:
4100 case XML_CDATA_SECTION_NODE:
4101 case XML_TEXT_NODE:
4102 string = tmp->content;
4103 break;
4104 case XML_NAMESPACE_DECL:
4105 string = ((xmlNsPtr)tmp)->href;
4106 break;
4107 default:
4108 break;
4109 }
4110 if ((string != NULL) && (string[0] != 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004111 if (len == 1) {
4112 return(ret + (((unsigned int) string[0]) << 8));
4113 }
4114 if (string[1] == 0) {
4115 len = 1;
4116 ret = (unsigned int) string[0];
4117 } else {
4118 return(((unsigned int) string[0]) +
4119 (((unsigned int) string[1]) << 8));
4120 }
4121 }
4122 /*
4123 * Skip to next node
4124 */
4125 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
4126 if (tmp->children->type != XML_ENTITY_DECL) {
4127 tmp = tmp->children;
4128 continue;
4129 }
4130 }
4131 if (tmp == node)
4132 break;
4133
4134 if (tmp->next != NULL) {
4135 tmp = tmp->next;
4136 continue;
4137 }
4138
4139 do {
4140 tmp = tmp->parent;
4141 if (tmp == NULL)
4142 break;
4143 if (tmp == node) {
4144 tmp = NULL;
4145 break;
4146 }
4147 if (tmp->next != NULL) {
4148 tmp = tmp->next;
4149 break;
4150 }
4151 } while (tmp != NULL);
4152 }
4153 return(ret);
4154}
4155
4156/**
4157 * xmlXPathStringHash:
4158 * @string: a string
4159 *
4160 * Function computing the beginning of the string value of the node,
4161 * used to speed up comparisons
4162 *
4163 * Returns an int usable as a hash
4164 */
4165static unsigned int
4166xmlXPathStringHash(const xmlChar * string) {
4167 if (string == NULL)
4168 return((unsigned int) 0);
4169 if (string[0] == 0)
4170 return(0);
4171 return(((unsigned int) string[0]) +
4172 (((unsigned int) string[1]) << 8));
4173}
4174
4175/**
Owen Taylor3473f882001-02-23 17:55:21 +00004176 * xmlXPathCompareNodeSetFloat:
4177 * @ctxt: the XPath Parser context
4178 * @inf: less than (1) or greater than (0)
4179 * @strict: is the comparison strict
4180 * @arg: the node set
4181 * @f: the value
4182 *
4183 * Implement the compare operation between a nodeset and a number
4184 * @ns < @val (1, 1, ...
4185 * @ns <= @val (1, 0, ...
4186 * @ns > @val (0, 1, ...
4187 * @ns >= @val (0, 0, ...
4188 *
4189 * If one object to be compared is a node-set and the other is a number,
4190 * then the comparison will be true if and only if there is a node in the
4191 * node-set such that the result of performing the comparison on the number
4192 * to be compared and on the result of converting the string-value of that
4193 * node to a number using the number function is true.
4194 *
4195 * Returns 0 or 1 depending on the results of the test.
4196 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004197static int
Owen Taylor3473f882001-02-23 17:55:21 +00004198xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4199 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4200 int i, ret = 0;
4201 xmlNodeSetPtr ns;
4202 xmlChar *str2;
4203
4204 if ((f == NULL) || (arg == NULL) ||
4205 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4206 xmlXPathFreeObject(arg);
4207 xmlXPathFreeObject(f);
4208 return(0);
4209 }
4210 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004211 if (ns != NULL) {
4212 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004213 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004214 if (str2 != NULL) {
4215 valuePush(ctxt,
4216 xmlXPathNewString(str2));
4217 xmlFree(str2);
4218 xmlXPathNumberFunction(ctxt, 1);
4219 valuePush(ctxt, xmlXPathObjectCopy(f));
4220 ret = xmlXPathCompareValues(ctxt, inf, strict);
4221 if (ret)
4222 break;
4223 }
4224 }
Owen Taylor3473f882001-02-23 17:55:21 +00004225 }
4226 xmlXPathFreeObject(arg);
4227 xmlXPathFreeObject(f);
4228 return(ret);
4229}
4230
4231/**
4232 * xmlXPathCompareNodeSetString:
4233 * @ctxt: the XPath Parser context
4234 * @inf: less than (1) or greater than (0)
4235 * @strict: is the comparison strict
4236 * @arg: the node set
4237 * @s: the value
4238 *
4239 * Implement the compare operation between a nodeset and a string
4240 * @ns < @val (1, 1, ...
4241 * @ns <= @val (1, 0, ...
4242 * @ns > @val (0, 1, ...
4243 * @ns >= @val (0, 0, ...
4244 *
4245 * If one object to be compared is a node-set and the other is a string,
4246 * then the comparison will be true if and only if there is a node in
4247 * the node-set such that the result of performing the comparison on the
4248 * string-value of the node and the other string is true.
4249 *
4250 * Returns 0 or 1 depending on the results of the test.
4251 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004252static int
Owen Taylor3473f882001-02-23 17:55:21 +00004253xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4254 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4255 int i, ret = 0;
4256 xmlNodeSetPtr ns;
4257 xmlChar *str2;
4258
4259 if ((s == NULL) || (arg == NULL) ||
4260 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4261 xmlXPathFreeObject(arg);
4262 xmlXPathFreeObject(s);
4263 return(0);
4264 }
4265 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00004266 if (ns != NULL) {
4267 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004268 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004269 if (str2 != NULL) {
4270 valuePush(ctxt,
4271 xmlXPathNewString(str2));
4272 xmlFree(str2);
4273 valuePush(ctxt, xmlXPathObjectCopy(s));
4274 ret = xmlXPathCompareValues(ctxt, inf, strict);
4275 if (ret)
4276 break;
4277 }
4278 }
Owen Taylor3473f882001-02-23 17:55:21 +00004279 }
4280 xmlXPathFreeObject(arg);
4281 xmlXPathFreeObject(s);
4282 return(ret);
4283}
4284
4285/**
4286 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004287 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00004288 * @strict: is the comparison strict
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004289 * @arg1: the first node set object
Owen Taylor3473f882001-02-23 17:55:21 +00004290 * @arg2: the second node set object
4291 *
4292 * Implement the compare operation on nodesets:
4293 *
4294 * If both objects to be compared are node-sets, then the comparison
4295 * will be true if and only if there is a node in the first node-set
4296 * and a node in the second node-set such that the result of performing
4297 * the comparison on the string-values of the two nodes is true.
4298 * ....
4299 * When neither object to be compared is a node-set and the operator
4300 * is <=, <, >= or >, then the objects are compared by converting both
4301 * objects to numbers and comparing the numbers according to IEEE 754.
4302 * ....
4303 * The number function converts its argument to a number as follows:
4304 * - a string that consists of optional whitespace followed by an
4305 * optional minus sign followed by a Number followed by whitespace
4306 * is converted to the IEEE 754 number that is nearest (according
4307 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4308 * represented by the string; any other string is converted to NaN
4309 *
4310 * Conclusion all nodes need to be converted first to their string value
4311 * and then the comparison must be done when possible
4312 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004313static int
4314xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00004315 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4316 int i, j, init = 0;
4317 double val1;
4318 double *values2;
4319 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00004320 xmlNodeSetPtr ns1;
4321 xmlNodeSetPtr ns2;
4322
4323 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004324 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4325 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004326 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004327 }
Owen Taylor3473f882001-02-23 17:55:21 +00004328 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00004329 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4330 xmlXPathFreeObject(arg1);
4331 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004332 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004333 }
Owen Taylor3473f882001-02-23 17:55:21 +00004334
4335 ns1 = arg1->nodesetval;
4336 ns2 = arg2->nodesetval;
4337
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004338 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004339 xmlXPathFreeObject(arg1);
4340 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004341 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004342 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00004343 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00004344 xmlXPathFreeObject(arg1);
4345 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004346 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004347 }
Owen Taylor3473f882001-02-23 17:55:21 +00004348
4349 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4350 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004351 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillard4dd93462001-04-02 15:16:19 +00004352 xmlXPathFreeObject(arg1);
4353 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004354 return(0);
4355 }
4356 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004357 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Daniel Veillardcda96922001-08-21 10:56:31 +00004358 if (xmlXPathIsNaN(val1))
Owen Taylor3473f882001-02-23 17:55:21 +00004359 continue;
4360 for (j = 0;j < ns2->nodeNr;j++) {
4361 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004362 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00004363 }
Daniel Veillardcda96922001-08-21 10:56:31 +00004364 if (xmlXPathIsNaN(values2[j]))
Owen Taylor3473f882001-02-23 17:55:21 +00004365 continue;
4366 if (inf && strict)
4367 ret = (val1 < values2[j]);
4368 else if (inf && !strict)
4369 ret = (val1 <= values2[j]);
4370 else if (!inf && strict)
4371 ret = (val1 > values2[j]);
4372 else if (!inf && !strict)
4373 ret = (val1 >= values2[j]);
4374 if (ret)
4375 break;
4376 }
4377 if (ret)
4378 break;
4379 init = 1;
4380 }
4381 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00004382 xmlXPathFreeObject(arg1);
4383 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00004384 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004385}
4386
4387/**
4388 * xmlXPathCompareNodeSetValue:
4389 * @ctxt: the XPath Parser context
4390 * @inf: less than (1) or greater than (0)
4391 * @strict: is the comparison strict
4392 * @arg: the node set
4393 * @val: the value
4394 *
4395 * Implement the compare operation between a nodeset and a value
4396 * @ns < @val (1, 1, ...
4397 * @ns <= @val (1, 0, ...
4398 * @ns > @val (0, 1, ...
4399 * @ns >= @val (0, 0, ...
4400 *
4401 * If one object to be compared is a node-set and the other is a boolean,
4402 * then the comparison will be true if and only if the result of performing
4403 * the comparison on the boolean and on the result of converting
4404 * the node-set to a boolean using the boolean function is true.
4405 *
4406 * Returns 0 or 1 depending on the results of the test.
4407 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004408static int
Owen Taylor3473f882001-02-23 17:55:21 +00004409xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4410 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4411 if ((val == NULL) || (arg == NULL) ||
4412 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4413 return(0);
4414
4415 switch(val->type) {
4416 case XPATH_NUMBER:
4417 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4418 case XPATH_NODESET:
4419 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004420 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00004421 case XPATH_STRING:
4422 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4423 case XPATH_BOOLEAN:
4424 valuePush(ctxt, arg);
4425 xmlXPathBooleanFunction(ctxt, 1);
4426 valuePush(ctxt, val);
4427 return(xmlXPathCompareValues(ctxt, inf, strict));
4428 default:
4429 TODO
Owen Taylor3473f882001-02-23 17:55:21 +00004430 }
4431 return(0);
4432}
4433
4434/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004435 * xmlXPathEqualNodeSetString:
Owen Taylor3473f882001-02-23 17:55:21 +00004436 * @arg: the nodeset object argument
4437 * @str: the string to compare to.
William M. Brack0c022ad2002-07-12 00:56:01 +00004438 * @neq: flag to show whether for '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004439 *
4440 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4441 * If one object to be compared is a node-set and the other is a string,
4442 * then the comparison will be true if and only if there is a node in
4443 * the node-set such that the result of performing the comparison on the
4444 * string-value of the node and the other string is true.
4445 *
4446 * Returns 0 or 1 depending on the results of the test.
4447 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004448static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004449xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004450{
Owen Taylor3473f882001-02-23 17:55:21 +00004451 int i;
4452 xmlNodeSetPtr ns;
4453 xmlChar *str2;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004454 unsigned int hash;
Owen Taylor3473f882001-02-23 17:55:21 +00004455
4456 if ((str == NULL) || (arg == NULL) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00004457 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4458 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004459 ns = arg->nodesetval;
William M. Brackc125a722003-11-16 08:06:19 +00004460 /*
4461 * A NULL nodeset compared with a string is always false
4462 * (since there is no node equal, and no node not equal)
4463 */
4464 if ((ns == NULL) || (ns->nodeNr <= 0) )
Daniel Veillardf06307e2001-07-03 10:35:50 +00004465 return (0);
William M. Brackc125a722003-11-16 08:06:19 +00004466 hash = xmlXPathStringHash(str);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004467 for (i = 0; i < ns->nodeNr; i++) {
4468 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4469 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4470 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4471 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004472 if (neq)
4473 continue;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004474 return (1);
Daniel Veillard9adc0462003-03-24 18:39:54 +00004475 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4476 if (neq)
4477 continue;
4478 return (1);
William M. Brack0c022ad2002-07-12 00:56:01 +00004479 } else if (neq) {
4480 if (str2 != NULL)
4481 xmlFree(str2);
4482 return (1);
4483 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004484 if (str2 != NULL)
4485 xmlFree(str2);
William M. Brack0c022ad2002-07-12 00:56:01 +00004486 } else if (neq)
4487 return (1);
Owen Taylor3473f882001-02-23 17:55:21 +00004488 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004489 return (0);
Owen Taylor3473f882001-02-23 17:55:21 +00004490}
4491
4492/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004493 * xmlXPathEqualNodeSetFloat:
Owen Taylor3473f882001-02-23 17:55:21 +00004494 * @arg: the nodeset object argument
4495 * @f: the float to compare to
William M. Brack0c022ad2002-07-12 00:56:01 +00004496 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004497 *
4498 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4499 * If one object to be compared is a node-set and the other is a number,
4500 * then the comparison will be true if and only if there is a node in
4501 * the node-set such that the result of performing the comparison on the
4502 * number to be compared and on the result of converting the string-value
4503 * of that node to a number using the number function is true.
4504 *
4505 * Returns 0 or 1 depending on the results of the test.
4506 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004507static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004508xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4509 xmlXPathObjectPtr arg, double f, int neq) {
4510 int i, ret=0;
4511 xmlNodeSetPtr ns;
4512 xmlChar *str2;
4513 xmlXPathObjectPtr val;
4514 double v;
Owen Taylor3473f882001-02-23 17:55:21 +00004515
4516 if ((arg == NULL) ||
4517 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4518 return(0);
4519
William M. Brack0c022ad2002-07-12 00:56:01 +00004520 ns = arg->nodesetval;
4521 if (ns != NULL) {
4522 for (i=0;i<ns->nodeNr;i++) {
4523 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4524 if (str2 != NULL) {
4525 valuePush(ctxt, xmlXPathNewString(str2));
4526 xmlFree(str2);
4527 xmlXPathNumberFunction(ctxt, 1);
4528 val = valuePop(ctxt);
4529 v = val->floatval;
4530 xmlXPathFreeObject(val);
4531 if (!xmlXPathIsNaN(v)) {
4532 if ((!neq) && (v==f)) {
4533 ret = 1;
4534 break;
4535 } else if ((neq) && (v!=f)) {
4536 ret = 1;
4537 break;
4538 }
4539 }
4540 }
4541 }
4542 }
4543
4544 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004545}
4546
4547
4548/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00004549 * xmlXPathEqualNodeSets:
Owen Taylor3473f882001-02-23 17:55:21 +00004550 * @arg1: first nodeset object argument
4551 * @arg2: second nodeset object argument
William M. Brack0c022ad2002-07-12 00:56:01 +00004552 * @neq: flag to show whether to test '=' (0) or '!=' (1)
Owen Taylor3473f882001-02-23 17:55:21 +00004553 *
William M. Brack0c022ad2002-07-12 00:56:01 +00004554 * Implement the equal / not equal operation on XPath nodesets:
4555 * @arg1 == @arg2 or @arg1 != @arg2
Owen Taylor3473f882001-02-23 17:55:21 +00004556 * If both objects to be compared are node-sets, then the comparison
4557 * will be true if and only if there is a node in the first node-set and
4558 * a node in the second node-set such that the result of performing the
4559 * comparison on the string-values of the two nodes is true.
4560 *
4561 * (needless to say, this is a costly operation)
4562 *
4563 * Returns 0 or 1 depending on the results of the test.
4564 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004565static int
William M. Brack0c022ad2002-07-12 00:56:01 +00004566xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
Owen Taylor3473f882001-02-23 17:55:21 +00004567 int i, j;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004568 unsigned int *hashs1;
4569 unsigned int *hashs2;
Owen Taylor3473f882001-02-23 17:55:21 +00004570 xmlChar **values1;
4571 xmlChar **values2;
4572 int ret = 0;
4573 xmlNodeSetPtr ns1;
4574 xmlNodeSetPtr ns2;
4575
4576 if ((arg1 == NULL) ||
4577 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4578 return(0);
4579 if ((arg2 == NULL) ||
4580 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4581 return(0);
4582
4583 ns1 = arg1->nodesetval;
4584 ns2 = arg2->nodesetval;
4585
Daniel Veillard911f49a2001-04-07 15:39:35 +00004586 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004587 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004588 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00004589 return(0);
4590
4591 /*
William M. Brack0c022ad2002-07-12 00:56:01 +00004592 * for equal, check if there is a node pertaining to both sets
Owen Taylor3473f882001-02-23 17:55:21 +00004593 */
William M. Brack0c022ad2002-07-12 00:56:01 +00004594 if (neq == 0)
4595 for (i = 0;i < ns1->nodeNr;i++)
4596 for (j = 0;j < ns2->nodeNr;j++)
4597 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4598 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00004599
4600 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004601 if (values1 == NULL) {
4602 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Owen Taylor3473f882001-02-23 17:55:21 +00004603 return(0);
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004604 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004605 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4606 if (hashs1 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004607 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004608 xmlFree(values1);
4609 return(0);
4610 }
Owen Taylor3473f882001-02-23 17:55:21 +00004611 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4612 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4613 if (values2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004614 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004615 xmlFree(hashs1);
Owen Taylor3473f882001-02-23 17:55:21 +00004616 xmlFree(values1);
4617 return(0);
4618 }
Daniel Veillardf06307e2001-07-03 10:35:50 +00004619 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4620 if (hashs2 == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +00004621 xmlXPathErrMemory(NULL, "comparing nodesets\n");
Daniel Veillardf06307e2001-07-03 10:35:50 +00004622 xmlFree(hashs1);
4623 xmlFree(values1);
4624 xmlFree(values2);
4625 return(0);
4626 }
Owen Taylor3473f882001-02-23 17:55:21 +00004627 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4628 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004629 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00004630 for (j = 0;j < ns2->nodeNr;j++) {
4631 if (i == 0)
Daniel Veillardf06307e2001-07-03 10:35:50 +00004632 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004633 if (hashs1[i] != hashs2[j]) {
4634 if (neq) {
4635 ret = 1;
4636 break;
4637 }
4638 }
4639 else {
Daniel Veillardf06307e2001-07-03 10:35:50 +00004640 if (values1[i] == NULL)
4641 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4642 if (values2[j] == NULL)
4643 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
William M. Brack0c022ad2002-07-12 00:56:01 +00004644 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
Daniel Veillardf06307e2001-07-03 10:35:50 +00004645 if (ret)
4646 break;
4647 }
Owen Taylor3473f882001-02-23 17:55:21 +00004648 }
4649 if (ret)
4650 break;
4651 }
4652 for (i = 0;i < ns1->nodeNr;i++)
4653 if (values1[i] != NULL)
4654 xmlFree(values1[i]);
4655 for (j = 0;j < ns2->nodeNr;j++)
4656 if (values2[j] != NULL)
4657 xmlFree(values2[j]);
4658 xmlFree(values1);
4659 xmlFree(values2);
Daniel Veillardf06307e2001-07-03 10:35:50 +00004660 xmlFree(hashs1);
4661 xmlFree(hashs2);
Owen Taylor3473f882001-02-23 17:55:21 +00004662 return(ret);
4663}
4664
William M. Brack0c022ad2002-07-12 00:56:01 +00004665static int
4666xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4667 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
Owen Taylor3473f882001-02-23 17:55:21 +00004668 int ret = 0;
William M. Brack0c022ad2002-07-12 00:56:01 +00004669 /*
4670 *At this point we are assured neither arg1 nor arg2
4671 *is a nodeset, so we can just pick the appropriate routine.
4672 */
Owen Taylor3473f882001-02-23 17:55:21 +00004673 switch (arg1->type) {
4674 case XPATH_UNDEFINED:
4675#ifdef DEBUG_EXPR
4676 xmlGenericError(xmlGenericErrorContext,
4677 "Equal: undefined\n");
4678#endif
4679 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004680 case XPATH_BOOLEAN:
4681 switch (arg2->type) {
4682 case XPATH_UNDEFINED:
4683#ifdef DEBUG_EXPR
4684 xmlGenericError(xmlGenericErrorContext,
4685 "Equal: undefined\n");
4686#endif
4687 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004688 case XPATH_BOOLEAN:
4689#ifdef DEBUG_EXPR
4690 xmlGenericError(xmlGenericErrorContext,
4691 "Equal: %d boolean %d \n",
4692 arg1->boolval, arg2->boolval);
4693#endif
4694 ret = (arg1->boolval == arg2->boolval);
4695 break;
4696 case XPATH_NUMBER:
William M. Brackef61d202002-07-19 08:32:00 +00004697 ret = (arg1->boolval ==
4698 xmlXPathCastNumberToBoolean(arg2->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004699 break;
4700 case XPATH_STRING:
4701 if ((arg2->stringval == NULL) ||
4702 (arg2->stringval[0] == 0)) ret = 0;
4703 else
4704 ret = 1;
4705 ret = (arg1->boolval == ret);
4706 break;
4707 case XPATH_USERS:
4708 case XPATH_POINT:
4709 case XPATH_RANGE:
4710 case XPATH_LOCATIONSET:
4711 TODO
4712 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004713 case XPATH_NODESET:
4714 case XPATH_XSLT_TREE:
4715 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004716 }
4717 break;
4718 case XPATH_NUMBER:
4719 switch (arg2->type) {
4720 case XPATH_UNDEFINED:
4721#ifdef DEBUG_EXPR
4722 xmlGenericError(xmlGenericErrorContext,
4723 "Equal: undefined\n");
4724#endif
4725 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004726 case XPATH_BOOLEAN:
William M. Brackef61d202002-07-19 08:32:00 +00004727 ret = (arg2->boolval==
4728 xmlXPathCastNumberToBoolean(arg1->floatval));
Owen Taylor3473f882001-02-23 17:55:21 +00004729 break;
4730 case XPATH_STRING:
4731 valuePush(ctxt, arg2);
4732 xmlXPathNumberFunction(ctxt, 1);
4733 arg2 = valuePop(ctxt);
4734 /* no break on purpose */
4735 case XPATH_NUMBER:
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004736 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004737 if (xmlXPathIsNaN(arg1->floatval) ||
4738 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004739 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004740 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4741 if (xmlXPathIsInf(arg2->floatval) == 1)
4742 ret = 1;
4743 else
4744 ret = 0;
4745 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4746 if (xmlXPathIsInf(arg2->floatval) == -1)
4747 ret = 1;
4748 else
4749 ret = 0;
4750 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4751 if (xmlXPathIsInf(arg1->floatval) == 1)
4752 ret = 1;
4753 else
4754 ret = 0;
4755 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4756 if (xmlXPathIsInf(arg1->floatval) == -1)
4757 ret = 1;
4758 else
4759 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004760 } else {
4761 ret = (arg1->floatval == arg2->floatval);
4762 }
Owen Taylor3473f882001-02-23 17:55:21 +00004763 break;
4764 case XPATH_USERS:
4765 case XPATH_POINT:
4766 case XPATH_RANGE:
4767 case XPATH_LOCATIONSET:
4768 TODO
4769 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004770 case XPATH_NODESET:
4771 case XPATH_XSLT_TREE:
4772 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004773 }
4774 break;
4775 case XPATH_STRING:
4776 switch (arg2->type) {
4777 case XPATH_UNDEFINED:
4778#ifdef DEBUG_EXPR
4779 xmlGenericError(xmlGenericErrorContext,
4780 "Equal: undefined\n");
4781#endif
4782 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004783 case XPATH_BOOLEAN:
4784 if ((arg1->stringval == NULL) ||
4785 (arg1->stringval[0] == 0)) ret = 0;
4786 else
4787 ret = 1;
4788 ret = (arg2->boolval == ret);
4789 break;
4790 case XPATH_STRING:
4791 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4792 break;
4793 case XPATH_NUMBER:
4794 valuePush(ctxt, arg1);
4795 xmlXPathNumberFunction(ctxt, 1);
4796 arg1 = valuePop(ctxt);
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004797 /* Hand check NaN and Infinity equalities */
William M. Brack08171912003-12-29 02:52:11 +00004798 if (xmlXPathIsNaN(arg1->floatval) ||
4799 xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillard21458c82002-03-27 16:12:22 +00004800 ret = 0;
Daniel Veillardd30be4a2002-03-28 18:25:31 +00004801 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4802 if (xmlXPathIsInf(arg2->floatval) == 1)
4803 ret = 1;
4804 else
4805 ret = 0;
4806 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4807 if (xmlXPathIsInf(arg2->floatval) == -1)
4808 ret = 1;
4809 else
4810 ret = 0;
4811 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4812 if (xmlXPathIsInf(arg1->floatval) == 1)
4813 ret = 1;
4814 else
4815 ret = 0;
4816 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4817 if (xmlXPathIsInf(arg1->floatval) == -1)
4818 ret = 1;
4819 else
4820 ret = 0;
Daniel Veillard21458c82002-03-27 16:12:22 +00004821 } else {
4822 ret = (arg1->floatval == arg2->floatval);
4823 }
Owen Taylor3473f882001-02-23 17:55:21 +00004824 break;
4825 case XPATH_USERS:
4826 case XPATH_POINT:
4827 case XPATH_RANGE:
4828 case XPATH_LOCATIONSET:
4829 TODO
4830 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004831 case XPATH_NODESET:
4832 case XPATH_XSLT_TREE:
4833 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004834 }
4835 break;
4836 case XPATH_USERS:
4837 case XPATH_POINT:
4838 case XPATH_RANGE:
4839 case XPATH_LOCATIONSET:
4840 TODO
4841 break;
William M. Brack0c022ad2002-07-12 00:56:01 +00004842 case XPATH_NODESET:
4843 case XPATH_XSLT_TREE:
4844 break;
Owen Taylor3473f882001-02-23 17:55:21 +00004845 }
4846 xmlXPathFreeObject(arg1);
4847 xmlXPathFreeObject(arg2);
4848 return(ret);
4849}
4850
William M. Brack0c022ad2002-07-12 00:56:01 +00004851/**
4852 * xmlXPathEqualValues:
4853 * @ctxt: the XPath Parser context
4854 *
4855 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4856 *
4857 * Returns 0 or 1 depending on the results of the test.
4858 */
4859int
4860xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4861 xmlXPathObjectPtr arg1, arg2, argtmp;
4862 int ret = 0;
4863
4864 arg2 = valuePop(ctxt);
4865 arg1 = valuePop(ctxt);
4866 if ((arg1 == NULL) || (arg2 == NULL)) {
4867 if (arg1 != NULL)
4868 xmlXPathFreeObject(arg1);
4869 else
4870 xmlXPathFreeObject(arg2);
4871 XP_ERROR0(XPATH_INVALID_OPERAND);
4872 }
4873
4874 if (arg1 == arg2) {
4875#ifdef DEBUG_EXPR
4876 xmlGenericError(xmlGenericErrorContext,
4877 "Equal: by pointer\n");
4878#endif
4879 return(1);
4880 }
4881
4882 /*
4883 *If either argument is a nodeset, it's a 'special case'
4884 */
4885 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4886 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4887 /*
4888 *Hack it to assure arg1 is the nodeset
4889 */
4890 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4891 argtmp = arg2;
4892 arg2 = arg1;
4893 arg1 = argtmp;
4894 }
4895 switch (arg2->type) {
4896 case XPATH_UNDEFINED:
4897#ifdef DEBUG_EXPR
4898 xmlGenericError(xmlGenericErrorContext,
4899 "Equal: undefined\n");
4900#endif
4901 break;
4902 case XPATH_NODESET:
4903 case XPATH_XSLT_TREE:
4904 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4905 break;
4906 case XPATH_BOOLEAN:
4907 if ((arg1->nodesetval == NULL) ||
4908 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4909 else
4910 ret = 1;
4911 ret = (ret == arg2->boolval);
4912 break;
4913 case XPATH_NUMBER:
4914 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4915 break;
4916 case XPATH_STRING:
4917 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4918 break;
4919 case XPATH_USERS:
4920 case XPATH_POINT:
4921 case XPATH_RANGE:
4922 case XPATH_LOCATIONSET:
4923 TODO
4924 break;
4925 }
4926 xmlXPathFreeObject(arg1);
4927 xmlXPathFreeObject(arg2);
4928 return(ret);
4929 }
4930
4931 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4932}
4933
4934/**
4935 * xmlXPathNotEqualValues:
4936 * @ctxt: the XPath Parser context
4937 *
4938 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4939 *
4940 * Returns 0 or 1 depending on the results of the test.
4941 */
4942int
4943xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4944 xmlXPathObjectPtr arg1, arg2, argtmp;
4945 int ret = 0;
4946
4947 arg2 = valuePop(ctxt);
4948 arg1 = valuePop(ctxt);
4949 if ((arg1 == NULL) || (arg2 == NULL)) {
4950 if (arg1 != NULL)
4951 xmlXPathFreeObject(arg1);
4952 else
4953 xmlXPathFreeObject(arg2);
4954 XP_ERROR0(XPATH_INVALID_OPERAND);
4955 }
4956
4957 if (arg1 == arg2) {
4958#ifdef DEBUG_EXPR
4959 xmlGenericError(xmlGenericErrorContext,
4960 "NotEqual: by pointer\n");
4961#endif
4962 return(0);
4963 }
4964
4965 /*
4966 *If either argument is a nodeset, it's a 'special case'
4967 */
4968 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4969 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4970 /*
4971 *Hack it to assure arg1 is the nodeset
4972 */
4973 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4974 argtmp = arg2;
4975 arg2 = arg1;
4976 arg1 = argtmp;
4977 }
4978 switch (arg2->type) {
4979 case XPATH_UNDEFINED:
4980#ifdef DEBUG_EXPR
4981 xmlGenericError(xmlGenericErrorContext,
4982 "NotEqual: undefined\n");
4983#endif
4984 break;
4985 case XPATH_NODESET:
4986 case XPATH_XSLT_TREE:
4987 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4988 break;
4989 case XPATH_BOOLEAN:
4990 if ((arg1->nodesetval == NULL) ||
4991 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4992 else
4993 ret = 1;
William M. Brackef61d202002-07-19 08:32:00 +00004994 ret = (ret != arg2->boolval);
William M. Brack0c022ad2002-07-12 00:56:01 +00004995 break;
4996 case XPATH_NUMBER:
4997 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4998 break;
4999 case XPATH_STRING:
5000 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
5001 break;
5002 case XPATH_USERS:
5003 case XPATH_POINT:
5004 case XPATH_RANGE:
5005 case XPATH_LOCATIONSET:
5006 TODO
5007 break;
5008 }
5009 xmlXPathFreeObject(arg1);
5010 xmlXPathFreeObject(arg2);
5011 return(ret);
5012 }
5013
5014 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5015}
Owen Taylor3473f882001-02-23 17:55:21 +00005016
5017/**
5018 * xmlXPathCompareValues:
5019 * @ctxt: the XPath Parser context
5020 * @inf: less than (1) or greater than (0)
5021 * @strict: is the comparison strict
5022 *
5023 * Implement the compare operation on XPath objects:
5024 * @arg1 < @arg2 (1, 1, ...
5025 * @arg1 <= @arg2 (1, 0, ...
5026 * @arg1 > @arg2 (0, 1, ...
5027 * @arg1 >= @arg2 (0, 0, ...
5028 *
5029 * When neither object to be compared is a node-set and the operator is
5030 * <=, <, >=, >, then the objects are compared by converted both objects
5031 * to numbers and comparing the numbers according to IEEE 754. The <
5032 * comparison will be true if and only if the first number is less than the
5033 * second number. The <= comparison will be true if and only if the first
5034 * number is less than or equal to the second number. The > comparison
5035 * will be true if and only if the first number is greater than the second
5036 * number. The >= comparison will be true if and only if the first number
5037 * is greater than or equal to the second number.
5038 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005039 * Returns 1 if the comparison succeeded, 0 if it failed
Owen Taylor3473f882001-02-23 17:55:21 +00005040 */
5041int
5042xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005043 int ret = 0, arg1i = 0, arg2i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005044 xmlXPathObjectPtr arg1, arg2;
5045
William M. Brack0c022ad2002-07-12 00:56:01 +00005046 arg2 = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005047 arg1 = valuePop(ctxt);
William M. Brack0c022ad2002-07-12 00:56:01 +00005048 if ((arg1 == NULL) || (arg2 == NULL)) {
5049 if (arg1 != NULL)
5050 xmlXPathFreeObject(arg1);
5051 else
5052 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005053 XP_ERROR0(XPATH_INVALID_OPERAND);
5054 }
5055
William M. Brack0c022ad2002-07-12 00:56:01 +00005056 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5057 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5058 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5059 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005060 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005061 } else {
William M. Brack0c022ad2002-07-12 00:56:01 +00005062 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005063 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5064 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00005065 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00005066 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5067 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00005068 }
5069 }
5070 return(ret);
5071 }
5072
5073 if (arg1->type != XPATH_NUMBER) {
5074 valuePush(ctxt, arg1);
5075 xmlXPathNumberFunction(ctxt, 1);
5076 arg1 = valuePop(ctxt);
5077 }
5078 if (arg1->type != XPATH_NUMBER) {
5079 xmlXPathFreeObject(arg1);
5080 xmlXPathFreeObject(arg2);
5081 XP_ERROR0(XPATH_INVALID_OPERAND);
5082 }
5083 if (arg2->type != XPATH_NUMBER) {
5084 valuePush(ctxt, arg2);
5085 xmlXPathNumberFunction(ctxt, 1);
5086 arg2 = valuePop(ctxt);
5087 }
5088 if (arg2->type != XPATH_NUMBER) {
5089 xmlXPathFreeObject(arg1);
5090 xmlXPathFreeObject(arg2);
5091 XP_ERROR0(XPATH_INVALID_OPERAND);
5092 }
5093 /*
5094 * Add tests for infinity and nan
5095 * => feedback on 3.4 for Inf and NaN
5096 */
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005097 /* Hand check NaN and Infinity comparisons */
Daniel Veillard21458c82002-03-27 16:12:22 +00005098 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005099 ret=0;
Daniel Veillard21458c82002-03-27 16:12:22 +00005100 } else {
Daniel Veillardd30be4a2002-03-28 18:25:31 +00005101 arg1i=xmlXPathIsInf(arg1->floatval);
5102 arg2i=xmlXPathIsInf(arg2->floatval);
5103 if (inf && strict) {
5104 if ((arg1i == -1 && arg2i != -1) ||
5105 (arg2i == 1 && arg1i != 1)) {
5106 ret = 1;
5107 } else if (arg1i == 0 && arg2i == 0) {
5108 ret = (arg1->floatval < arg2->floatval);
5109 } else {
5110 ret = 0;
5111 }
5112 }
5113 else if (inf && !strict) {
5114 if (arg1i == -1 || arg2i == 1) {
5115 ret = 1;
5116 } else if (arg1i == 0 && arg2i == 0) {
5117 ret = (arg1->floatval <= arg2->floatval);
5118 } else {
5119 ret = 0;
5120 }
5121 }
5122 else if (!inf && strict) {
5123 if ((arg1i == 1 && arg2i != 1) ||
5124 (arg2i == -1 && arg1i != -1)) {
5125 ret = 1;
5126 } else if (arg1i == 0 && arg2i == 0) {
5127 ret = (arg1->floatval > arg2->floatval);
5128 } else {
5129 ret = 0;
5130 }
5131 }
5132 else if (!inf && !strict) {
5133 if (arg1i == 1 || arg2i == -1) {
5134 ret = 1;
5135 } else if (arg1i == 0 && arg2i == 0) {
5136 ret = (arg1->floatval >= arg2->floatval);
5137 } else {
5138 ret = 0;
5139 }
5140 }
Daniel Veillard21458c82002-03-27 16:12:22 +00005141 }
Owen Taylor3473f882001-02-23 17:55:21 +00005142 xmlXPathFreeObject(arg1);
5143 xmlXPathFreeObject(arg2);
5144 return(ret);
5145}
5146
5147/**
5148 * xmlXPathValueFlipSign:
5149 * @ctxt: the XPath Parser context
5150 *
5151 * Implement the unary - operation on an XPath object
5152 * The numeric operators convert their operands to numbers as if
5153 * by calling the number function.
5154 */
5155void
5156xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005157 CAST_TO_NUMBER;
5158 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005159 if (xmlXPathIsNaN(ctxt->value->floatval))
5160 ctxt->value->floatval=xmlXPathNAN;
5161 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5162 ctxt->value->floatval=xmlXPathNINF;
5163 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5164 ctxt->value->floatval=xmlXPathPINF;
5165 else if (ctxt->value->floatval == 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005166 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5167 ctxt->value->floatval = xmlXPathNZERO;
5168 else
5169 ctxt->value->floatval = 0;
5170 }
5171 else
5172 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00005173}
5174
5175/**
5176 * xmlXPathAddValues:
5177 * @ctxt: the XPath Parser context
5178 *
5179 * Implement the add operation on XPath objects:
5180 * The numeric operators convert their operands to numbers as if
5181 * by calling the number function.
5182 */
5183void
5184xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5185 xmlXPathObjectPtr arg;
5186 double val;
5187
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005188 arg = valuePop(ctxt);
5189 if (arg == NULL)
5190 XP_ERROR(XPATH_INVALID_OPERAND);
5191 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005192 xmlXPathFreeObject(arg);
5193
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005194 CAST_TO_NUMBER;
5195 CHECK_TYPE(XPATH_NUMBER);
5196 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00005197}
5198
5199/**
5200 * xmlXPathSubValues:
5201 * @ctxt: the XPath Parser context
5202 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005203 * Implement the subtraction operation on XPath objects:
Owen Taylor3473f882001-02-23 17:55:21 +00005204 * The numeric operators convert their operands to numbers as if
5205 * by calling the number function.
5206 */
5207void
5208xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5209 xmlXPathObjectPtr arg;
5210 double val;
5211
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005212 arg = valuePop(ctxt);
5213 if (arg == NULL)
5214 XP_ERROR(XPATH_INVALID_OPERAND);
5215 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005216 xmlXPathFreeObject(arg);
5217
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005218 CAST_TO_NUMBER;
5219 CHECK_TYPE(XPATH_NUMBER);
5220 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005221}
5222
5223/**
5224 * xmlXPathMultValues:
5225 * @ctxt: the XPath Parser context
5226 *
5227 * Implement the multiply operation on XPath objects:
5228 * The numeric operators convert their operands to numbers as if
5229 * by calling the number function.
5230 */
5231void
5232xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5233 xmlXPathObjectPtr arg;
5234 double val;
5235
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005236 arg = valuePop(ctxt);
5237 if (arg == NULL)
5238 XP_ERROR(XPATH_INVALID_OPERAND);
5239 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005240 xmlXPathFreeObject(arg);
5241
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005242 CAST_TO_NUMBER;
5243 CHECK_TYPE(XPATH_NUMBER);
5244 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005245}
5246
5247/**
5248 * xmlXPathDivValues:
5249 * @ctxt: the XPath Parser context
5250 *
5251 * Implement the div operation on XPath objects @arg1 / @arg2:
5252 * The numeric operators convert their operands to numbers as if
5253 * by calling the number function.
5254 */
5255void
5256xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5257 xmlXPathObjectPtr arg;
5258 double val;
5259
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005260 arg = valuePop(ctxt);
5261 if (arg == NULL)
5262 XP_ERROR(XPATH_INVALID_OPERAND);
5263 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005264 xmlXPathFreeObject(arg);
5265
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005266 CAST_TO_NUMBER;
5267 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardeca82812002-04-24 11:42:02 +00005268 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5269 ctxt->value->floatval = xmlXPathNAN;
5270 else if (val == 0 && xmlXPathGetSign(val) != 0) {
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005271 if (ctxt->value->floatval == 0)
5272 ctxt->value->floatval = xmlXPathNAN;
5273 else if (ctxt->value->floatval > 0)
5274 ctxt->value->floatval = xmlXPathNINF;
5275 else if (ctxt->value->floatval < 0)
5276 ctxt->value->floatval = xmlXPathPINF;
5277 }
5278 else if (val == 0) {
Daniel Veillard5f4b5992002-02-20 10:22:49 +00005279 if (ctxt->value->floatval == 0)
5280 ctxt->value->floatval = xmlXPathNAN;
5281 else if (ctxt->value->floatval > 0)
5282 ctxt->value->floatval = xmlXPathPINF;
5283 else if (ctxt->value->floatval < 0)
5284 ctxt->value->floatval = xmlXPathNINF;
5285 } else
5286 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00005287}
5288
5289/**
5290 * xmlXPathModValues:
5291 * @ctxt: the XPath Parser context
5292 *
5293 * Implement the mod operation on XPath objects: @arg1 / @arg2
5294 * The numeric operators convert their operands to numbers as if
5295 * by calling the number function.
5296 */
5297void
5298xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5299 xmlXPathObjectPtr arg;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005300 double arg1, arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00005301
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005302 arg = valuePop(ctxt);
5303 if (arg == NULL)
5304 XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005305 arg2 = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00005306 xmlXPathFreeObject(arg);
5307
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005308 CAST_TO_NUMBER;
5309 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005310 arg1 = ctxt->value->floatval;
Daniel Veillard268fd1b2001-08-26 18:46:36 +00005311 if (arg2 == 0)
5312 ctxt->value->floatval = xmlXPathNAN;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005313 else {
Daniel Veillardfdc91562002-07-01 21:52:03 +00005314 ctxt->value->floatval = fmod(arg1, arg2);
Daniel Veillard5fc1f082002-03-27 09:05:40 +00005315 }
Owen Taylor3473f882001-02-23 17:55:21 +00005316}
5317
5318/************************************************************************
5319 * *
5320 * The traversal functions *
5321 * *
5322 ************************************************************************/
5323
Owen Taylor3473f882001-02-23 17:55:21 +00005324/*
5325 * A traversal function enumerates nodes along an axis.
5326 * Initially it must be called with NULL, and it indicates
5327 * termination on the axis by returning NULL.
5328 */
5329typedef xmlNodePtr (*xmlXPathTraversalFunction)
5330 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5331
5332/**
5333 * xmlXPathNextSelf:
5334 * @ctxt: the XPath Parser context
5335 * @cur: the current node in the traversal
5336 *
5337 * Traversal function for the "self" direction
5338 * The self axis contains just the context node itself
5339 *
5340 * Returns the next element following that axis
5341 */
5342xmlNodePtr
5343xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5344 if (cur == NULL)
5345 return(ctxt->context->node);
5346 return(NULL);
5347}
5348
5349/**
5350 * xmlXPathNextChild:
5351 * @ctxt: the XPath Parser context
5352 * @cur: the current node in the traversal
5353 *
5354 * Traversal function for the "child" direction
5355 * The child axis contains the children of the context node in document order.
5356 *
5357 * Returns the next element following that axis
5358 */
5359xmlNodePtr
5360xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5361 if (cur == NULL) {
5362 if (ctxt->context->node == NULL) return(NULL);
5363 switch (ctxt->context->node->type) {
5364 case XML_ELEMENT_NODE:
5365 case XML_TEXT_NODE:
5366 case XML_CDATA_SECTION_NODE:
5367 case XML_ENTITY_REF_NODE:
5368 case XML_ENTITY_NODE:
5369 case XML_PI_NODE:
5370 case XML_COMMENT_NODE:
5371 case XML_NOTATION_NODE:
5372 case XML_DTD_NODE:
5373 return(ctxt->context->node->children);
5374 case XML_DOCUMENT_NODE:
5375 case XML_DOCUMENT_TYPE_NODE:
5376 case XML_DOCUMENT_FRAG_NODE:
5377 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005378#ifdef LIBXML_DOCB_ENABLED
5379 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005380#endif
5381 return(((xmlDocPtr) ctxt->context->node)->children);
5382 case XML_ELEMENT_DECL:
5383 case XML_ATTRIBUTE_DECL:
5384 case XML_ENTITY_DECL:
5385 case XML_ATTRIBUTE_NODE:
5386 case XML_NAMESPACE_DECL:
5387 case XML_XINCLUDE_START:
5388 case XML_XINCLUDE_END:
5389 return(NULL);
5390 }
5391 return(NULL);
5392 }
5393 if ((cur->type == XML_DOCUMENT_NODE) ||
5394 (cur->type == XML_HTML_DOCUMENT_NODE))
5395 return(NULL);
5396 return(cur->next);
5397}
5398
5399/**
5400 * xmlXPathNextDescendant:
5401 * @ctxt: the XPath Parser context
5402 * @cur: the current node in the traversal
5403 *
5404 * Traversal function for the "descendant" direction
5405 * the descendant axis contains the descendants of the context node in document
5406 * order; a descendant is a child or a child of a child and so on.
5407 *
5408 * Returns the next element following that axis
5409 */
5410xmlNodePtr
5411xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5412 if (cur == NULL) {
5413 if (ctxt->context->node == NULL)
5414 return(NULL);
5415 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5416 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5417 return(NULL);
5418
5419 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5420 return(ctxt->context->doc->children);
5421 return(ctxt->context->node->children);
5422 }
5423
Daniel Veillard567e1b42001-08-01 15:53:47 +00005424 if (cur->children != NULL) {
Daniel Veillard68e9e742002-11-16 15:35:11 +00005425 /*
5426 * Do not descend on entities declarations
5427 */
5428 if (cur->children->type != XML_ENTITY_DECL) {
5429 cur = cur->children;
5430 /*
5431 * Skip DTDs
5432 */
5433 if (cur->type != XML_DTD_NODE)
5434 return(cur);
5435 }
Daniel Veillard567e1b42001-08-01 15:53:47 +00005436 }
5437
5438 if (cur == ctxt->context->node) return(NULL);
5439
Daniel Veillard68e9e742002-11-16 15:35:11 +00005440 while (cur->next != NULL) {
5441 cur = cur->next;
5442 if ((cur->type != XML_ENTITY_DECL) &&
5443 (cur->type != XML_DTD_NODE))
5444 return(cur);
5445 }
Owen Taylor3473f882001-02-23 17:55:21 +00005446
5447 do {
5448 cur = cur->parent;
5449 if (cur == NULL) return(NULL);
5450 if (cur == ctxt->context->node) return(NULL);
5451 if (cur->next != NULL) {
5452 cur = cur->next;
5453 return(cur);
5454 }
5455 } while (cur != NULL);
5456 return(cur);
5457}
5458
5459/**
5460 * xmlXPathNextDescendantOrSelf:
5461 * @ctxt: the XPath Parser context
5462 * @cur: the current node in the traversal
5463 *
5464 * Traversal function for the "descendant-or-self" direction
5465 * the descendant-or-self axis contains the context node and the descendants
5466 * of the context node in document order; thus the context node is the first
5467 * node on the axis, and the first child of the context node is the second node
5468 * on the axis
5469 *
5470 * Returns the next element following that axis
5471 */
5472xmlNodePtr
5473xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5474 if (cur == NULL) {
5475 if (ctxt->context->node == NULL)
5476 return(NULL);
5477 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5478 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5479 return(NULL);
5480 return(ctxt->context->node);
5481 }
5482
5483 return(xmlXPathNextDescendant(ctxt, cur));
5484}
5485
5486/**
5487 * xmlXPathNextParent:
5488 * @ctxt: the XPath Parser context
5489 * @cur: the current node in the traversal
5490 *
5491 * Traversal function for the "parent" direction
5492 * The parent axis contains the parent of the context node, if there is one.
5493 *
5494 * Returns the next element following that axis
5495 */
5496xmlNodePtr
5497xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5498 /*
5499 * the parent of an attribute or namespace node is the element
5500 * to which the attribute or namespace node is attached
5501 * Namespace handling !!!
5502 */
5503 if (cur == NULL) {
5504 if (ctxt->context->node == NULL) return(NULL);
5505 switch (ctxt->context->node->type) {
5506 case XML_ELEMENT_NODE:
5507 case XML_TEXT_NODE:
5508 case XML_CDATA_SECTION_NODE:
5509 case XML_ENTITY_REF_NODE:
5510 case XML_ENTITY_NODE:
5511 case XML_PI_NODE:
5512 case XML_COMMENT_NODE:
5513 case XML_NOTATION_NODE:
5514 case XML_DTD_NODE:
5515 case XML_ELEMENT_DECL:
5516 case XML_ATTRIBUTE_DECL:
5517 case XML_XINCLUDE_START:
5518 case XML_XINCLUDE_END:
5519 case XML_ENTITY_DECL:
5520 if (ctxt->context->node->parent == NULL)
5521 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005522 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005523 ((ctxt->context->node->parent->name[0] == ' ') ||
5524 (xmlStrEqual(ctxt->context->node->parent->name,
5525 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005526 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005527 return(ctxt->context->node->parent);
5528 case XML_ATTRIBUTE_NODE: {
5529 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5530
5531 return(att->parent);
5532 }
5533 case XML_DOCUMENT_NODE:
5534 case XML_DOCUMENT_TYPE_NODE:
5535 case XML_DOCUMENT_FRAG_NODE:
5536 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005537#ifdef LIBXML_DOCB_ENABLED
5538 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005539#endif
5540 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005541 case XML_NAMESPACE_DECL: {
5542 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5543
5544 if ((ns->next != NULL) &&
5545 (ns->next->type != XML_NAMESPACE_DECL))
5546 return((xmlNodePtr) ns->next);
Owen Taylor3473f882001-02-23 17:55:21 +00005547 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005548 }
Owen Taylor3473f882001-02-23 17:55:21 +00005549 }
5550 }
5551 return(NULL);
5552}
5553
5554/**
5555 * xmlXPathNextAncestor:
5556 * @ctxt: the XPath Parser context
5557 * @cur: the current node in the traversal
5558 *
5559 * Traversal function for the "ancestor" direction
5560 * the ancestor axis contains the ancestors of the context node; the ancestors
5561 * of the context node consist of the parent of context node and the parent's
5562 * parent and so on; the nodes are ordered in reverse document order; thus the
5563 * parent is the first node on the axis, and the parent's parent is the second
5564 * node on the axis
5565 *
5566 * Returns the next element following that axis
5567 */
5568xmlNodePtr
5569xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5570 /*
5571 * the parent of an attribute or namespace node is the element
5572 * to which the attribute or namespace node is attached
5573 * !!!!!!!!!!!!!
5574 */
5575 if (cur == NULL) {
5576 if (ctxt->context->node == NULL) return(NULL);
5577 switch (ctxt->context->node->type) {
5578 case XML_ELEMENT_NODE:
5579 case XML_TEXT_NODE:
5580 case XML_CDATA_SECTION_NODE:
5581 case XML_ENTITY_REF_NODE:
5582 case XML_ENTITY_NODE:
5583 case XML_PI_NODE:
5584 case XML_COMMENT_NODE:
5585 case XML_DTD_NODE:
5586 case XML_ELEMENT_DECL:
5587 case XML_ATTRIBUTE_DECL:
5588 case XML_ENTITY_DECL:
5589 case XML_NOTATION_NODE:
5590 case XML_XINCLUDE_START:
5591 case XML_XINCLUDE_END:
5592 if (ctxt->context->node->parent == NULL)
5593 return((xmlNodePtr) ctxt->context->doc);
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005594 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005595 ((ctxt->context->node->parent->name[0] == ' ') ||
5596 (xmlStrEqual(ctxt->context->node->parent->name,
5597 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005598 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005599 return(ctxt->context->node->parent);
5600 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005601 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00005602
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005603 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00005604 }
5605 case XML_DOCUMENT_NODE:
5606 case XML_DOCUMENT_TYPE_NODE:
5607 case XML_DOCUMENT_FRAG_NODE:
5608 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005609#ifdef LIBXML_DOCB_ENABLED
5610 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005611#endif
5612 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005613 case XML_NAMESPACE_DECL: {
5614 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5615
5616 if ((ns->next != NULL) &&
5617 (ns->next->type != XML_NAMESPACE_DECL))
5618 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005619 /* Bad, how did that namespace end up here ? */
Owen Taylor3473f882001-02-23 17:55:21 +00005620 return(NULL);
Daniel Veillard044fc6b2002-03-04 17:09:44 +00005621 }
Owen Taylor3473f882001-02-23 17:55:21 +00005622 }
5623 return(NULL);
5624 }
5625 if (cur == ctxt->context->doc->children)
5626 return((xmlNodePtr) ctxt->context->doc);
5627 if (cur == (xmlNodePtr) ctxt->context->doc)
5628 return(NULL);
5629 switch (cur->type) {
5630 case XML_ELEMENT_NODE:
5631 case XML_TEXT_NODE:
5632 case XML_CDATA_SECTION_NODE:
5633 case XML_ENTITY_REF_NODE:
5634 case XML_ENTITY_NODE:
5635 case XML_PI_NODE:
5636 case XML_COMMENT_NODE:
5637 case XML_NOTATION_NODE:
5638 case XML_DTD_NODE:
5639 case XML_ELEMENT_DECL:
5640 case XML_ATTRIBUTE_DECL:
5641 case XML_ENTITY_DECL:
5642 case XML_XINCLUDE_START:
5643 case XML_XINCLUDE_END:
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005644 if (cur->parent == NULL)
5645 return(NULL);
5646 if ((cur->parent->type == XML_ELEMENT_NODE) &&
Daniel Veillard652d8a92003-02-04 19:28:49 +00005647 ((cur->parent->name[0] == ' ') ||
5648 (xmlStrEqual(cur->parent->name,
5649 BAD_CAST "fake node libxslt"))))
Daniel Veillard8e7e1c02003-01-10 17:06:09 +00005650 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005651 return(cur->parent);
5652 case XML_ATTRIBUTE_NODE: {
5653 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5654
5655 return(att->parent);
5656 }
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005657 case XML_NAMESPACE_DECL: {
5658 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5659
5660 if ((ns->next != NULL) &&
5661 (ns->next->type != XML_NAMESPACE_DECL))
5662 return((xmlNodePtr) ns->next);
William M. Brack08171912003-12-29 02:52:11 +00005663 /* Bad, how did that namespace end up here ? */
Aleksey Sanindffd5c82002-05-31 04:24:13 +00005664 return(NULL);
5665 }
Owen Taylor3473f882001-02-23 17:55:21 +00005666 case XML_DOCUMENT_NODE:
5667 case XML_DOCUMENT_TYPE_NODE:
5668 case XML_DOCUMENT_FRAG_NODE:
5669 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00005670#ifdef LIBXML_DOCB_ENABLED
5671 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00005672#endif
5673 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005674 }
5675 return(NULL);
5676}
5677
5678/**
5679 * xmlXPathNextAncestorOrSelf:
5680 * @ctxt: the XPath Parser context
5681 * @cur: the current node in the traversal
5682 *
5683 * Traversal function for the "ancestor-or-self" direction
5684 * he ancestor-or-self axis contains the context node and ancestors of
5685 * the context node in reverse document order; thus the context node is
5686 * the first node on the axis, and the context node's parent the second;
5687 * parent here is defined the same as with the parent axis.
5688 *
5689 * Returns the next element following that axis
5690 */
5691xmlNodePtr
5692xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5693 if (cur == NULL)
5694 return(ctxt->context->node);
5695 return(xmlXPathNextAncestor(ctxt, cur));
5696}
5697
5698/**
5699 * xmlXPathNextFollowingSibling:
5700 * @ctxt: the XPath Parser context
5701 * @cur: the current node in the traversal
5702 *
5703 * Traversal function for the "following-sibling" direction
5704 * The following-sibling axis contains the following siblings of the context
5705 * node in document order.
5706 *
5707 * Returns the next element following that axis
5708 */
5709xmlNodePtr
5710xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5711 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5712 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5713 return(NULL);
5714 if (cur == (xmlNodePtr) ctxt->context->doc)
5715 return(NULL);
5716 if (cur == NULL)
5717 return(ctxt->context->node->next);
5718 return(cur->next);
5719}
5720
5721/**
5722 * xmlXPathNextPrecedingSibling:
5723 * @ctxt: the XPath Parser context
5724 * @cur: the current node in the traversal
5725 *
5726 * Traversal function for the "preceding-sibling" direction
5727 * The preceding-sibling axis contains the preceding siblings of the context
5728 * node in reverse document order; the first preceding sibling is first on the
5729 * axis; the sibling preceding that node is the second on the axis and so on.
5730 *
5731 * Returns the next element following that axis
5732 */
5733xmlNodePtr
5734xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5735 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5736 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5737 return(NULL);
5738 if (cur == (xmlNodePtr) ctxt->context->doc)
5739 return(NULL);
5740 if (cur == NULL)
5741 return(ctxt->context->node->prev);
Daniel Veillardf06307e2001-07-03 10:35:50 +00005742 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5743 cur = cur->prev;
5744 if (cur == NULL)
5745 return(ctxt->context->node->prev);
5746 }
Owen Taylor3473f882001-02-23 17:55:21 +00005747 return(cur->prev);
5748}
5749
5750/**
5751 * xmlXPathNextFollowing:
5752 * @ctxt: the XPath Parser context
5753 * @cur: the current node in the traversal
5754 *
5755 * Traversal function for the "following" direction
5756 * The following axis contains all nodes in the same document as the context
5757 * node that are after the context node in document order, excluding any
5758 * descendants and excluding attribute nodes and namespace nodes; the nodes
5759 * are ordered in document order
5760 *
5761 * Returns the next element following that axis
5762 */
5763xmlNodePtr
5764xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5765 if (cur != NULL && cur->children != NULL)
5766 return cur->children ;
5767 if (cur == NULL) cur = ctxt->context->node;
5768 if (cur == NULL) return(NULL) ; /* ERROR */
5769 if (cur->next != NULL) return(cur->next) ;
5770 do {
5771 cur = cur->parent;
5772 if (cur == NULL) return(NULL);
5773 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5774 if (cur->next != NULL) return(cur->next);
5775 } while (cur != NULL);
5776 return(cur);
5777}
5778
5779/*
5780 * xmlXPathIsAncestor:
5781 * @ancestor: the ancestor node
5782 * @node: the current node
5783 *
5784 * Check that @ancestor is a @node's ancestor
5785 *
5786 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5787 */
5788static int
5789xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5790 if ((ancestor == NULL) || (node == NULL)) return(0);
5791 /* nodes need to be in the same document */
5792 if (ancestor->doc != node->doc) return(0);
5793 /* avoid searching if ancestor or node is the root node */
5794 if (ancestor == (xmlNodePtr) node->doc) return(1);
5795 if (node == (xmlNodePtr) ancestor->doc) return(0);
5796 while (node->parent != NULL) {
5797 if (node->parent == ancestor)
5798 return(1);
5799 node = node->parent;
5800 }
5801 return(0);
5802}
5803
5804/**
5805 * xmlXPathNextPreceding:
5806 * @ctxt: the XPath Parser context
5807 * @cur: the current node in the traversal
5808 *
5809 * Traversal function for the "preceding" direction
5810 * the preceding axis contains all nodes in the same document as the context
5811 * node that are before the context node in document order, excluding any
5812 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5813 * ordered in reverse document order
5814 *
5815 * Returns the next element following that axis
5816 */
5817xmlNodePtr
Daniel Veillardf06307e2001-07-03 10:35:50 +00005818xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5819{
Owen Taylor3473f882001-02-23 17:55:21 +00005820 if (cur == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00005821 cur = ctxt->context->node;
5822 if (cur == NULL)
5823 return (NULL);
5824 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5825 cur = cur->prev;
Owen Taylor3473f882001-02-23 17:55:21 +00005826 do {
5827 if (cur->prev != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00005828 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5829 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005830 }
5831
5832 cur = cur->parent;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005833 if (cur == NULL)
5834 return (NULL);
5835 if (cur == ctxt->context->doc->children)
5836 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005837 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillardf06307e2001-07-03 10:35:50 +00005838 return (cur);
5839}
5840
5841/**
5842 * xmlXPathNextPrecedingInternal:
5843 * @ctxt: the XPath Parser context
5844 * @cur: the current node in the traversal
5845 *
5846 * Traversal function for the "preceding" direction
5847 * the preceding axis contains all nodes in the same document as the context
5848 * node that are before the context node in document order, excluding any
5849 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5850 * ordered in reverse document order
5851 * This is a faster implementation but internal only since it requires a
5852 * state kept in the parser context: ctxt->ancestor.
5853 *
5854 * Returns the next element following that axis
5855 */
5856static xmlNodePtr
5857xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5858 xmlNodePtr cur)
5859{
5860 if (cur == NULL) {
5861 cur = ctxt->context->node;
5862 if (cur == NULL)
5863 return (NULL);
William M. Brack40c22b42003-10-10 03:58:39 +00005864 if (cur->type == XML_NAMESPACE_DECL)
5865 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
Daniel Veillardf06307e2001-07-03 10:35:50 +00005866 ctxt->ancestor = cur->parent;
5867 }
5868 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5869 cur = cur->prev;
5870 while (cur->prev == NULL) {
5871 cur = cur->parent;
5872 if (cur == NULL)
5873 return (NULL);
5874 if (cur == ctxt->context->doc->children)
5875 return (NULL);
5876 if (cur != ctxt->ancestor)
5877 return (cur);
5878 ctxt->ancestor = cur->parent;
5879 }
5880 cur = cur->prev;
5881 while (cur->last != NULL)
5882 cur = cur->last;
5883 return (cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005884}
5885
5886/**
5887 * xmlXPathNextNamespace:
5888 * @ctxt: the XPath Parser context
5889 * @cur: the current attribute in the traversal
5890 *
5891 * Traversal function for the "namespace" direction
5892 * the namespace axis contains the namespace nodes of the context node;
5893 * the order of nodes on this axis is implementation-defined; the axis will
5894 * be empty unless the context node is an element
5895 *
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005896 * We keep the XML namespace node at the end of the list.
5897 *
Owen Taylor3473f882001-02-23 17:55:21 +00005898 * Returns the next element following that axis
5899 */
5900xmlNodePtr
5901xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5902 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardfdc91562002-07-01 21:52:03 +00005903 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005904 if (ctxt->context->tmpNsList != NULL)
5905 xmlFree(ctxt->context->tmpNsList);
5906 ctxt->context->tmpNsList =
Owen Taylor3473f882001-02-23 17:55:21 +00005907 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005908 ctxt->context->tmpNsNr = 0;
Daniel Veillardfdc91562002-07-01 21:52:03 +00005909 if (ctxt->context->tmpNsList != NULL) {
5910 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5911 ctxt->context->tmpNsNr++;
5912 }
5913 }
Daniel Veillard20ee8c02001-10-05 09:18:14 +00005914 return((xmlNodePtr) xmlXPathXMLNamespace);
Daniel Veillard7d7e3792001-07-30 13:42:13 +00005915 }
Daniel Veillardfdc91562002-07-01 21:52:03 +00005916 if (ctxt->context->tmpNsNr > 0) {
5917 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5918 } else {
5919 if (ctxt->context->tmpNsList != NULL)
5920 xmlFree(ctxt->context->tmpNsList);
5921 ctxt->context->tmpNsList = NULL;
5922 return(NULL);
5923 }
Owen Taylor3473f882001-02-23 17:55:21 +00005924}
5925
5926/**
5927 * xmlXPathNextAttribute:
5928 * @ctxt: the XPath Parser context
5929 * @cur: the current attribute in the traversal
5930 *
5931 * Traversal function for the "attribute" direction
5932 * TODO: support DTD inherited default attributes
5933 *
5934 * Returns the next element following that axis
5935 */
5936xmlNodePtr
5937xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00005938 if (ctxt->context->node == NULL)
5939 return(NULL);
5940 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5941 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005942 if (cur == NULL) {
5943 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5944 return(NULL);
5945 return((xmlNodePtr)ctxt->context->node->properties);
5946 }
5947 return((xmlNodePtr)cur->next);
5948}
5949
5950/************************************************************************
5951 * *
5952 * NodeTest Functions *
5953 * *
5954 ************************************************************************/
5955
Owen Taylor3473f882001-02-23 17:55:21 +00005956#define IS_FUNCTION 200
5957
Owen Taylor3473f882001-02-23 17:55:21 +00005958
5959/************************************************************************
5960 * *
5961 * Implicit tree core function library *
5962 * *
5963 ************************************************************************/
5964
5965/**
5966 * xmlXPathRoot:
5967 * @ctxt: the XPath Parser context
5968 *
5969 * Initialize the context to the root of the document
5970 */
5971void
5972xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5973 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5974 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5975}
5976
5977/************************************************************************
5978 * *
5979 * The explicit core function library *
5980 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5981 * *
5982 ************************************************************************/
5983
5984
5985/**
5986 * xmlXPathLastFunction:
5987 * @ctxt: the XPath Parser context
5988 * @nargs: the number of arguments
5989 *
5990 * Implement the last() XPath function
5991 * number last()
5992 * The last function returns the number of nodes in the context node list.
5993 */
5994void
5995xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5996 CHECK_ARITY(0);
5997 if (ctxt->context->contextSize >= 0) {
5998 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5999#ifdef DEBUG_EXPR
6000 xmlGenericError(xmlGenericErrorContext,
6001 "last() : %d\n", ctxt->context->contextSize);
6002#endif
6003 } else {
6004 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6005 }
6006}
6007
6008/**
6009 * xmlXPathPositionFunction:
6010 * @ctxt: the XPath Parser context
6011 * @nargs: the number of arguments
6012 *
6013 * Implement the position() XPath function
6014 * number position()
6015 * The position function returns the position of the context node in the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006016 * context node list. The first position is 1, and so the last position
Owen Taylor3473f882001-02-23 17:55:21 +00006017 * will be equal to last().
6018 */
6019void
6020xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6021 CHECK_ARITY(0);
6022 if (ctxt->context->proximityPosition >= 0) {
6023 valuePush(ctxt,
6024 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
6025#ifdef DEBUG_EXPR
6026 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
6027 ctxt->context->proximityPosition);
6028#endif
6029 } else {
6030 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6031 }
6032}
6033
6034/**
6035 * xmlXPathCountFunction:
6036 * @ctxt: the XPath Parser context
6037 * @nargs: the number of arguments
6038 *
6039 * Implement the count() XPath function
6040 * number count(node-set)
6041 */
6042void
6043xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6044 xmlXPathObjectPtr cur;
6045
6046 CHECK_ARITY(1);
6047 if ((ctxt->value == NULL) ||
6048 ((ctxt->value->type != XPATH_NODESET) &&
6049 (ctxt->value->type != XPATH_XSLT_TREE)))
6050 XP_ERROR(XPATH_INVALID_TYPE);
6051 cur = valuePop(ctxt);
6052
Daniel Veillard911f49a2001-04-07 15:39:35 +00006053 if ((cur == NULL) || (cur->nodesetval == NULL))
6054 valuePush(ctxt, xmlXPathNewFloat((double) 0));
William M. Brack0c022ad2002-07-12 00:56:01 +00006055 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
Daniel Veillard911f49a2001-04-07 15:39:35 +00006056 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillardfe703322001-08-14 12:18:09 +00006057 } else {
6058 if ((cur->nodesetval->nodeNr != 1) ||
6059 (cur->nodesetval->nodeTab == NULL)) {
6060 valuePush(ctxt, xmlXPathNewFloat((double) 0));
6061 } else {
6062 xmlNodePtr tmp;
6063 int i = 0;
6064
6065 tmp = cur->nodesetval->nodeTab[0];
6066 if (tmp != NULL) {
6067 tmp = tmp->children;
6068 while (tmp != NULL) {
6069 tmp = tmp->next;
6070 i++;
6071 }
6072 }
6073 valuePush(ctxt, xmlXPathNewFloat((double) i));
6074 }
6075 }
Owen Taylor3473f882001-02-23 17:55:21 +00006076 xmlXPathFreeObject(cur);
6077}
6078
6079/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006080 * xmlXPathGetElementsByIds:
6081 * @doc: the document
6082 * @ids: a whitespace separated list of IDs
6083 *
6084 * Selects elements by their unique ID.
6085 *
6086 * Returns a node-set of selected elements.
6087 */
6088static xmlNodeSetPtr
6089xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6090 xmlNodeSetPtr ret;
6091 const xmlChar *cur = ids;
6092 xmlChar *ID;
6093 xmlAttrPtr attr;
6094 xmlNodePtr elem = NULL;
6095
Daniel Veillard7a985a12003-07-06 17:57:42 +00006096 if (ids == NULL) return(NULL);
6097
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006098 ret = xmlXPathNodeSetCreate(NULL);
6099
William M. Brack76e95df2003-10-18 16:20:14 +00006100 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006101 while (*cur != 0) {
William M. Brack76e95df2003-10-18 16:20:14 +00006102 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
Daniel Veillarde209b332003-03-26 21:40:13 +00006103 cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006104
6105 ID = xmlStrndup(ids, cur - ids);
Daniel Veillarde209b332003-03-26 21:40:13 +00006106 if (ID != NULL) {
Daniel Veillard68cb4b22004-04-18 20:55:39 +00006107 /*
6108 * We used to check the fact that the value passed
6109 * was an NCName, but this generated much troubles for
6110 * me and Aleksey Sanin, people blatantly violated that
6111 * constaint, like Visa3D spec.
6112 * if (xmlValidateNCName(ID, 1) == 0)
6113 */
6114 attr = xmlGetID(doc, ID);
6115 if (attr != NULL) {
6116 if (attr->type == XML_ATTRIBUTE_NODE)
6117 elem = attr->parent;
6118 else if (attr->type == XML_ELEMENT_NODE)
6119 elem = (xmlNodePtr) attr;
6120 else
6121 elem = NULL;
6122 if (elem != NULL)
6123 xmlXPathNodeSetAdd(ret, elem);
Daniel Veillarde209b332003-03-26 21:40:13 +00006124 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006125 xmlFree(ID);
Daniel Veillarde209b332003-03-26 21:40:13 +00006126 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006127
William M. Brack76e95df2003-10-18 16:20:14 +00006128 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006129 ids = cur;
6130 }
6131 return(ret);
6132}
6133
6134/**
Owen Taylor3473f882001-02-23 17:55:21 +00006135 * xmlXPathIdFunction:
6136 * @ctxt: the XPath Parser context
6137 * @nargs: the number of arguments
6138 *
6139 * Implement the id() XPath function
6140 * node-set id(object)
6141 * The id function selects elements by their unique ID
6142 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6143 * then the result is the union of the result of applying id to the
6144 * string value of each of the nodes in the argument node-set. When the
6145 * argument to id is of any other type, the argument is converted to a
6146 * string as if by a call to the string function; the string is split
6147 * into a whitespace-separated list of tokens (whitespace is any sequence
6148 * of characters matching the production S); the result is a node-set
6149 * containing the elements in the same document as the context node that
6150 * have a unique ID equal to any of the tokens in the list.
6151 */
6152void
6153xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006154 xmlChar *tokens;
6155 xmlNodeSetPtr ret;
6156 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00006157
6158 CHECK_ARITY(1);
6159 obj = valuePop(ctxt);
6160 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
William M. Brack0c022ad2002-07-12 00:56:01 +00006161 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006162 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00006163 int i;
6164
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006165 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006166
Daniel Veillard911f49a2001-04-07 15:39:35 +00006167 if (obj->nodesetval != NULL) {
6168 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006169 tokens =
6170 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6171 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6172 ret = xmlXPathNodeSetMerge(ret, ns);
6173 xmlXPathFreeNodeSet(ns);
6174 if (tokens != NULL)
6175 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00006176 }
Owen Taylor3473f882001-02-23 17:55:21 +00006177 }
6178
6179 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006180 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006181 return;
6182 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006183 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00006184
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006185 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6186 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00006187
Owen Taylor3473f882001-02-23 17:55:21 +00006188 xmlXPathFreeObject(obj);
6189 return;
6190}
6191
6192/**
6193 * xmlXPathLocalNameFunction:
6194 * @ctxt: the XPath Parser context
6195 * @nargs: the number of arguments
6196 *
6197 * Implement the local-name() XPath function
6198 * string local-name(node-set?)
6199 * The local-name function returns a string containing the local part
6200 * of the name of the node in the argument node-set that is first in
6201 * document order. If the node-set is empty or the first node has no
6202 * name, an empty string is returned. If the argument is omitted it
6203 * defaults to the context node.
6204 */
6205void
6206xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6207 xmlXPathObjectPtr cur;
6208
6209 if (nargs == 0) {
6210 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6211 nargs = 1;
6212 }
6213
6214 CHECK_ARITY(1);
6215 if ((ctxt->value == NULL) ||
6216 ((ctxt->value->type != XPATH_NODESET) &&
6217 (ctxt->value->type != XPATH_XSLT_TREE)))
6218 XP_ERROR(XPATH_INVALID_TYPE);
6219 cur = valuePop(ctxt);
6220
Daniel Veillard911f49a2001-04-07 15:39:35 +00006221 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006222 valuePush(ctxt, xmlXPathNewCString(""));
6223 } else {
6224 int i = 0; /* Should be first in document order !!!!! */
6225 switch (cur->nodesetval->nodeTab[i]->type) {
6226 case XML_ELEMENT_NODE:
6227 case XML_ATTRIBUTE_NODE:
6228 case XML_PI_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006229 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6230 valuePush(ctxt, xmlXPathNewCString(""));
6231 else
6232 valuePush(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006233 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6234 break;
6235 case XML_NAMESPACE_DECL:
6236 valuePush(ctxt, xmlXPathNewString(
6237 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6238 break;
6239 default:
6240 valuePush(ctxt, xmlXPathNewCString(""));
6241 }
6242 }
6243 xmlXPathFreeObject(cur);
6244}
6245
6246/**
6247 * xmlXPathNamespaceURIFunction:
6248 * @ctxt: the XPath Parser context
6249 * @nargs: the number of arguments
6250 *
6251 * Implement the namespace-uri() XPath function
6252 * string namespace-uri(node-set?)
6253 * The namespace-uri function returns a string containing the
6254 * namespace URI of the expanded name of the node in the argument
6255 * node-set that is first in document order. If the node-set is empty,
6256 * the first node has no name, or the expanded name has no namespace
6257 * URI, an empty string is returned. If the argument is omitted it
6258 * defaults to the context node.
6259 */
6260void
6261xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6262 xmlXPathObjectPtr cur;
6263
6264 if (nargs == 0) {
6265 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6266 nargs = 1;
6267 }
6268 CHECK_ARITY(1);
6269 if ((ctxt->value == NULL) ||
6270 ((ctxt->value->type != XPATH_NODESET) &&
6271 (ctxt->value->type != XPATH_XSLT_TREE)))
6272 XP_ERROR(XPATH_INVALID_TYPE);
6273 cur = valuePop(ctxt);
6274
Daniel Veillard911f49a2001-04-07 15:39:35 +00006275 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006276 valuePush(ctxt, xmlXPathNewCString(""));
6277 } else {
6278 int i = 0; /* Should be first in document order !!!!! */
6279 switch (cur->nodesetval->nodeTab[i]->type) {
6280 case XML_ELEMENT_NODE:
6281 case XML_ATTRIBUTE_NODE:
6282 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6283 valuePush(ctxt, xmlXPathNewCString(""));
6284 else
6285 valuePush(ctxt, xmlXPathNewString(
6286 cur->nodesetval->nodeTab[i]->ns->href));
6287 break;
6288 default:
6289 valuePush(ctxt, xmlXPathNewCString(""));
6290 }
6291 }
6292 xmlXPathFreeObject(cur);
6293}
6294
6295/**
6296 * xmlXPathNameFunction:
6297 * @ctxt: the XPath Parser context
6298 * @nargs: the number of arguments
6299 *
6300 * Implement the name() XPath function
6301 * string name(node-set?)
6302 * The name function returns a string containing a QName representing
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006303 * the name of the node in the argument node-set that is first in document
Owen Taylor3473f882001-02-23 17:55:21 +00006304 * order. The QName must represent the name with respect to the namespace
6305 * declarations in effect on the node whose name is being represented.
6306 * Typically, this will be the form in which the name occurred in the XML
6307 * source. This need not be the case if there are namespace declarations
6308 * in effect on the node that associate multiple prefixes with the same
6309 * namespace. However, an implementation may include information about
6310 * the original prefix in its representation of nodes; in this case, an
6311 * implementation can ensure that the returned string is always the same
6312 * as the QName used in the XML source. If the argument it omitted it
6313 * defaults to the context node.
6314 * Libxml keep the original prefix so the "real qualified name" used is
6315 * returned.
6316 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006317static void
Daniel Veillard04383752001-07-08 14:27:15 +00006318xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6319{
Owen Taylor3473f882001-02-23 17:55:21 +00006320 xmlXPathObjectPtr cur;
6321
6322 if (nargs == 0) {
Daniel Veillard04383752001-07-08 14:27:15 +00006323 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6324 nargs = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006325 }
6326
6327 CHECK_ARITY(1);
Daniel Veillard04383752001-07-08 14:27:15 +00006328 if ((ctxt->value == NULL) ||
6329 ((ctxt->value->type != XPATH_NODESET) &&
6330 (ctxt->value->type != XPATH_XSLT_TREE)))
6331 XP_ERROR(XPATH_INVALID_TYPE);
Owen Taylor3473f882001-02-23 17:55:21 +00006332 cur = valuePop(ctxt);
6333
Daniel Veillard911f49a2001-04-07 15:39:35 +00006334 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006335 valuePush(ctxt, xmlXPathNewCString(""));
Owen Taylor3473f882001-02-23 17:55:21 +00006336 } else {
Daniel Veillard04383752001-07-08 14:27:15 +00006337 int i = 0; /* Should be first in document order !!!!! */
Owen Taylor3473f882001-02-23 17:55:21 +00006338
Daniel Veillard04383752001-07-08 14:27:15 +00006339 switch (cur->nodesetval->nodeTab[i]->type) {
6340 case XML_ELEMENT_NODE:
6341 case XML_ATTRIBUTE_NODE:
Daniel Veillard652d8a92003-02-04 19:28:49 +00006342 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6343 valuePush(ctxt, xmlXPathNewCString(""));
6344 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6345 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
Daniel Veillard04383752001-07-08 14:27:15 +00006346 valuePush(ctxt,
Daniel Veillardc00cda82003-04-07 10:22:39 +00006347 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
Daniel Veillard04383752001-07-08 14:27:15 +00006348
Daniel Veillard652d8a92003-02-04 19:28:49 +00006349 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006350 xmlChar *fullname;
6351
6352 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6353 cur->nodesetval->nodeTab[i]->ns->prefix,
6354 NULL, 0);
6355 if (fullname == cur->nodesetval->nodeTab[i]->name)
6356 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6357 if (fullname == NULL) {
6358 XP_ERROR(XPATH_MEMORY_ERROR);
6359 }
6360 valuePush(ctxt, xmlXPathWrapString(fullname));
Daniel Veillard04383752001-07-08 14:27:15 +00006361 }
6362 break;
6363 default:
6364 valuePush(ctxt,
6365 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6366 xmlXPathLocalNameFunction(ctxt, 1);
6367 }
Owen Taylor3473f882001-02-23 17:55:21 +00006368 }
6369 xmlXPathFreeObject(cur);
6370}
6371
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006372
6373/**
Owen Taylor3473f882001-02-23 17:55:21 +00006374 * xmlXPathStringFunction:
6375 * @ctxt: the XPath Parser context
6376 * @nargs: the number of arguments
6377 *
6378 * Implement the string() XPath function
6379 * string string(object?)
William M. Brack08171912003-12-29 02:52:11 +00006380 * The string function converts an object to a string as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006381 * - A node-set is converted to a string by returning the value of
6382 * the node in the node-set that is first in document order.
6383 * If the node-set is empty, an empty string is returned.
6384 * - A number is converted to a string as follows
6385 * + NaN is converted to the string NaN
6386 * + positive zero is converted to the string 0
6387 * + negative zero is converted to the string 0
6388 * + positive infinity is converted to the string Infinity
6389 * + negative infinity is converted to the string -Infinity
6390 * + if the number is an integer, the number is represented in
6391 * decimal form as a Number with no decimal point and no leading
6392 * zeros, preceded by a minus sign (-) if the number is negative
6393 * + otherwise, the number is represented in decimal form as a
6394 * Number including a decimal point with at least one digit
6395 * before the decimal point and at least one digit after the
6396 * decimal point, preceded by a minus sign (-) if the number
6397 * is negative; there must be no leading zeros before the decimal
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006398 * point apart possibly from the one required digit immediately
Owen Taylor3473f882001-02-23 17:55:21 +00006399 * before the decimal point; beyond the one required digit
6400 * after the decimal point there must be as many, but only as
6401 * many, more digits as are needed to uniquely distinguish the
6402 * number from all other IEEE 754 numeric values.
6403 * - The boolean false value is converted to the string false.
6404 * The boolean true value is converted to the string true.
6405 *
6406 * If the argument is omitted, it defaults to a node-set with the
6407 * context node as its only member.
6408 */
6409void
6410xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6411 xmlXPathObjectPtr cur;
6412
6413 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006414 valuePush(ctxt,
6415 xmlXPathWrapString(
6416 xmlXPathCastNodeToString(ctxt->context->node)));
6417 return;
Owen Taylor3473f882001-02-23 17:55:21 +00006418 }
6419
6420 CHECK_ARITY(1);
6421 cur = valuePop(ctxt);
6422 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006423 cur = xmlXPathConvertString(cur);
6424 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006425}
6426
6427/**
6428 * xmlXPathStringLengthFunction:
6429 * @ctxt: the XPath Parser context
6430 * @nargs: the number of arguments
6431 *
6432 * Implement the string-length() XPath function
6433 * number string-length(string?)
6434 * The string-length returns the number of characters in the string
6435 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6436 * the context node converted to a string, in other words the value
6437 * of the context node.
6438 */
6439void
6440xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6441 xmlXPathObjectPtr cur;
6442
6443 if (nargs == 0) {
6444 if (ctxt->context->node == NULL) {
6445 valuePush(ctxt, xmlXPathNewFloat(0));
6446 } else {
6447 xmlChar *content;
6448
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006449 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006450 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00006451 xmlFree(content);
6452 }
6453 return;
6454 }
6455 CHECK_ARITY(1);
6456 CAST_TO_STRING;
6457 CHECK_TYPE(XPATH_STRING);
6458 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00006459 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00006460 xmlXPathFreeObject(cur);
6461}
6462
6463/**
6464 * xmlXPathConcatFunction:
6465 * @ctxt: the XPath Parser context
6466 * @nargs: the number of arguments
6467 *
6468 * Implement the concat() XPath function
6469 * string concat(string, string, string*)
6470 * The concat function returns the concatenation of its arguments.
6471 */
6472void
6473xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6474 xmlXPathObjectPtr cur, newobj;
6475 xmlChar *tmp;
6476
6477 if (nargs < 2) {
6478 CHECK_ARITY(2);
6479 }
6480
6481 CAST_TO_STRING;
6482 cur = valuePop(ctxt);
6483 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6484 xmlXPathFreeObject(cur);
6485 return;
6486 }
6487 nargs--;
6488
6489 while (nargs > 0) {
6490 CAST_TO_STRING;
6491 newobj = valuePop(ctxt);
6492 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6493 xmlXPathFreeObject(newobj);
6494 xmlXPathFreeObject(cur);
6495 XP_ERROR(XPATH_INVALID_TYPE);
6496 }
6497 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6498 newobj->stringval = cur->stringval;
6499 cur->stringval = tmp;
6500
6501 xmlXPathFreeObject(newobj);
6502 nargs--;
6503 }
6504 valuePush(ctxt, cur);
6505}
6506
6507/**
6508 * xmlXPathContainsFunction:
6509 * @ctxt: the XPath Parser context
6510 * @nargs: the number of arguments
6511 *
6512 * Implement the contains() XPath function
6513 * boolean contains(string, string)
6514 * The contains function returns true if the first argument string
6515 * contains the second argument string, and otherwise returns false.
6516 */
6517void
6518xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6519 xmlXPathObjectPtr hay, needle;
6520
6521 CHECK_ARITY(2);
6522 CAST_TO_STRING;
6523 CHECK_TYPE(XPATH_STRING);
6524 needle = valuePop(ctxt);
6525 CAST_TO_STRING;
6526 hay = valuePop(ctxt);
6527 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6528 xmlXPathFreeObject(hay);
6529 xmlXPathFreeObject(needle);
6530 XP_ERROR(XPATH_INVALID_TYPE);
6531 }
6532 if (xmlStrstr(hay->stringval, needle->stringval))
6533 valuePush(ctxt, xmlXPathNewBoolean(1));
6534 else
6535 valuePush(ctxt, xmlXPathNewBoolean(0));
6536 xmlXPathFreeObject(hay);
6537 xmlXPathFreeObject(needle);
6538}
6539
6540/**
6541 * xmlXPathStartsWithFunction:
6542 * @ctxt: the XPath Parser context
6543 * @nargs: the number of arguments
6544 *
6545 * Implement the starts-with() XPath function
6546 * boolean starts-with(string, string)
6547 * The starts-with function returns true if the first argument string
6548 * starts with the second argument string, and otherwise returns false.
6549 */
6550void
6551xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6552 xmlXPathObjectPtr hay, needle;
6553 int n;
6554
6555 CHECK_ARITY(2);
6556 CAST_TO_STRING;
6557 CHECK_TYPE(XPATH_STRING);
6558 needle = valuePop(ctxt);
6559 CAST_TO_STRING;
6560 hay = valuePop(ctxt);
6561 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6562 xmlXPathFreeObject(hay);
6563 xmlXPathFreeObject(needle);
6564 XP_ERROR(XPATH_INVALID_TYPE);
6565 }
6566 n = xmlStrlen(needle->stringval);
6567 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6568 valuePush(ctxt, xmlXPathNewBoolean(0));
6569 else
6570 valuePush(ctxt, xmlXPathNewBoolean(1));
6571 xmlXPathFreeObject(hay);
6572 xmlXPathFreeObject(needle);
6573}
6574
6575/**
6576 * xmlXPathSubstringFunction:
6577 * @ctxt: the XPath Parser context
6578 * @nargs: the number of arguments
6579 *
6580 * Implement the substring() XPath function
6581 * string substring(string, number, number?)
6582 * The substring function returns the substring of the first argument
6583 * starting at the position specified in the second argument with
6584 * length specified in the third argument. For example,
6585 * substring("12345",2,3) returns "234". If the third argument is not
6586 * specified, it returns the substring starting at the position specified
6587 * in the second argument and continuing to the end of the string. For
6588 * example, substring("12345",2) returns "2345". More precisely, each
6589 * character in the string (see [3.6 Strings]) is considered to have a
6590 * numeric position: the position of the first character is 1, the position
6591 * of the second character is 2 and so on. The returned substring contains
6592 * those characters for which the position of the character is greater than
6593 * or equal to the second argument and, if the third argument is specified,
6594 * less than the sum of the second and third arguments; the comparisons
6595 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6596 * - substring("12345", 1.5, 2.6) returns "234"
6597 * - substring("12345", 0, 3) returns "12"
6598 * - substring("12345", 0 div 0, 3) returns ""
6599 * - substring("12345", 1, 0 div 0) returns ""
6600 * - substring("12345", -42, 1 div 0) returns "12345"
6601 * - substring("12345", -1 div 0, 1 div 0) returns ""
6602 */
6603void
6604xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6605 xmlXPathObjectPtr str, start, len;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006606 double le=0, in;
6607 int i, l, m;
Owen Taylor3473f882001-02-23 17:55:21 +00006608 xmlChar *ret;
6609
Owen Taylor3473f882001-02-23 17:55:21 +00006610 if (nargs < 2) {
6611 CHECK_ARITY(2);
6612 }
6613 if (nargs > 3) {
6614 CHECK_ARITY(3);
6615 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006616 /*
6617 * take care of possible last (position) argument
6618 */
Owen Taylor3473f882001-02-23 17:55:21 +00006619 if (nargs == 3) {
6620 CAST_TO_NUMBER;
6621 CHECK_TYPE(XPATH_NUMBER);
6622 len = valuePop(ctxt);
6623 le = len->floatval;
6624 xmlXPathFreeObject(len);
Owen Taylor3473f882001-02-23 17:55:21 +00006625 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006626
Owen Taylor3473f882001-02-23 17:55:21 +00006627 CAST_TO_NUMBER;
6628 CHECK_TYPE(XPATH_NUMBER);
6629 start = valuePop(ctxt);
6630 in = start->floatval;
6631 xmlXPathFreeObject(start);
6632 CAST_TO_STRING;
6633 CHECK_TYPE(XPATH_STRING);
6634 str = valuePop(ctxt);
Daniel Veillard97ac1312001-05-30 19:14:17 +00006635 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
Owen Taylor3473f882001-02-23 17:55:21 +00006636
Daniel Veillard97ac1312001-05-30 19:14:17 +00006637 /*
6638 * If last pos not present, calculate last position
6639 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006640 if (nargs != 3) {
6641 le = (double)m;
6642 if (in < 1.0)
6643 in = 1.0;
6644 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006645
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006646 /* Need to check for the special cases where either
6647 * the index is NaN, the length is NaN, or both
6648 * arguments are infinity (relying on Inf + -Inf = NaN)
Daniel Veillard97ac1312001-05-30 19:14:17 +00006649 */
Daniel Veillard9e412302002-06-10 15:59:44 +00006650 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006651 /*
Daniel Veillard9e412302002-06-10 15:59:44 +00006652 * To meet the requirements of the spec, the arguments
6653 * must be converted to integer format before
6654 * initial index calculations are done
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006655 *
Daniel Veillard9e412302002-06-10 15:59:44 +00006656 * First we go to integer form, rounding up
6657 * and checking for special cases
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006658 */
6659 i = (int) in;
Daniel Veillard9e412302002-06-10 15:59:44 +00006660 if (((double)i)+0.5 <= in) i++;
Owen Taylor3473f882001-02-23 17:55:21 +00006661
Daniel Veillard9e412302002-06-10 15:59:44 +00006662 if (xmlXPathIsInf(le) == 1) {
6663 l = m;
6664 if (i < 1)
6665 i = 1;
6666 }
6667 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6668 l = 0;
6669 else {
6670 l = (int) le;
6671 if (((double)l)+0.5 <= le) l++;
6672 }
6673
6674 /* Now we normalize inidices */
6675 i -= 1;
6676 l += i;
6677 if (i < 0)
6678 i = 0;
6679 if (l > m)
6680 l = m;
Owen Taylor3473f882001-02-23 17:55:21 +00006681
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006682 /* number of chars to copy */
6683 l -= i;
Owen Taylor3473f882001-02-23 17:55:21 +00006684
Daniel Veillard0eafdef2002-04-10 16:14:34 +00006685 ret = xmlUTF8Strsub(str->stringval, i, l);
6686 }
6687 else {
6688 ret = NULL;
6689 }
6690
Owen Taylor3473f882001-02-23 17:55:21 +00006691 if (ret == NULL)
6692 valuePush(ctxt, xmlXPathNewCString(""));
6693 else {
6694 valuePush(ctxt, xmlXPathNewString(ret));
6695 xmlFree(ret);
6696 }
Daniel Veillard97ac1312001-05-30 19:14:17 +00006697
Owen Taylor3473f882001-02-23 17:55:21 +00006698 xmlXPathFreeObject(str);
6699}
6700
6701/**
6702 * xmlXPathSubstringBeforeFunction:
6703 * @ctxt: the XPath Parser context
6704 * @nargs: the number of arguments
6705 *
6706 * Implement the substring-before() XPath function
6707 * string substring-before(string, string)
6708 * The substring-before function returns the substring of the first
6709 * argument string that precedes the first occurrence of the second
6710 * argument string in the first argument string, or the empty string
6711 * if the first argument string does not contain the second argument
6712 * string. For example, substring-before("1999/04/01","/") returns 1999.
6713 */
6714void
6715xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6716 xmlXPathObjectPtr str;
6717 xmlXPathObjectPtr find;
6718 xmlBufferPtr target;
6719 const xmlChar *point;
6720 int offset;
6721
6722 CHECK_ARITY(2);
6723 CAST_TO_STRING;
6724 find = valuePop(ctxt);
6725 CAST_TO_STRING;
6726 str = valuePop(ctxt);
6727
6728 target = xmlBufferCreate();
6729 if (target) {
6730 point = xmlStrstr(str->stringval, find->stringval);
6731 if (point) {
6732 offset = (int)(point - str->stringval);
6733 xmlBufferAdd(target, str->stringval, offset);
6734 }
6735 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6736 xmlBufferFree(target);
6737 }
6738
6739 xmlXPathFreeObject(str);
6740 xmlXPathFreeObject(find);
6741}
6742
6743/**
6744 * xmlXPathSubstringAfterFunction:
6745 * @ctxt: the XPath Parser context
6746 * @nargs: the number of arguments
6747 *
6748 * Implement the substring-after() XPath function
6749 * string substring-after(string, string)
6750 * The substring-after function returns the substring of the first
6751 * argument string that follows the first occurrence of the second
6752 * argument string in the first argument string, or the empty stringi
6753 * if the first argument string does not contain the second argument
6754 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6755 * and substring-after("1999/04/01","19") returns 99/04/01.
6756 */
6757void
6758xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6759 xmlXPathObjectPtr str;
6760 xmlXPathObjectPtr find;
6761 xmlBufferPtr target;
6762 const xmlChar *point;
6763 int offset;
6764
6765 CHECK_ARITY(2);
6766 CAST_TO_STRING;
6767 find = valuePop(ctxt);
6768 CAST_TO_STRING;
6769 str = valuePop(ctxt);
6770
6771 target = xmlBufferCreate();
6772 if (target) {
6773 point = xmlStrstr(str->stringval, find->stringval);
6774 if (point) {
6775 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6776 xmlBufferAdd(target, &str->stringval[offset],
6777 xmlStrlen(str->stringval) - offset);
6778 }
6779 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6780 xmlBufferFree(target);
6781 }
6782
6783 xmlXPathFreeObject(str);
6784 xmlXPathFreeObject(find);
6785}
6786
6787/**
6788 * xmlXPathNormalizeFunction:
6789 * @ctxt: the XPath Parser context
6790 * @nargs: the number of arguments
6791 *
6792 * Implement the normalize-space() XPath function
6793 * string normalize-space(string?)
6794 * The normalize-space function returns the argument string with white
6795 * space normalized by stripping leading and trailing whitespace
6796 * and replacing sequences of whitespace characters by a single
6797 * space. Whitespace characters are the same allowed by the S production
6798 * in XML. If the argument is omitted, it defaults to the context
6799 * node converted to a string, in other words the value of the context node.
6800 */
6801void
6802xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6803 xmlXPathObjectPtr obj = NULL;
6804 xmlChar *source = NULL;
6805 xmlBufferPtr target;
6806 xmlChar blank;
6807
6808 if (nargs == 0) {
6809 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00006810 valuePush(ctxt,
6811 xmlXPathWrapString(
6812 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00006813 nargs = 1;
6814 }
6815
6816 CHECK_ARITY(1);
6817 CAST_TO_STRING;
6818 CHECK_TYPE(XPATH_STRING);
6819 obj = valuePop(ctxt);
6820 source = obj->stringval;
6821
6822 target = xmlBufferCreate();
6823 if (target && source) {
6824
6825 /* Skip leading whitespaces */
William M. Brack76e95df2003-10-18 16:20:14 +00006826 while (IS_BLANK_CH(*source))
Owen Taylor3473f882001-02-23 17:55:21 +00006827 source++;
6828
6829 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6830 blank = 0;
6831 while (*source) {
William M. Brack76e95df2003-10-18 16:20:14 +00006832 if (IS_BLANK_CH(*source)) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006833 blank = 0x20;
Owen Taylor3473f882001-02-23 17:55:21 +00006834 } else {
6835 if (blank) {
6836 xmlBufferAdd(target, &blank, 1);
6837 blank = 0;
6838 }
6839 xmlBufferAdd(target, source, 1);
6840 }
6841 source++;
6842 }
6843
6844 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6845 xmlBufferFree(target);
6846 }
6847 xmlXPathFreeObject(obj);
6848}
6849
6850/**
6851 * xmlXPathTranslateFunction:
6852 * @ctxt: the XPath Parser context
6853 * @nargs: the number of arguments
6854 *
6855 * Implement the translate() XPath function
6856 * string translate(string, string, string)
6857 * The translate function returns the first argument string with
6858 * occurrences of characters in the second argument string replaced
6859 * by the character at the corresponding position in the third argument
6860 * string. For example, translate("bar","abc","ABC") returns the string
6861 * BAr. If there is a character in the second argument string with no
6862 * character at a corresponding position in the third argument string
6863 * (because the second argument string is longer than the third argument
6864 * string), then occurrences of that character in the first argument
6865 * string are removed. For example, translate("--aaa--","abc-","ABC")
6866 * returns "AAA". If a character occurs more than once in second
6867 * argument string, then the first occurrence determines the replacement
6868 * character. If the third argument string is longer than the second
6869 * argument string, then excess characters are ignored.
6870 */
6871void
6872xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00006873 xmlXPathObjectPtr str;
6874 xmlXPathObjectPtr from;
6875 xmlXPathObjectPtr to;
6876 xmlBufferPtr target;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006877 int offset, max;
Daniel Veillarde043ee12001-04-16 14:08:07 +00006878 xmlChar ch;
Daniel Veillard97ac1312001-05-30 19:14:17 +00006879 xmlChar *point;
6880 xmlChar *cptr;
Owen Taylor3473f882001-02-23 17:55:21 +00006881
Daniel Veillarde043ee12001-04-16 14:08:07 +00006882 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00006883
Daniel Veillarde043ee12001-04-16 14:08:07 +00006884 CAST_TO_STRING;
6885 to = valuePop(ctxt);
6886 CAST_TO_STRING;
6887 from = valuePop(ctxt);
6888 CAST_TO_STRING;
6889 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006890
Daniel Veillarde043ee12001-04-16 14:08:07 +00006891 target = xmlBufferCreate();
6892 if (target) {
Daniel Veillard97ac1312001-05-30 19:14:17 +00006893 max = xmlUTF8Strlen(to->stringval);
6894 for (cptr = str->stringval; (ch=*cptr); ) {
6895 offset = xmlUTF8Strloc(from->stringval, cptr);
6896 if (offset >= 0) {
6897 if (offset < max) {
6898 point = xmlUTF8Strpos(to->stringval, offset);
6899 if (point)
6900 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6901 }
6902 } else
6903 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6904
6905 /* Step to next character in input */
6906 cptr++;
6907 if ( ch & 0x80 ) {
6908 /* if not simple ascii, verify proper format */
6909 if ( (ch & 0xc0) != 0xc0 ) {
6910 xmlGenericError(xmlGenericErrorContext,
6911 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6912 break;
6913 }
6914 /* then skip over remaining bytes for this char */
6915 while ( (ch <<= 1) & 0x80 )
6916 if ( (*cptr++ & 0xc0) != 0x80 ) {
6917 xmlGenericError(xmlGenericErrorContext,
6918 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6919 break;
6920 }
6921 if (ch & 0x80) /* must have had error encountered */
6922 break;
6923 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006924 }
Owen Taylor3473f882001-02-23 17:55:21 +00006925 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00006926 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6927 xmlBufferFree(target);
6928 xmlXPathFreeObject(str);
6929 xmlXPathFreeObject(from);
6930 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00006931}
6932
6933/**
6934 * xmlXPathBooleanFunction:
6935 * @ctxt: the XPath Parser context
6936 * @nargs: the number of arguments
6937 *
6938 * Implement the boolean() XPath function
6939 * boolean boolean(object)
William M. Brack08171912003-12-29 02:52:11 +00006940 * The boolean function converts its argument to a boolean as follows:
Owen Taylor3473f882001-02-23 17:55:21 +00006941 * - a number is true if and only if it is neither positive or
6942 * negative zero nor NaN
6943 * - a node-set is true if and only if it is non-empty
6944 * - a string is true if and only if its length is non-zero
6945 */
6946void
6947xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6948 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00006949
6950 CHECK_ARITY(1);
6951 cur = valuePop(ctxt);
6952 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006953 cur = xmlXPathConvertBoolean(cur);
6954 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00006955}
6956
6957/**
6958 * xmlXPathNotFunction:
6959 * @ctxt: the XPath Parser context
6960 * @nargs: the number of arguments
6961 *
6962 * Implement the not() XPath function
6963 * boolean not(boolean)
6964 * The not function returns true if its argument is false,
6965 * and false otherwise.
6966 */
6967void
6968xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6969 CHECK_ARITY(1);
6970 CAST_TO_BOOLEAN;
6971 CHECK_TYPE(XPATH_BOOLEAN);
6972 ctxt->value->boolval = ! ctxt->value->boolval;
6973}
6974
6975/**
6976 * xmlXPathTrueFunction:
6977 * @ctxt: the XPath Parser context
6978 * @nargs: the number of arguments
6979 *
6980 * Implement the true() XPath function
6981 * boolean true()
6982 */
6983void
6984xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6985 CHECK_ARITY(0);
6986 valuePush(ctxt, xmlXPathNewBoolean(1));
6987}
6988
6989/**
6990 * xmlXPathFalseFunction:
6991 * @ctxt: the XPath Parser context
6992 * @nargs: the number of arguments
6993 *
6994 * Implement the false() XPath function
6995 * boolean false()
6996 */
6997void
6998xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6999 CHECK_ARITY(0);
7000 valuePush(ctxt, xmlXPathNewBoolean(0));
7001}
7002
7003/**
7004 * xmlXPathLangFunction:
7005 * @ctxt: the XPath Parser context
7006 * @nargs: the number of arguments
7007 *
7008 * Implement the lang() XPath function
7009 * boolean lang(string)
7010 * The lang function returns true or false depending on whether the
7011 * language of the context node as specified by xml:lang attributes
7012 * is the same as or is a sublanguage of the language specified by
7013 * the argument string. The language of the context node is determined
7014 * by the value of the xml:lang attribute on the context node, or, if
7015 * the context node has no xml:lang attribute, by the value of the
7016 * xml:lang attribute on the nearest ancestor of the context node that
7017 * has an xml:lang attribute. If there is no such attribute, then lang
7018 * returns false. If there is such an attribute, then lang returns
7019 * true if the attribute value is equal to the argument ignoring case,
7020 * or if there is some suffix starting with - such that the attribute
7021 * value is equal to the argument ignoring that suffix of the attribute
7022 * value and ignoring case.
7023 */
7024void
7025xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7026 xmlXPathObjectPtr val;
7027 const xmlChar *theLang;
7028 const xmlChar *lang;
7029 int ret = 0;
7030 int i;
7031
7032 CHECK_ARITY(1);
7033 CAST_TO_STRING;
7034 CHECK_TYPE(XPATH_STRING);
7035 val = valuePop(ctxt);
7036 lang = val->stringval;
7037 theLang = xmlNodeGetLang(ctxt->context->node);
7038 if ((theLang != NULL) && (lang != NULL)) {
7039 for (i = 0;lang[i] != 0;i++)
7040 if (toupper(lang[i]) != toupper(theLang[i]))
7041 goto not_equal;
7042 ret = 1;
7043 }
7044not_equal:
William M. Bracka59ddb52004-02-25 08:12:32 +00007045 xmlFree((void *)theLang);
Owen Taylor3473f882001-02-23 17:55:21 +00007046 xmlXPathFreeObject(val);
7047 valuePush(ctxt, xmlXPathNewBoolean(ret));
7048}
7049
7050/**
7051 * xmlXPathNumberFunction:
7052 * @ctxt: the XPath Parser context
7053 * @nargs: the number of arguments
7054 *
7055 * Implement the number() XPath function
7056 * number number(object?)
7057 */
7058void
7059xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7060 xmlXPathObjectPtr cur;
7061 double res;
7062
7063 if (nargs == 0) {
7064 if (ctxt->context->node == NULL) {
7065 valuePush(ctxt, xmlXPathNewFloat(0.0));
7066 } else {
7067 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7068
7069 res = xmlXPathStringEvalNumber(content);
7070 valuePush(ctxt, xmlXPathNewFloat(res));
7071 xmlFree(content);
7072 }
7073 return;
7074 }
7075
7076 CHECK_ARITY(1);
7077 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007078 cur = xmlXPathConvertNumber(cur);
7079 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00007080}
7081
7082/**
7083 * xmlXPathSumFunction:
7084 * @ctxt: the XPath Parser context
7085 * @nargs: the number of arguments
7086 *
7087 * Implement the sum() XPath function
7088 * number sum(node-set)
7089 * The sum function returns the sum of the values of the nodes in
7090 * the argument node-set.
7091 */
7092void
7093xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7094 xmlXPathObjectPtr cur;
7095 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007096 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00007097
7098 CHECK_ARITY(1);
7099 if ((ctxt->value == NULL) ||
7100 ((ctxt->value->type != XPATH_NODESET) &&
7101 (ctxt->value->type != XPATH_XSLT_TREE)))
7102 XP_ERROR(XPATH_INVALID_TYPE);
7103 cur = valuePop(ctxt);
7104
William M. Brack08171912003-12-29 02:52:11 +00007105 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007106 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7107 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00007108 }
7109 }
William M. Brack08171912003-12-29 02:52:11 +00007110 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00007111 xmlXPathFreeObject(cur);
7112}
7113
7114/**
7115 * xmlXPathFloorFunction:
7116 * @ctxt: the XPath Parser context
7117 * @nargs: the number of arguments
7118 *
7119 * Implement the floor() XPath function
7120 * number floor(number)
7121 * The floor function returns the largest (closest to positive infinity)
7122 * number that is not greater than the argument and that is an integer.
7123 */
7124void
7125xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007126 double f;
7127
Owen Taylor3473f882001-02-23 17:55:21 +00007128 CHECK_ARITY(1);
7129 CAST_TO_NUMBER;
7130 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007131
7132 f = (double)((int) ctxt->value->floatval);
7133 if (f != ctxt->value->floatval) {
7134 if (ctxt->value->floatval > 0)
7135 ctxt->value->floatval = f;
7136 else
7137 ctxt->value->floatval = f - 1;
7138 }
Owen Taylor3473f882001-02-23 17:55:21 +00007139}
7140
7141/**
7142 * xmlXPathCeilingFunction:
7143 * @ctxt: the XPath Parser context
7144 * @nargs: the number of arguments
7145 *
7146 * Implement the ceiling() XPath function
7147 * number ceiling(number)
7148 * The ceiling function returns the smallest (closest to negative infinity)
7149 * number that is not less than the argument and that is an integer.
7150 */
7151void
7152xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7153 double f;
7154
7155 CHECK_ARITY(1);
7156 CAST_TO_NUMBER;
7157 CHECK_TYPE(XPATH_NUMBER);
7158
7159#if 0
7160 ctxt->value->floatval = ceil(ctxt->value->floatval);
7161#else
7162 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007163 if (f != ctxt->value->floatval) {
7164 if (ctxt->value->floatval > 0)
7165 ctxt->value->floatval = f + 1;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007166 else {
7167 if (ctxt->value->floatval < 0 && f == 0)
7168 ctxt->value->floatval = xmlXPathNZERO;
7169 else
7170 ctxt->value->floatval = f;
7171 }
7172
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007173 }
Owen Taylor3473f882001-02-23 17:55:21 +00007174#endif
7175}
7176
7177/**
7178 * xmlXPathRoundFunction:
7179 * @ctxt: the XPath Parser context
7180 * @nargs: the number of arguments
7181 *
7182 * Implement the round() XPath function
7183 * number round(number)
7184 * The round function returns the number that is closest to the
7185 * argument and that is an integer. If there are two such numbers,
7186 * then the one that is even is returned.
7187 */
7188void
7189xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7190 double f;
7191
7192 CHECK_ARITY(1);
7193 CAST_TO_NUMBER;
7194 CHECK_TYPE(XPATH_NUMBER);
7195
Daniel Veillardcda96922001-08-21 10:56:31 +00007196 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7197 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7198 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
Owen Taylor3473f882001-02-23 17:55:21 +00007199 (ctxt->value->floatval == 0.0))
7200 return;
7201
Owen Taylor3473f882001-02-23 17:55:21 +00007202 f = (double)((int) ctxt->value->floatval);
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007203 if (ctxt->value->floatval < 0) {
7204 if (ctxt->value->floatval < f - 0.5)
7205 ctxt->value->floatval = f - 1;
7206 else
7207 ctxt->value->floatval = f;
Daniel Veillard5fc1f082002-03-27 09:05:40 +00007208 if (ctxt->value->floatval == 0)
7209 ctxt->value->floatval = xmlXPathNZERO;
Daniel Veillard56cd18b2002-03-22 14:14:43 +00007210 } else {
7211 if (ctxt->value->floatval < f + 0.5)
7212 ctxt->value->floatval = f;
7213 else
7214 ctxt->value->floatval = f + 1;
7215 }
Owen Taylor3473f882001-02-23 17:55:21 +00007216}
7217
7218/************************************************************************
7219 * *
7220 * The Parser *
7221 * *
7222 ************************************************************************/
7223
7224/*
William M. Brack08171912003-12-29 02:52:11 +00007225 * a few forward declarations since we use a recursive call based
Owen Taylor3473f882001-02-23 17:55:21 +00007226 * implementation.
7227 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007228static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007229static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007230static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007231static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillard2156a562001-04-28 12:24:34 +00007232static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7233 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00007234
7235/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00007236 * xmlXPathCurrentChar:
7237 * @ctxt: the XPath parser context
7238 * @cur: pointer to the beginning of the char
7239 * @len: pointer to the length of the char read
7240 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00007241 * The current char value, if using UTF-8 this may actually span multiple
Daniel Veillard61d80a22001-04-27 17:13:01 +00007242 * bytes in the input buffer.
7243 *
Daniel Veillard60087f32001-10-10 09:45:09 +00007244 * Returns the current char value and its length
Daniel Veillard61d80a22001-04-27 17:13:01 +00007245 */
7246
7247static int
7248xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7249 unsigned char c;
7250 unsigned int val;
7251 const xmlChar *cur;
7252
7253 if (ctxt == NULL)
7254 return(0);
7255 cur = ctxt->cur;
7256
7257 /*
7258 * We are supposed to handle UTF8, check it's valid
7259 * From rfc2044: encoding of the Unicode values on UTF-8:
7260 *
7261 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7262 * 0000 0000-0000 007F 0xxxxxxx
7263 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7264 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7265 *
7266 * Check for the 0x110000 limit too
7267 */
7268 c = *cur;
7269 if (c & 0x80) {
7270 if ((cur[1] & 0xc0) != 0x80)
7271 goto encoding_error;
7272 if ((c & 0xe0) == 0xe0) {
7273
7274 if ((cur[2] & 0xc0) != 0x80)
7275 goto encoding_error;
7276 if ((c & 0xf0) == 0xf0) {
7277 if (((c & 0xf8) != 0xf0) ||
7278 ((cur[3] & 0xc0) != 0x80))
7279 goto encoding_error;
7280 /* 4-byte code */
7281 *len = 4;
7282 val = (cur[0] & 0x7) << 18;
7283 val |= (cur[1] & 0x3f) << 12;
7284 val |= (cur[2] & 0x3f) << 6;
7285 val |= cur[3] & 0x3f;
7286 } else {
7287 /* 3-byte code */
7288 *len = 3;
7289 val = (cur[0] & 0xf) << 12;
7290 val |= (cur[1] & 0x3f) << 6;
7291 val |= cur[2] & 0x3f;
7292 }
7293 } else {
7294 /* 2-byte code */
7295 *len = 2;
7296 val = (cur[0] & 0x1f) << 6;
7297 val |= cur[1] & 0x3f;
7298 }
7299 if (!IS_CHAR(val)) {
7300 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7301 }
7302 return(val);
7303 } else {
7304 /* 1-byte code */
7305 *len = 1;
7306 return((int) *cur);
7307 }
7308encoding_error:
7309 /*
William M. Brack08171912003-12-29 02:52:11 +00007310 * If we detect an UTF8 error that probably means that the
7311 * input encoding didn't get properly advertised in the
Daniel Veillard61d80a22001-04-27 17:13:01 +00007312 * declaration header. Report the error and switch the encoding
7313 * to ISO-Latin-1 (if you don't like this policy, just declare the
7314 * encoding !)
7315 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00007316 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00007317 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007318}
7319
7320/**
Owen Taylor3473f882001-02-23 17:55:21 +00007321 * xmlXPathParseNCName:
7322 * @ctxt: the XPath Parser context
7323 *
7324 * parse an XML namespace non qualified name.
7325 *
7326 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7327 *
7328 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7329 * CombiningChar | Extender
7330 *
7331 * Returns the namespace name or NULL
7332 */
7333
7334xmlChar *
7335xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00007336 const xmlChar *in;
7337 xmlChar *ret;
7338 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007339
Daniel Veillard2156a562001-04-28 12:24:34 +00007340 /*
7341 * Accelerator for simple ASCII names
7342 */
7343 in = ctxt->cur;
7344 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7345 ((*in >= 0x41) && (*in <= 0x5A)) ||
7346 (*in == '_')) {
7347 in++;
7348 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7349 ((*in >= 0x41) && (*in <= 0x5A)) ||
7350 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard9a89a8a2001-06-27 11:13:35 +00007351 (*in == '_') || (*in == '.') ||
7352 (*in == '-'))
Daniel Veillard2156a562001-04-28 12:24:34 +00007353 in++;
7354 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7355 (*in == '[') || (*in == ']') || (*in == ':') ||
7356 (*in == '@') || (*in == '*')) {
7357 count = in - ctxt->cur;
7358 if (count == 0)
7359 return(NULL);
7360 ret = xmlStrndup(ctxt->cur, count);
7361 ctxt->cur = in;
7362 return(ret);
7363 }
7364 }
7365 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00007366}
7367
Daniel Veillard2156a562001-04-28 12:24:34 +00007368
Owen Taylor3473f882001-02-23 17:55:21 +00007369/**
7370 * xmlXPathParseQName:
7371 * @ctxt: the XPath Parser context
7372 * @prefix: a xmlChar **
7373 *
7374 * parse an XML qualified name
7375 *
7376 * [NS 5] QName ::= (Prefix ':')? LocalPart
7377 *
7378 * [NS 6] Prefix ::= NCName
7379 *
7380 * [NS 7] LocalPart ::= NCName
7381 *
7382 * Returns the function returns the local part, and prefix is updated
7383 * to get the Prefix if any.
7384 */
7385
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007386static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00007387xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7388 xmlChar *ret = NULL;
7389
7390 *prefix = NULL;
7391 ret = xmlXPathParseNCName(ctxt);
7392 if (CUR == ':') {
7393 *prefix = ret;
7394 NEXT;
7395 ret = xmlXPathParseNCName(ctxt);
7396 }
7397 return(ret);
7398}
7399
7400/**
7401 * xmlXPathParseName:
7402 * @ctxt: the XPath Parser context
7403 *
7404 * parse an XML name
7405 *
7406 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7407 * CombiningChar | Extender
7408 *
7409 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7410 *
7411 * Returns the namespace name or NULL
7412 */
7413
7414xmlChar *
7415xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007416 const xmlChar *in;
7417 xmlChar *ret;
7418 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007419
Daniel Veillard61d80a22001-04-27 17:13:01 +00007420 /*
7421 * Accelerator for simple ASCII names
7422 */
7423 in = ctxt->cur;
7424 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7425 ((*in >= 0x41) && (*in <= 0x5A)) ||
7426 (*in == '_') || (*in == ':')) {
7427 in++;
7428 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7429 ((*in >= 0x41) && (*in <= 0x5A)) ||
7430 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00007431 (*in == '_') || (*in == '-') ||
7432 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00007433 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007434 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007435 count = in - ctxt->cur;
7436 ret = xmlStrndup(ctxt->cur, count);
7437 ctxt->cur = in;
7438 return(ret);
7439 }
7440 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007441 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00007442}
7443
Daniel Veillard61d80a22001-04-27 17:13:01 +00007444static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00007445xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007446 xmlChar buf[XML_MAX_NAMELEN + 5];
7447 int len = 0, l;
7448 int c;
7449
7450 /*
7451 * Handler for more complex cases
7452 */
7453 c = CUR_CHAR(l);
7454 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00007455 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7456 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00007457 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00007458 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00007459 return(NULL);
7460 }
7461
7462 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7463 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7464 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007465 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007466 (IS_COMBINING(c)) ||
7467 (IS_EXTENDER(c)))) {
7468 COPY_BUF(l,buf,len,c);
7469 NEXTL(l);
7470 c = CUR_CHAR(l);
7471 if (len >= XML_MAX_NAMELEN) {
7472 /*
7473 * Okay someone managed to make a huge name, so he's ready to pay
7474 * for the processing speed.
7475 */
7476 xmlChar *buffer;
7477 int max = len * 2;
7478
Daniel Veillard3c908dc2003-04-19 00:07:51 +00007479 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007480 if (buffer == NULL) {
7481 XP_ERROR0(XPATH_MEMORY_ERROR);
7482 }
7483 memcpy(buffer, buf, len);
7484 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7485 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00007486 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00007487 (IS_COMBINING(c)) ||
7488 (IS_EXTENDER(c))) {
7489 if (len + 10 > max) {
7490 max *= 2;
7491 buffer = (xmlChar *) xmlRealloc(buffer,
7492 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00007493 if (buffer == NULL) {
7494 XP_ERROR0(XPATH_MEMORY_ERROR);
7495 }
7496 }
7497 COPY_BUF(l,buffer,len,c);
7498 NEXTL(l);
7499 c = CUR_CHAR(l);
7500 }
7501 buffer[len] = 0;
7502 return(buffer);
7503 }
7504 }
Daniel Veillard2156a562001-04-28 12:24:34 +00007505 if (len == 0)
7506 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00007507 return(xmlStrndup(buf, len));
7508}
Daniel Veillard3cd72402002-05-13 10:33:30 +00007509
7510#define MAX_FRAC 20
7511
William M. Brack372a4452004-02-17 13:09:23 +00007512/*
7513 * These are used as divisors for the fractional part of a number.
7514 * Since the table includes 1.0 (representing '0' fractional digits),
7515 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
7516 */
7517static double my_pow10[MAX_FRAC+1] = {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007518 1.0, 10.0, 100.0, 1000.0, 10000.0,
7519 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7520 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7521 100000000000000.0,
7522 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
William M. Brack372a4452004-02-17 13:09:23 +00007523 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
Daniel Veillard3cd72402002-05-13 10:33:30 +00007524};
7525
Owen Taylor3473f882001-02-23 17:55:21 +00007526/**
7527 * xmlXPathStringEvalNumber:
7528 * @str: A string to scan
7529 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00007530 * [30a] Float ::= Number ('e' Digits?)?
7531 *
Owen Taylor3473f882001-02-23 17:55:21 +00007532 * [30] Number ::= Digits ('.' Digits?)?
7533 * | '.' Digits
7534 * [31] Digits ::= [0-9]+
7535 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007536 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00007537 * In complement of the Number expression, this function also handles
7538 * negative values : '-' Number.
7539 *
7540 * Returns the double value.
7541 */
7542double
7543xmlXPathStringEvalNumber(const xmlChar *str) {
7544 const xmlChar *cur = str;
Daniel Veillard7b416132002-03-07 08:36:03 +00007545 double ret;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007546 int ok = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007547 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007548 int exponent = 0;
7549 int is_exponent_negative = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007550#ifdef __GNUC__
7551 unsigned long tmp = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007552 double temp;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007553#endif
Daniel Veillardeca82812002-04-24 11:42:02 +00007554 if (cur == NULL) return(0);
William M. Brack76e95df2003-10-18 16:20:14 +00007555 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007556 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7557 return(xmlXPathNAN);
7558 }
7559 if (*cur == '-') {
7560 isneg = 1;
7561 cur++;
7562 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007563
7564#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007565 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007566 * tmp/temp is a workaround against a gcc compiler bug
7567 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007568 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007569 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007570 while ((*cur >= '0') && (*cur <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007571 ret = ret * 10;
7572 tmp = (*cur - '0');
Owen Taylor3473f882001-02-23 17:55:21 +00007573 ok = 1;
7574 cur++;
Daniel Veillard7b416132002-03-07 08:36:03 +00007575 temp = (double) tmp;
7576 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007577 }
Daniel Veillardb06c6142001-08-27 14:26:30 +00007578#else
Daniel Veillard7b416132002-03-07 08:36:03 +00007579 ret = 0;
Daniel Veillardb06c6142001-08-27 14:26:30 +00007580 while ((*cur >= '0') && (*cur <= '9')) {
7581 ret = ret * 10 + (*cur - '0');
7582 ok = 1;
7583 cur++;
7584 }
7585#endif
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007586
Owen Taylor3473f882001-02-23 17:55:21 +00007587 if (*cur == '.') {
Daniel Veillard3cd72402002-05-13 10:33:30 +00007588 int v, frac = 0;
7589 double fraction = 0;
7590
Owen Taylor3473f882001-02-23 17:55:21 +00007591 cur++;
7592 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7593 return(xmlXPathNAN);
7594 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007595 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7596 v = (*cur - '0');
7597 fraction = fraction * 10 + v;
7598 frac = frac + 1;
Owen Taylor3473f882001-02-23 17:55:21 +00007599 cur++;
7600 }
Daniel Veillard3cd72402002-05-13 10:33:30 +00007601 fraction /= my_pow10[frac];
7602 ret = ret + fraction;
7603 while ((*cur >= '0') && (*cur <= '9'))
7604 cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007605 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007606 if ((*cur == 'e') || (*cur == 'E')) {
7607 cur++;
7608 if (*cur == '-') {
7609 is_exponent_negative = 1;
7610 cur++;
William M. Brack99127052004-05-24 02:52:28 +00007611 } else if (*cur == '+') {
7612 cur++;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007613 }
7614 while ((*cur >= '0') && (*cur <= '9')) {
7615 exponent = exponent * 10 + (*cur - '0');
7616 cur++;
7617 }
7618 }
William M. Brack76e95df2003-10-18 16:20:14 +00007619 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00007620 if (*cur != 0) return(xmlXPathNAN);
7621 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007622 if (is_exponent_negative) exponent = -exponent;
7623 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00007624 return(ret);
7625}
7626
7627/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007628 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00007629 * @ctxt: the XPath Parser context
7630 *
7631 * [30] Number ::= Digits ('.' Digits?)?
7632 * | '.' Digits
7633 * [31] Digits ::= [0-9]+
7634 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007635 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00007636 *
7637 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007638static void
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007639xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7640{
Owen Taylor3473f882001-02-23 17:55:21 +00007641 double ret = 0.0;
7642 double mult = 1;
Daniel Veillard7b416132002-03-07 08:36:03 +00007643 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00007644 int exponent = 0;
7645 int is_exponent_negative = 0;
Daniel Veillard7b416132002-03-07 08:36:03 +00007646#ifdef __GNUC__
7647 unsigned long tmp = 0;
7648 double temp;
7649#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007650
7651 CHECK_ERROR;
7652 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7653 XP_ERROR(XPATH_NUMBER_ERROR);
7654 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007655#ifdef __GNUC__
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007656 /*
Daniel Veillard7b416132002-03-07 08:36:03 +00007657 * tmp/temp is a workaround against a gcc compiler bug
7658 * http://veillard.com/gcc.bug
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007659 */
Daniel Veillard7b416132002-03-07 08:36:03 +00007660 ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00007661 while ((CUR >= '0') && (CUR <= '9')) {
Daniel Veillard7b416132002-03-07 08:36:03 +00007662 ret = ret * 10;
7663 tmp = (CUR - '0');
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007664 ok = 1;
7665 NEXT;
Daniel Veillard7b416132002-03-07 08:36:03 +00007666 temp = (double) tmp;
7667 ret = ret + temp;
Owen Taylor3473f882001-02-23 17:55:21 +00007668 }
Daniel Veillard7b416132002-03-07 08:36:03 +00007669#else
7670 ret = 0;
7671 while ((CUR >= '0') && (CUR <= '9')) {
7672 ret = ret * 10 + (CUR - '0');
7673 ok = 1;
7674 NEXT;
7675 }
7676#endif
Owen Taylor3473f882001-02-23 17:55:21 +00007677 if (CUR == '.') {
7678 NEXT;
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007679 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7680 XP_ERROR(XPATH_NUMBER_ERROR);
7681 }
7682 while ((CUR >= '0') && (CUR <= '9')) {
7683 mult /= 10;
7684 ret = ret + (CUR - '0') * mult;
7685 NEXT;
7686 }
Owen Taylor3473f882001-02-23 17:55:21 +00007687 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00007688 if ((CUR == 'e') || (CUR == 'E')) {
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007689 NEXT;
7690 if (CUR == '-') {
7691 is_exponent_negative = 1;
7692 NEXT;
William M. Brack99127052004-05-24 02:52:28 +00007693 } else if (CUR == '+') {
7694 NEXT;
7695 }
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007696 while ((CUR >= '0') && (CUR <= '9')) {
7697 exponent = exponent * 10 + (CUR - '0');
7698 NEXT;
7699 }
7700 if (is_exponent_negative)
7701 exponent = -exponent;
7702 ret *= pow(10.0, (double) exponent);
Bjorn Reese70a9da52001-04-21 16:57:29 +00007703 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007704 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
Daniel Veillardd79bcd12001-06-21 22:07:42 +00007705 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007706}
7707
7708/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007709 * xmlXPathParseLiteral:
7710 * @ctxt: the XPath Parser context
7711 *
7712 * Parse a Literal
7713 *
7714 * [29] Literal ::= '"' [^"]* '"'
7715 * | "'" [^']* "'"
7716 *
7717 * Returns the value found or NULL in case of error
7718 */
7719static xmlChar *
7720xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7721 const xmlChar *q;
7722 xmlChar *ret = NULL;
7723
7724 if (CUR == '"') {
7725 NEXT;
7726 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007727 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007728 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007729 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007730 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7731 } else {
7732 ret = xmlStrndup(q, CUR_PTR - q);
7733 NEXT;
7734 }
7735 } else if (CUR == '\'') {
7736 NEXT;
7737 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007738 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007739 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007740 if (!IS_CHAR_CH(CUR)) {
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007741 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7742 } else {
7743 ret = xmlStrndup(q, CUR_PTR - q);
7744 NEXT;
7745 }
7746 } else {
7747 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7748 }
7749 return(ret);
7750}
7751
7752/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007753 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00007754 * @ctxt: the XPath Parser context
7755 *
7756 * Parse a Literal and push it on the stack.
7757 *
7758 * [29] Literal ::= '"' [^"]* '"'
7759 * | "'" [^']* "'"
7760 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007761 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00007762 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007763static void
7764xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007765 const xmlChar *q;
7766 xmlChar *ret = NULL;
7767
7768 if (CUR == '"') {
7769 NEXT;
7770 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007771 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
Owen Taylor3473f882001-02-23 17:55:21 +00007772 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007773 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007774 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7775 } else {
7776 ret = xmlStrndup(q, CUR_PTR - q);
7777 NEXT;
7778 }
7779 } else if (CUR == '\'') {
7780 NEXT;
7781 q = CUR_PTR;
William M. Brack76e95df2003-10-18 16:20:14 +00007782 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
Owen Taylor3473f882001-02-23 17:55:21 +00007783 NEXT;
William M. Brack76e95df2003-10-18 16:20:14 +00007784 if (!IS_CHAR_CH(CUR)) {
Owen Taylor3473f882001-02-23 17:55:21 +00007785 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7786 } else {
7787 ret = xmlStrndup(q, CUR_PTR - q);
7788 NEXT;
7789 }
7790 } else {
7791 XP_ERROR(XPATH_START_LITERAL_ERROR);
7792 }
7793 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007794 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7795 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007796 xmlFree(ret);
7797}
7798
7799/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007800 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00007801 * @ctxt: the XPath Parser context
7802 *
7803 * Parse a VariableReference, evaluate it and push it on the stack.
7804 *
7805 * The variable bindings consist of a mapping from variable names
William M. Brack08171912003-12-29 02:52:11 +00007806 * to variable values. The value of a variable is an object, which can be
Owen Taylor3473f882001-02-23 17:55:21 +00007807 * of any of the types that are possible for the value of an expression,
7808 * and may also be of additional types not specified here.
7809 *
7810 * Early evaluation is possible since:
7811 * The variable bindings [...] used to evaluate a subexpression are
7812 * always the same as those used to evaluate the containing expression.
7813 *
7814 * [36] VariableReference ::= '$' QName
7815 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007816static void
7817xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007818 xmlChar *name;
7819 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007820
7821 SKIP_BLANKS;
7822 if (CUR != '$') {
7823 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7824 }
7825 NEXT;
7826 name = xmlXPathParseQName(ctxt, &prefix);
7827 if (name == NULL) {
7828 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7829 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007830 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007831 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7832 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007833 SKIP_BLANKS;
7834}
7835
7836/**
7837 * xmlXPathIsNodeType:
Owen Taylor3473f882001-02-23 17:55:21 +00007838 * @name: a name string
7839 *
7840 * Is the name given a NodeType one.
7841 *
7842 * [38] NodeType ::= 'comment'
7843 * | 'text'
7844 * | 'processing-instruction'
7845 * | 'node'
7846 *
7847 * Returns 1 if true 0 otherwise
7848 */
7849int
7850xmlXPathIsNodeType(const xmlChar *name) {
7851 if (name == NULL)
7852 return(0);
7853
Daniel Veillard1971ee22002-01-31 20:29:19 +00007854 if (xmlStrEqual(name, BAD_CAST "node"))
Owen Taylor3473f882001-02-23 17:55:21 +00007855 return(1);
7856 if (xmlStrEqual(name, BAD_CAST "text"))
7857 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007858 if (xmlStrEqual(name, BAD_CAST "comment"))
Owen Taylor3473f882001-02-23 17:55:21 +00007859 return(1);
Daniel Veillard1971ee22002-01-31 20:29:19 +00007860 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
Owen Taylor3473f882001-02-23 17:55:21 +00007861 return(1);
7862 return(0);
7863}
7864
7865/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007866 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00007867 * @ctxt: the XPath Parser context
7868 *
7869 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7870 * [17] Argument ::= Expr
7871 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007872 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00007873 * pushed on the stack
7874 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007875static void
7876xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007877 xmlChar *name;
7878 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00007879 int nbargs = 0;
7880
7881 name = xmlXPathParseQName(ctxt, &prefix);
7882 if (name == NULL) {
7883 XP_ERROR(XPATH_EXPR_ERROR);
7884 }
7885 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007886#ifdef DEBUG_EXPR
7887 if (prefix == NULL)
7888 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7889 name);
7890 else
7891 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7892 prefix, name);
7893#endif
7894
Owen Taylor3473f882001-02-23 17:55:21 +00007895 if (CUR != '(') {
7896 XP_ERROR(XPATH_EXPR_ERROR);
7897 }
7898 NEXT;
7899 SKIP_BLANKS;
7900
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007901 ctxt->comp->last = -1;
Daniel Veillard71f9d732003-01-14 16:07:16 +00007902 if (CUR != ')') {
7903 while (CUR != 0) {
7904 int op1 = ctxt->comp->last;
7905 ctxt->comp->last = -1;
7906 xmlXPathCompileExpr(ctxt);
7907 CHECK_ERROR;
7908 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7909 nbargs++;
7910 if (CUR == ')') break;
7911 if (CUR != ',') {
7912 XP_ERROR(XPATH_EXPR_ERROR);
7913 }
7914 NEXT;
7915 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007916 }
Owen Taylor3473f882001-02-23 17:55:21 +00007917 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007918 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7919 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00007920 NEXT;
7921 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00007922}
7923
7924/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007925 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007926 * @ctxt: the XPath Parser context
7927 *
7928 * [15] PrimaryExpr ::= VariableReference
7929 * | '(' Expr ')'
7930 * | Literal
7931 * | Number
7932 * | FunctionCall
7933 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007934 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007935 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007936static void
7937xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007938 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007939 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007940 else if (CUR == '(') {
7941 NEXT;
7942 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007943 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +00007944 CHECK_ERROR;
Owen Taylor3473f882001-02-23 17:55:21 +00007945 if (CUR != ')') {
7946 XP_ERROR(XPATH_EXPR_ERROR);
7947 }
7948 NEXT;
7949 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00007950 } else if (IS_DIGIT_CH(CUR) || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007951 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007952 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007953 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007954 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007955 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007956 }
7957 SKIP_BLANKS;
7958}
7959
7960/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007961 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00007962 * @ctxt: the XPath Parser context
7963 *
7964 * [20] FilterExpr ::= PrimaryExpr
7965 * | FilterExpr Predicate
7966 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007967 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00007968 * Square brackets are used to filter expressions in the same way that
7969 * they are used in location paths. It is an error if the expression to
7970 * be filtered does not evaluate to a node-set. The context node list
7971 * used for evaluating the expression in square brackets is the node-set
7972 * to be filtered listed in document order.
7973 */
7974
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007975static void
7976xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7977 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007978 CHECK_ERROR;
7979 SKIP_BLANKS;
7980
7981 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007982 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00007983 SKIP_BLANKS;
7984 }
7985
7986
7987}
7988
7989/**
7990 * xmlXPathScanName:
7991 * @ctxt: the XPath Parser context
7992 *
7993 * Trickery: parse an XML name but without consuming the input flow
7994 * Needed to avoid insanity in the parser state.
7995 *
7996 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7997 * CombiningChar | Extender
7998 *
7999 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8000 *
8001 * [6] Names ::= Name (S Name)*
8002 *
8003 * Returns the Name parsed or NULL
8004 */
8005
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008006static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00008007xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8008 xmlChar buf[XML_MAX_NAMELEN];
8009 int len = 0;
8010
8011 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00008012 if (!IS_LETTER_CH(CUR) && (CUR != '_') &&
Owen Taylor3473f882001-02-23 17:55:21 +00008013 (CUR != ':')) {
8014 return(NULL);
8015 }
8016
William M. Brack76e95df2003-10-18 16:20:14 +00008017 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008018 (NXT(len) == '.') || (NXT(len) == '-') ||
8019 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008020 (IS_COMBINING_CH(NXT(len))) ||
8021 (IS_EXTENDER_CH(NXT(len)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008022 buf[len] = NXT(len);
8023 len++;
8024 if (len >= XML_MAX_NAMELEN) {
8025 xmlGenericError(xmlGenericErrorContext,
8026 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
William M. Brack76e95df2003-10-18 16:20:14 +00008027 while ((IS_LETTER_CH(NXT(len))) || (IS_DIGIT_CH(NXT(len))) ||
Owen Taylor3473f882001-02-23 17:55:21 +00008028 (NXT(len) == '.') || (NXT(len) == '-') ||
8029 (NXT(len) == '_') || (NXT(len) == ':') ||
William M. Brack76e95df2003-10-18 16:20:14 +00008030 (IS_COMBINING_CH(NXT(len))) ||
8031 (IS_EXTENDER_CH(NXT(len))))
Owen Taylor3473f882001-02-23 17:55:21 +00008032 len++;
8033 break;
8034 }
8035 }
8036 return(xmlStrndup(buf, len));
8037}
8038
8039/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008040 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008041 * @ctxt: the XPath Parser context
8042 *
8043 * [19] PathExpr ::= LocationPath
8044 * | FilterExpr
8045 * | FilterExpr '/' RelativeLocationPath
8046 * | FilterExpr '//' RelativeLocationPath
8047 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008048 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008049 * The / operator and // operators combine an arbitrary expression
8050 * and a relative location path. It is an error if the expression
8051 * does not evaluate to a node-set.
8052 * The / operator does composition in the same way as when / is
8053 * used in a location path. As in location paths, // is short for
8054 * /descendant-or-self::node()/.
8055 */
8056
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008057static void
8058xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008059 int lc = 1; /* Should we branch to LocationPath ? */
8060 xmlChar *name = NULL; /* we may have to preparse a name to find out */
8061
8062 SKIP_BLANKS;
William M. Brack76e95df2003-10-18 16:20:14 +00008063 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT_CH(CUR)) ||
8064 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT_CH(NXT(1)))) {
Owen Taylor3473f882001-02-23 17:55:21 +00008065 lc = 0;
8066 } else if (CUR == '*') {
8067 /* relative or absolute location path */
8068 lc = 1;
8069 } else if (CUR == '/') {
8070 /* relative or absolute location path */
8071 lc = 1;
8072 } else if (CUR == '@') {
8073 /* relative abbreviated attribute location path */
8074 lc = 1;
8075 } else if (CUR == '.') {
8076 /* relative abbreviated attribute location path */
8077 lc = 1;
8078 } else {
8079 /*
8080 * Problem is finding if we have a name here whether it's:
8081 * - a nodetype
8082 * - a function call in which case it's followed by '('
8083 * - an axis in which case it's followed by ':'
8084 * - a element name
8085 * We do an a priori analysis here rather than having to
8086 * maintain parsed token content through the recursive function
William M. Brack08171912003-12-29 02:52:11 +00008087 * calls. This looks uglier but makes the code easier to
Owen Taylor3473f882001-02-23 17:55:21 +00008088 * read/write/debug.
8089 */
8090 SKIP_BLANKS;
8091 name = xmlXPathScanName(ctxt);
8092 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8093#ifdef DEBUG_STEP
8094 xmlGenericError(xmlGenericErrorContext,
8095 "PathExpr: Axis\n");
8096#endif
8097 lc = 1;
8098 xmlFree(name);
8099 } else if (name != NULL) {
8100 int len =xmlStrlen(name);
Owen Taylor3473f882001-02-23 17:55:21 +00008101
8102
8103 while (NXT(len) != 0) {
8104 if (NXT(len) == '/') {
8105 /* element name */
8106#ifdef DEBUG_STEP
8107 xmlGenericError(xmlGenericErrorContext,
8108 "PathExpr: AbbrRelLocation\n");
8109#endif
8110 lc = 1;
8111 break;
William M. Brack76e95df2003-10-18 16:20:14 +00008112 } else if (IS_BLANK_CH(NXT(len))) {
William M. Brack78637da2003-07-31 14:47:38 +00008113 /* ignore blanks */
8114 ;
Owen Taylor3473f882001-02-23 17:55:21 +00008115 } else if (NXT(len) == ':') {
8116#ifdef DEBUG_STEP
8117 xmlGenericError(xmlGenericErrorContext,
8118 "PathExpr: AbbrRelLocation\n");
8119#endif
8120 lc = 1;
8121 break;
8122 } else if ((NXT(len) == '(')) {
8123 /* Note Type or Function */
8124 if (xmlXPathIsNodeType(name)) {
8125#ifdef DEBUG_STEP
8126 xmlGenericError(xmlGenericErrorContext,
8127 "PathExpr: Type search\n");
8128#endif
8129 lc = 1;
8130 } else {
8131#ifdef DEBUG_STEP
8132 xmlGenericError(xmlGenericErrorContext,
8133 "PathExpr: function call\n");
8134#endif
8135 lc = 0;
8136 }
8137 break;
8138 } else if ((NXT(len) == '[')) {
8139 /* element name */
8140#ifdef DEBUG_STEP
8141 xmlGenericError(xmlGenericErrorContext,
8142 "PathExpr: AbbrRelLocation\n");
8143#endif
8144 lc = 1;
8145 break;
8146 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8147 (NXT(len) == '=')) {
8148 lc = 1;
8149 break;
8150 } else {
8151 lc = 1;
8152 break;
8153 }
8154 len++;
8155 }
8156 if (NXT(len) == 0) {
8157#ifdef DEBUG_STEP
8158 xmlGenericError(xmlGenericErrorContext,
8159 "PathExpr: AbbrRelLocation\n");
8160#endif
8161 /* element name */
8162 lc = 1;
8163 }
8164 xmlFree(name);
8165 } else {
William M. Brack08171912003-12-29 02:52:11 +00008166 /* make sure all cases are covered explicitly */
Owen Taylor3473f882001-02-23 17:55:21 +00008167 XP_ERROR(XPATH_EXPR_ERROR);
8168 }
8169 }
8170
8171 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008172 if (CUR == '/') {
8173 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8174 } else {
8175 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008176 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008177 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008178 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008179 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008180 CHECK_ERROR;
8181 if ((CUR == '/') && (NXT(1) == '/')) {
8182 SKIP(2);
8183 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008184
8185 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8186 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8187 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8188
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008189 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008190 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008191 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008192 }
8193 }
8194 SKIP_BLANKS;
8195}
8196
8197/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008198 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008199 * @ctxt: the XPath Parser context
8200 *
8201 * [18] UnionExpr ::= PathExpr
8202 * | UnionExpr '|' PathExpr
8203 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008204 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008205 */
8206
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008207static void
8208xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8209 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008210 CHECK_ERROR;
8211 SKIP_BLANKS;
8212 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008213 int op1 = ctxt->comp->last;
8214 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008215
8216 NEXT;
8217 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008218 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008219
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008220 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8221
Owen Taylor3473f882001-02-23 17:55:21 +00008222 SKIP_BLANKS;
8223 }
Owen Taylor3473f882001-02-23 17:55:21 +00008224}
8225
8226/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008227 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008228 * @ctxt: the XPath Parser context
8229 *
8230 * [27] UnaryExpr ::= UnionExpr
8231 * | '-' UnaryExpr
8232 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008233 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008234 */
8235
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008236static void
8237xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008238 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008239 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008240
8241 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00008242 while (CUR == '-') {
8243 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008244 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008245 NEXT;
8246 SKIP_BLANKS;
8247 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008248
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008249 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008250 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008251 if (found) {
8252 if (minus)
8253 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8254 else
8255 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008256 }
8257}
8258
8259/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008260 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008261 * @ctxt: the XPath Parser context
8262 *
8263 * [26] MultiplicativeExpr ::= UnaryExpr
8264 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8265 * | MultiplicativeExpr 'div' UnaryExpr
8266 * | MultiplicativeExpr 'mod' UnaryExpr
8267 * [34] MultiplyOperator ::= '*'
8268 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008269 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008270 */
8271
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008272static void
8273xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8274 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008275 CHECK_ERROR;
8276 SKIP_BLANKS;
8277 while ((CUR == '*') ||
8278 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8279 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8280 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008281 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008282
8283 if (CUR == '*') {
8284 op = 0;
8285 NEXT;
8286 } else if (CUR == 'd') {
8287 op = 1;
8288 SKIP(3);
8289 } else if (CUR == 'm') {
8290 op = 2;
8291 SKIP(3);
8292 }
8293 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008294 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008295 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008296 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008297 SKIP_BLANKS;
8298 }
8299}
8300
8301/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008302 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008303 * @ctxt: the XPath Parser context
8304 *
8305 * [25] AdditiveExpr ::= MultiplicativeExpr
8306 * | AdditiveExpr '+' MultiplicativeExpr
8307 * | AdditiveExpr '-' MultiplicativeExpr
8308 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008309 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008310 */
8311
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008312static void
8313xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008314
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008315 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008316 CHECK_ERROR;
8317 SKIP_BLANKS;
8318 while ((CUR == '+') || (CUR == '-')) {
8319 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008320 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008321
8322 if (CUR == '+') plus = 1;
8323 else plus = 0;
8324 NEXT;
8325 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008326 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008327 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008328 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008329 SKIP_BLANKS;
8330 }
8331}
8332
8333/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008334 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008335 * @ctxt: the XPath Parser context
8336 *
8337 * [24] RelationalExpr ::= AdditiveExpr
8338 * | RelationalExpr '<' AdditiveExpr
8339 * | RelationalExpr '>' AdditiveExpr
8340 * | RelationalExpr '<=' AdditiveExpr
8341 * | RelationalExpr '>=' AdditiveExpr
8342 *
8343 * A <= B > C is allowed ? Answer from James, yes with
8344 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8345 * which is basically what got implemented.
8346 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008347 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00008348 * on the stack
8349 */
8350
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008351static void
8352xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8353 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008354 CHECK_ERROR;
8355 SKIP_BLANKS;
8356 while ((CUR == '<') ||
8357 (CUR == '>') ||
8358 ((CUR == '<') && (NXT(1) == '=')) ||
8359 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008360 int inf, strict;
8361 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008362
8363 if (CUR == '<') inf = 1;
8364 else inf = 0;
8365 if (NXT(1) == '=') strict = 0;
8366 else strict = 1;
8367 NEXT;
8368 if (!strict) NEXT;
8369 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008370 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008371 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008372 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00008373 SKIP_BLANKS;
8374 }
8375}
8376
8377/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008378 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008379 * @ctxt: the XPath Parser context
8380 *
8381 * [23] EqualityExpr ::= RelationalExpr
8382 * | EqualityExpr '=' RelationalExpr
8383 * | EqualityExpr '!=' RelationalExpr
8384 *
8385 * A != B != C is allowed ? Answer from James, yes with
8386 * (RelationalExpr = RelationalExpr) = RelationalExpr
8387 * (RelationalExpr != RelationalExpr) != RelationalExpr
8388 * which is basically what got implemented.
8389 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008390 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008391 *
8392 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008393static void
8394xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8395 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008396 CHECK_ERROR;
8397 SKIP_BLANKS;
8398 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008399 int eq;
8400 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008401
8402 if (CUR == '=') eq = 1;
8403 else eq = 0;
8404 NEXT;
8405 if (!eq) NEXT;
8406 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008407 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008408 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008409 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008410 SKIP_BLANKS;
8411 }
8412}
8413
8414/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008415 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008416 * @ctxt: the XPath Parser context
8417 *
8418 * [22] AndExpr ::= EqualityExpr
8419 * | AndExpr 'and' EqualityExpr
8420 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008421 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00008422 *
8423 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008424static void
8425xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8426 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008427 CHECK_ERROR;
8428 SKIP_BLANKS;
8429 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008430 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008431 SKIP(3);
8432 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008433 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008434 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008435 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008436 SKIP_BLANKS;
8437 }
8438}
8439
8440/**
Daniel Veillard591b4be2003-02-09 23:33:36 +00008441 * xmlXPathCompileExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00008442 * @ctxt: the XPath Parser context
8443 *
8444 * [14] Expr ::= OrExpr
8445 * [21] OrExpr ::= AndExpr
8446 * | OrExpr 'or' AndExpr
8447 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008448 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00008449 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008450static void
8451xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8452 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008453 CHECK_ERROR;
8454 SKIP_BLANKS;
8455 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008456 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008457 SKIP(2);
8458 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008459 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008460 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008461 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8462 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00008463 SKIP_BLANKS;
8464 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008465 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8466 /* more ops could be optimized too */
8467 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8468 }
Owen Taylor3473f882001-02-23 17:55:21 +00008469}
8470
8471/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008472 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00008473 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008474 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00008475 *
8476 * [8] Predicate ::= '[' PredicateExpr ']'
8477 * [9] PredicateExpr ::= Expr
8478 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008479 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00008480 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008481static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008482xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008483 int op1 = ctxt->comp->last;
8484
8485 SKIP_BLANKS;
8486 if (CUR != '[') {
8487 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8488 }
8489 NEXT;
8490 SKIP_BLANKS;
8491
8492 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008493 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008494 CHECK_ERROR;
8495
8496 if (CUR != ']') {
8497 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8498 }
8499
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008500 if (filter)
8501 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8502 else
8503 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008504
8505 NEXT;
8506 SKIP_BLANKS;
8507}
8508
8509/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008510 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00008511 * @ctxt: the XPath Parser context
8512 * @test: pointer to a xmlXPathTestVal
8513 * @type: pointer to a xmlXPathTypeVal
8514 * @prefix: placeholder for a possible name prefix
8515 *
8516 * [7] NodeTest ::= NameTest
8517 * | NodeType '(' ')'
8518 * | 'processing-instruction' '(' Literal ')'
8519 *
8520 * [37] NameTest ::= '*'
8521 * | NCName ':' '*'
8522 * | QName
8523 * [38] NodeType ::= 'comment'
8524 * | 'text'
8525 * | 'processing-instruction'
8526 * | 'node'
8527 *
William M. Brack08171912003-12-29 02:52:11 +00008528 * Returns the name found and updates @test, @type and @prefix appropriately
Owen Taylor3473f882001-02-23 17:55:21 +00008529 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008530static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008531xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8532 xmlXPathTypeVal *type, const xmlChar **prefix,
8533 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00008534 int blanks;
8535
8536 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8537 STRANGE;
8538 return(NULL);
8539 }
William M. Brack78637da2003-07-31 14:47:38 +00008540 *type = (xmlXPathTypeVal) 0;
8541 *test = (xmlXPathTestVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008542 *prefix = NULL;
8543 SKIP_BLANKS;
8544
8545 if ((name == NULL) && (CUR == '*')) {
8546 /*
8547 * All elements
8548 */
8549 NEXT;
8550 *test = NODE_TEST_ALL;
8551 return(NULL);
8552 }
8553
8554 if (name == NULL)
8555 name = xmlXPathParseNCName(ctxt);
8556 if (name == NULL) {
8557 XP_ERROR0(XPATH_EXPR_ERROR);
8558 }
8559
William M. Brack76e95df2003-10-18 16:20:14 +00008560 blanks = IS_BLANK_CH(CUR);
Owen Taylor3473f882001-02-23 17:55:21 +00008561 SKIP_BLANKS;
8562 if (CUR == '(') {
8563 NEXT;
8564 /*
8565 * NodeType or PI search
8566 */
8567 if (xmlStrEqual(name, BAD_CAST "comment"))
8568 *type = NODE_TYPE_COMMENT;
8569 else if (xmlStrEqual(name, BAD_CAST "node"))
8570 *type = NODE_TYPE_NODE;
8571 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8572 *type = NODE_TYPE_PI;
8573 else if (xmlStrEqual(name, BAD_CAST "text"))
8574 *type = NODE_TYPE_TEXT;
8575 else {
8576 if (name != NULL)
8577 xmlFree(name);
8578 XP_ERROR0(XPATH_EXPR_ERROR);
8579 }
8580
8581 *test = NODE_TEST_TYPE;
8582
8583 SKIP_BLANKS;
8584 if (*type == NODE_TYPE_PI) {
8585 /*
8586 * Specific case: search a PI by name.
8587 */
Owen Taylor3473f882001-02-23 17:55:21 +00008588 if (name != NULL)
8589 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00008590 name = NULL;
8591 if (CUR != ')') {
8592 name = xmlXPathParseLiteral(ctxt);
8593 CHECK_ERROR 0;
Daniel Veillarded23b7d2002-05-27 12:16:02 +00008594 *test = NODE_TEST_PI;
Daniel Veillard82e49712001-04-26 14:38:03 +00008595 SKIP_BLANKS;
8596 }
Owen Taylor3473f882001-02-23 17:55:21 +00008597 }
8598 if (CUR != ')') {
8599 if (name != NULL)
8600 xmlFree(name);
8601 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8602 }
8603 NEXT;
8604 return(name);
8605 }
8606 *test = NODE_TEST_NAME;
8607 if ((!blanks) && (CUR == ':')) {
8608 NEXT;
8609
8610 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008611 * Since currently the parser context don't have a
8612 * namespace list associated:
8613 * The namespace name for this prefix can be computed
8614 * only at evaluation time. The compilation is done
8615 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00008616 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008617#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00008618 *prefix = xmlXPathNsLookup(ctxt->context, name);
8619 if (name != NULL)
8620 xmlFree(name);
8621 if (*prefix == NULL) {
8622 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8623 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008624#else
8625 *prefix = name;
8626#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008627
8628 if (CUR == '*') {
8629 /*
8630 * All elements
8631 */
8632 NEXT;
8633 *test = NODE_TEST_ALL;
8634 return(NULL);
8635 }
8636
8637 name = xmlXPathParseNCName(ctxt);
8638 if (name == NULL) {
8639 XP_ERROR0(XPATH_EXPR_ERROR);
8640 }
8641 }
8642 return(name);
8643}
8644
8645/**
8646 * xmlXPathIsAxisName:
8647 * @name: a preparsed name token
8648 *
8649 * [6] AxisName ::= 'ancestor'
8650 * | 'ancestor-or-self'
8651 * | 'attribute'
8652 * | 'child'
8653 * | 'descendant'
8654 * | 'descendant-or-self'
8655 * | 'following'
8656 * | 'following-sibling'
8657 * | 'namespace'
8658 * | 'parent'
8659 * | 'preceding'
8660 * | 'preceding-sibling'
8661 * | 'self'
8662 *
8663 * Returns the axis or 0
8664 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00008665static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00008666xmlXPathIsAxisName(const xmlChar *name) {
William M. Brack78637da2003-07-31 14:47:38 +00008667 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008668 switch (name[0]) {
8669 case 'a':
8670 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8671 ret = AXIS_ANCESTOR;
8672 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8673 ret = AXIS_ANCESTOR_OR_SELF;
8674 if (xmlStrEqual(name, BAD_CAST "attribute"))
8675 ret = AXIS_ATTRIBUTE;
8676 break;
8677 case 'c':
8678 if (xmlStrEqual(name, BAD_CAST "child"))
8679 ret = AXIS_CHILD;
8680 break;
8681 case 'd':
8682 if (xmlStrEqual(name, BAD_CAST "descendant"))
8683 ret = AXIS_DESCENDANT;
8684 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8685 ret = AXIS_DESCENDANT_OR_SELF;
8686 break;
8687 case 'f':
8688 if (xmlStrEqual(name, BAD_CAST "following"))
8689 ret = AXIS_FOLLOWING;
8690 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8691 ret = AXIS_FOLLOWING_SIBLING;
8692 break;
8693 case 'n':
8694 if (xmlStrEqual(name, BAD_CAST "namespace"))
8695 ret = AXIS_NAMESPACE;
8696 break;
8697 case 'p':
8698 if (xmlStrEqual(name, BAD_CAST "parent"))
8699 ret = AXIS_PARENT;
8700 if (xmlStrEqual(name, BAD_CAST "preceding"))
8701 ret = AXIS_PRECEDING;
8702 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8703 ret = AXIS_PRECEDING_SIBLING;
8704 break;
8705 case 's':
8706 if (xmlStrEqual(name, BAD_CAST "self"))
8707 ret = AXIS_SELF;
8708 break;
8709 }
8710 return(ret);
8711}
8712
8713/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008714 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00008715 * @ctxt: the XPath Parser context
8716 *
8717 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8718 * | AbbreviatedStep
8719 *
8720 * [12] AbbreviatedStep ::= '.' | '..'
8721 *
8722 * [5] AxisSpecifier ::= AxisName '::'
8723 * | AbbreviatedAxisSpecifier
8724 *
8725 * [13] AbbreviatedAxisSpecifier ::= '@'?
8726 *
8727 * Modified for XPtr range support as:
8728 *
8729 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8730 * | AbbreviatedStep
8731 * | 'range-to' '(' Expr ')' Predicate*
8732 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008733 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00008734 * A location step of . is short for self::node(). This is
8735 * particularly useful in conjunction with //. For example, the
8736 * location path .//para is short for
8737 * self::node()/descendant-or-self::node()/child::para
8738 * and so will select all para descendant elements of the context
8739 * node.
8740 * Similarly, a location step of .. is short for parent::node().
8741 * For example, ../title is short for parent::node()/child::title
8742 * and so will select the title children of the parent of the context
8743 * node.
8744 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008745static void
8746xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008747#ifdef LIBXML_XPTR_ENABLED
8748 int rangeto = 0;
8749 int op2 = -1;
8750#endif
8751
Owen Taylor3473f882001-02-23 17:55:21 +00008752 SKIP_BLANKS;
8753 if ((CUR == '.') && (NXT(1) == '.')) {
8754 SKIP(2);
8755 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008756 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8757 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008758 } else if (CUR == '.') {
8759 NEXT;
8760 SKIP_BLANKS;
8761 } else {
8762 xmlChar *name = NULL;
8763 const xmlChar *prefix = NULL;
8764 xmlXPathTestVal test;
William M. Brack78637da2003-07-31 14:47:38 +00008765 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
Owen Taylor3473f882001-02-23 17:55:21 +00008766 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008767 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00008768
8769 /*
8770 * The modification needed for XPointer change to the production
8771 */
8772#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00008773 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00008774 name = xmlXPathParseNCName(ctxt);
8775 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008776 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00008777 xmlFree(name);
8778 SKIP_BLANKS;
8779 if (CUR != '(') {
8780 XP_ERROR(XPATH_EXPR_ERROR);
8781 }
8782 NEXT;
8783 SKIP_BLANKS;
8784
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008785 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008786 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00008787 CHECK_ERROR;
8788
8789 SKIP_BLANKS;
8790 if (CUR != ')') {
8791 XP_ERROR(XPATH_EXPR_ERROR);
8792 }
8793 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008794 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00008795 goto eval_predicates;
8796 }
8797 }
8798#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00008799 if (CUR == '*') {
8800 axis = AXIS_CHILD;
8801 } else {
8802 if (name == NULL)
8803 name = xmlXPathParseNCName(ctxt);
8804 if (name != NULL) {
8805 axis = xmlXPathIsAxisName(name);
8806 if (axis != 0) {
8807 SKIP_BLANKS;
8808 if ((CUR == ':') && (NXT(1) == ':')) {
8809 SKIP(2);
8810 xmlFree(name);
8811 name = NULL;
8812 } else {
8813 /* an element name can conflict with an axis one :-\ */
8814 axis = AXIS_CHILD;
8815 }
Owen Taylor3473f882001-02-23 17:55:21 +00008816 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00008817 axis = AXIS_CHILD;
8818 }
Daniel Veillard2156a562001-04-28 12:24:34 +00008819 } else if (CUR == '@') {
8820 NEXT;
8821 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00008822 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00008823 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00008824 }
Owen Taylor3473f882001-02-23 17:55:21 +00008825 }
8826
8827 CHECK_ERROR;
8828
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008829 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00008830 if (test == 0)
8831 return;
8832
8833#ifdef DEBUG_STEP
8834 xmlGenericError(xmlGenericErrorContext,
8835 "Basis : computing new set\n");
8836#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008837
Owen Taylor3473f882001-02-23 17:55:21 +00008838#ifdef DEBUG_STEP
8839 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008840 if (ctxt->value == NULL)
8841 xmlGenericError(xmlGenericErrorContext, "no value\n");
8842 else if (ctxt->value->nodesetval == NULL)
8843 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8844 else
8845 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008846#endif
Owen Taylor3473f882001-02-23 17:55:21 +00008847
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008848#ifdef LIBXML_XPTR_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00008849eval_predicates:
Daniel Veillard5bb9ccd2004-02-09 12:39:02 +00008850#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008851 op1 = ctxt->comp->last;
8852 ctxt->comp->last = -1;
8853
Owen Taylor3473f882001-02-23 17:55:21 +00008854 SKIP_BLANKS;
8855 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008856 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00008857 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008858
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008859#ifdef LIBXML_XPTR_ENABLED
8860 if (rangeto) {
8861 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8862 } else
8863#endif
8864 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8865 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008866
Owen Taylor3473f882001-02-23 17:55:21 +00008867 }
8868#ifdef DEBUG_STEP
8869 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00008870 if (ctxt->value == NULL)
8871 xmlGenericError(xmlGenericErrorContext, "no value\n");
8872 else if (ctxt->value->nodesetval == NULL)
8873 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8874 else
8875 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8876 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00008877#endif
8878}
8879
8880/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008881 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008882 * @ctxt: the XPath Parser context
8883 *
8884 * [3] RelativeLocationPath ::= Step
8885 * | RelativeLocationPath '/' Step
8886 * | AbbreviatedRelativeLocationPath
8887 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8888 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008889 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00008890 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008891static void
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008892xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00008893(xmlXPathParserContextPtr ctxt) {
8894 SKIP_BLANKS;
8895 if ((CUR == '/') && (NXT(1) == '/')) {
8896 SKIP(2);
8897 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008898 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8899 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008900 } else if (CUR == '/') {
8901 NEXT;
8902 SKIP_BLANKS;
8903 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008904 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008905 SKIP_BLANKS;
8906 while (CUR == '/') {
8907 if ((CUR == '/') && (NXT(1) == '/')) {
8908 SKIP(2);
8909 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008910 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00008911 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008912 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008913 } else if (CUR == '/') {
8914 NEXT;
8915 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008916 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008917 }
8918 SKIP_BLANKS;
8919 }
8920}
8921
8922/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008923 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00008924 * @ctxt: the XPath Parser context
8925 *
8926 * [1] LocationPath ::= RelativeLocationPath
8927 * | AbsoluteLocationPath
8928 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8929 * | AbbreviatedAbsoluteLocationPath
8930 * [10] AbbreviatedAbsoluteLocationPath ::=
8931 * '//' RelativeLocationPath
8932 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008933 * Compile a location path
8934 *
Owen Taylor3473f882001-02-23 17:55:21 +00008935 * // is short for /descendant-or-self::node()/. For example,
8936 * //para is short for /descendant-or-self::node()/child::para and
8937 * so will select any para element in the document (even a para element
8938 * that is a document element will be selected by //para since the
8939 * document element node is a child of the root node); div//para is
8940 * short for div/descendant-or-self::node()/child::para and so will
8941 * select all para descendants of div children.
8942 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008943static void
8944xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00008945 SKIP_BLANKS;
8946 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008947 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008948 } else {
8949 while (CUR == '/') {
8950 if ((CUR == '/') && (NXT(1) == '/')) {
8951 SKIP(2);
8952 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008953 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8954 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008955 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008956 } else if (CUR == '/') {
8957 NEXT;
Daniel Veillard608ad072001-06-14 08:32:28 +00008958 SKIP_BLANKS;
8959 if ((CUR != 0 ) &&
William M. Brack76e95df2003-10-18 16:20:14 +00008960 ((IS_LETTER_CH(CUR)) || (CUR == '_') || (CUR == '.') ||
Daniel Veillard608ad072001-06-14 08:32:28 +00008961 (CUR == '@') || (CUR == '*')))
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008962 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008963 }
8964 }
8965 }
8966}
8967
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008968/************************************************************************
8969 * *
8970 * XPath precompiled expression evaluation *
8971 * *
8972 ************************************************************************/
8973
Daniel Veillardf06307e2001-07-03 10:35:50 +00008974static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008975xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8976
8977/**
8978 * xmlXPathNodeCollectAndTest:
8979 * @ctxt: the XPath Parser context
8980 * @op: the XPath precompiled step operation
Daniel Veillardf06307e2001-07-03 10:35:50 +00008981 * @first: pointer to the first element in document order
8982 * @last: pointer to the last element in document order
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008983 *
8984 * This is the function implementing a step: based on the current list
8985 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00008986 * axis and selecting them. It also does the predicate filtering
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008987 *
8988 * Pushes the new NodeSet resulting from the search.
Daniel Veillardf06307e2001-07-03 10:35:50 +00008989 *
William M. Brack08171912003-12-29 02:52:11 +00008990 * Returns the number of nodes traversed
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008991 */
Daniel Veillardf06307e2001-07-03 10:35:50 +00008992static int
Daniel Veillardd8df6c02001-04-05 16:54:14 +00008993xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
Daniel Veillardf06307e2001-07-03 10:35:50 +00008994 xmlXPathStepOpPtr op,
8995 xmlNodePtr * first, xmlNodePtr * last)
8996{
William M. Brack78637da2003-07-31 14:47:38 +00008997 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8998 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8999 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009000 const xmlChar *prefix = op->value4;
9001 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009002 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009003
9004#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009005 int n = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009006#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009007 int i, t = 0;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009008 xmlNodeSetPtr ret, list;
9009 xmlXPathTraversalFunction next = NULL;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009010 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard75be0132002-03-13 10:03:35 +00009011 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009012 xmlNodePtr cur = NULL;
9013 xmlXPathObjectPtr obj;
9014 xmlNodeSetPtr nodelist;
9015 xmlNodePtr tmp;
9016
Daniel Veillardf06307e2001-07-03 10:35:50 +00009017 CHECK_TYPE0(XPATH_NODESET);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009018 obj = valuePop(ctxt);
9019 addNode = xmlXPathNodeSetAdd;
Daniel Veillard75be0132002-03-13 10:03:35 +00009020 mergeNodeSet = xmlXPathNodeSetMerge;
Daniel Veillarde043ee12001-04-16 14:08:07 +00009021 if (prefix != NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009022 URI = xmlXPathNsLookup(ctxt->context, prefix);
9023 if (URI == NULL)
9024 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
Daniel Veillarde043ee12001-04-16 14:08:07 +00009025 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009026#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009027 xmlGenericError(xmlGenericErrorContext, "new step : ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009028#endif
9029 switch (axis) {
9030 case AXIS_ANCESTOR:
9031#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009032 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009033#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009034 first = NULL;
9035 next = xmlXPathNextAncestor;
9036 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009037 case AXIS_ANCESTOR_OR_SELF:
9038#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009039 xmlGenericError(xmlGenericErrorContext,
9040 "axis 'ancestors-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009041#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009042 first = NULL;
9043 next = xmlXPathNextAncestorOrSelf;
9044 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009045 case AXIS_ATTRIBUTE:
9046#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009047 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009048#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009049 first = NULL;
9050 last = NULL;
9051 next = xmlXPathNextAttribute;
Daniel Veillard75be0132002-03-13 10:03:35 +00009052 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009053 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009054 case AXIS_CHILD:
9055#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009056 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009057#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009058 last = NULL;
9059 next = xmlXPathNextChild;
Daniel Veillard75be0132002-03-13 10:03:35 +00009060 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009061 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009062 case AXIS_DESCENDANT:
9063#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009064 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009065#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009066 last = NULL;
9067 next = xmlXPathNextDescendant;
9068 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009069 case AXIS_DESCENDANT_OR_SELF:
9070#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009071 xmlGenericError(xmlGenericErrorContext,
9072 "axis 'descendant-or-self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009073#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009074 last = NULL;
9075 next = xmlXPathNextDescendantOrSelf;
9076 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009077 case AXIS_FOLLOWING:
9078#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009079 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009080#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009081 last = NULL;
9082 next = xmlXPathNextFollowing;
9083 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009084 case AXIS_FOLLOWING_SIBLING:
9085#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009086 xmlGenericError(xmlGenericErrorContext,
9087 "axis 'following-siblings' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009088#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009089 last = NULL;
9090 next = xmlXPathNextFollowingSibling;
9091 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009092 case AXIS_NAMESPACE:
9093#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009094 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009095#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009096 first = NULL;
9097 last = NULL;
9098 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
Daniel Veillard75be0132002-03-13 10:03:35 +00009099 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009100 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009101 case AXIS_PARENT:
9102#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009103 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009104#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009105 first = NULL;
9106 next = xmlXPathNextParent;
9107 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009108 case AXIS_PRECEDING:
9109#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009110 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009111#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009112 first = NULL;
9113 next = xmlXPathNextPrecedingInternal;
9114 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009115 case AXIS_PRECEDING_SIBLING:
9116#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009117 xmlGenericError(xmlGenericErrorContext,
9118 "axis 'preceding-sibling' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009119#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009120 first = NULL;
9121 next = xmlXPathNextPrecedingSibling;
9122 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009123 case AXIS_SELF:
9124#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009125 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009126#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009127 first = NULL;
9128 last = NULL;
9129 next = xmlXPathNextSelf;
Daniel Veillard75be0132002-03-13 10:03:35 +00009130 mergeNodeSet = xmlXPathNodeSetMergeUnique;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009131 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009132 }
9133 if (next == NULL)
Daniel Veillardf06307e2001-07-03 10:35:50 +00009134 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009135
9136 nodelist = obj->nodesetval;
9137 if (nodelist == NULL) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009138 xmlXPathFreeObject(obj);
9139 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9140 return(0);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009141 }
9142 addNode = xmlXPathNodeSetAddUnique;
9143 ret = NULL;
9144#ifdef DEBUG_STEP
9145 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009146 " context contains %d nodes\n", nodelist->nodeNr);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009147 switch (test) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009148 case NODE_TEST_NONE:
9149 xmlGenericError(xmlGenericErrorContext,
9150 " searching for none !!!\n");
9151 break;
9152 case NODE_TEST_TYPE:
9153 xmlGenericError(xmlGenericErrorContext,
9154 " searching for type %d\n", type);
9155 break;
9156 case NODE_TEST_PI:
9157 xmlGenericError(xmlGenericErrorContext,
9158 " searching for PI !!!\n");
9159 break;
9160 case NODE_TEST_ALL:
9161 xmlGenericError(xmlGenericErrorContext,
9162 " searching for *\n");
9163 break;
9164 case NODE_TEST_NS:
9165 xmlGenericError(xmlGenericErrorContext,
9166 " searching for namespace %s\n",
9167 prefix);
9168 break;
9169 case NODE_TEST_NAME:
9170 xmlGenericError(xmlGenericErrorContext,
9171 " searching for name %s\n", name);
9172 if (prefix != NULL)
9173 xmlGenericError(xmlGenericErrorContext,
9174 " with namespace %s\n", prefix);
9175 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009176 }
9177 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9178#endif
9179 /*
9180 * 2.3 Node Tests
9181 * - For the attribute axis, the principal node type is attribute.
9182 * - For the namespace axis, the principal node type is namespace.
9183 * - For other axes, the principal node type is element.
9184 *
9185 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009186 * principal node type. For example, child::* will
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009187 * select all element children of the context node
9188 */
9189 tmp = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009190 for (i = 0; i < nodelist->nodeNr; i++) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009191 ctxt->context->node = nodelist->nodeTab[i];
9192
Daniel Veillardf06307e2001-07-03 10:35:50 +00009193 cur = NULL;
9194 list = xmlXPathNodeSetCreate(NULL);
9195 do {
9196 cur = next(ctxt, cur);
9197 if (cur == NULL)
9198 break;
9199 if ((first != NULL) && (*first == cur))
9200 break;
9201 if (((t % 256) == 0) &&
9202 (first != NULL) && (*first != NULL) &&
9203 (xmlXPathCmpNodes(*first, cur) >= 0))
9204 break;
9205 if ((last != NULL) && (*last == cur))
9206 break;
9207 if (((t % 256) == 0) &&
9208 (last != NULL) && (*last != NULL) &&
9209 (xmlXPathCmpNodes(cur, *last) >= 0))
9210 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009211 t++;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009212#ifdef DEBUG_STEP
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009213 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9214#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009215 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009216 case NODE_TEST_NONE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009217 ctxt->context->node = tmp;
9218 STRANGE return(t);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009219 case NODE_TEST_TYPE:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009220 if ((cur->type == type) ||
9221 ((type == NODE_TYPE_NODE) &&
9222 ((cur->type == XML_DOCUMENT_NODE) ||
9223 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9224 (cur->type == XML_ELEMENT_NODE) ||
Aleksey Saninf8cb6dd2002-06-04 04:27:06 +00009225 (cur->type == XML_NAMESPACE_DECL) ||
9226 (cur->type == XML_ATTRIBUTE_NODE) ||
Daniel Veillardf06307e2001-07-03 10:35:50 +00009227 (cur->type == XML_PI_NODE) ||
9228 (cur->type == XML_COMMENT_NODE) ||
9229 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard7583a592001-07-08 13:15:55 +00009230 (cur->type == XML_TEXT_NODE))) ||
9231 ((type == NODE_TYPE_TEXT) &&
9232 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009233#ifdef DEBUG_STEP
9234 n++;
9235#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009236 addNode(list, cur);
9237 }
9238 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009239 case NODE_TEST_PI:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009240 if (cur->type == XML_PI_NODE) {
9241 if ((name != NULL) &&
9242 (!xmlStrEqual(name, cur->name)))
9243 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009244#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009245 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009246#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009247 addNode(list, cur);
9248 }
9249 break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009250 case NODE_TEST_ALL:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009251 if (axis == AXIS_ATTRIBUTE) {
9252 if (cur->type == XML_ATTRIBUTE_NODE) {
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 } else if (axis == AXIS_NAMESPACE) {
9259 if (cur->type == XML_NAMESPACE_DECL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009260#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009261 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009262#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009263 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9264 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009265 }
9266 } else {
9267 if (cur->type == XML_ELEMENT_NODE) {
9268 if (prefix == NULL) {
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 Veillardf06307e2001-07-03 10:35:50 +00009272 addNode(list, cur);
9273 } else if ((cur->ns != NULL) &&
9274 (xmlStrEqual(URI, cur->ns->href))) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009275#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009276 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009277#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009278 addNode(list, cur);
9279 }
9280 }
9281 }
9282 break;
9283 case NODE_TEST_NS:{
9284 TODO;
9285 break;
9286 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009287 case NODE_TEST_NAME:
Daniel Veillardf06307e2001-07-03 10:35:50 +00009288 switch (cur->type) {
9289 case XML_ELEMENT_NODE:
9290 if (xmlStrEqual(name, cur->name)) {
9291 if (prefix == NULL) {
9292 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009293#ifdef DEBUG_STEP
Daniel Veillardf06307e2001-07-03 10:35:50 +00009294 n++;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009295#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009296 addNode(list, cur);
9297 }
9298 } else {
9299 if ((cur->ns != NULL) &&
9300 (xmlStrEqual(URI,
9301 cur->ns->href))) {
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 }
9308 }
9309 break;
9310 case XML_ATTRIBUTE_NODE:{
9311 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009312
Daniel Veillardf06307e2001-07-03 10:35:50 +00009313 if (xmlStrEqual(name, attr->name)) {
9314 if (prefix == NULL) {
9315 if ((attr->ns == NULL) ||
9316 (attr->ns->prefix == NULL)) {
9317#ifdef DEBUG_STEP
9318 n++;
9319#endif
9320 addNode(list,
9321 (xmlNodePtr) attr);
9322 }
9323 } else {
9324 if ((attr->ns != NULL) &&
9325 (xmlStrEqual(URI,
9326 attr->ns->
9327 href))) {
9328#ifdef DEBUG_STEP
9329 n++;
9330#endif
9331 addNode(list,
9332 (xmlNodePtr) attr);
9333 }
9334 }
9335 }
9336 break;
9337 }
9338 case XML_NAMESPACE_DECL:
9339 if (cur->type == XML_NAMESPACE_DECL) {
9340 xmlNsPtr ns = (xmlNsPtr) cur;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009341
Daniel Veillardf06307e2001-07-03 10:35:50 +00009342 if ((ns->prefix != NULL) && (name != NULL)
9343 && (xmlStrEqual(ns->prefix, name))) {
9344#ifdef DEBUG_STEP
9345 n++;
9346#endif
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009347 xmlXPathNodeSetAddNs(list,
9348 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009349 }
9350 }
9351 break;
9352 default:
9353 break;
9354 }
9355 break;
9356 break;
9357 }
9358 } while (cur != NULL);
9359
9360 /*
9361 * If there is some predicate filtering do it now
9362 */
Daniel Veillard6fbcf422002-03-21 12:32:59 +00009363 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009364 xmlXPathObjectPtr obj2;
9365
9366 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9367 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9368 CHECK_TYPE0(XPATH_NODESET);
9369 obj2 = valuePop(ctxt);
9370 list = obj2->nodesetval;
9371 obj2->nodesetval = NULL;
9372 xmlXPathFreeObject(obj2);
9373 }
9374 if (ret == NULL) {
9375 ret = list;
9376 } else {
Daniel Veillard75be0132002-03-13 10:03:35 +00009377 ret = mergeNodeSet(ret, list);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009378 xmlXPathFreeNodeSet(list);
9379 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009380 }
9381 ctxt->context->node = tmp;
9382#ifdef DEBUG_STEP
9383 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +00009384 "\nExamined %d nodes, found %d nodes at that step\n",
9385 t, n);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009386#endif
Daniel Veillardd8df6c02001-04-05 16:54:14 +00009387 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009388 if ((obj->boolval) && (obj->user != NULL)) {
9389 ctxt->value->boolval = 1;
9390 ctxt->value->user = obj->user;
9391 obj->user = NULL;
9392 obj->boolval = 0;
9393 }
9394 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009395 return(t);
9396}
9397
9398/**
9399 * xmlXPathNodeCollectAndTestNth:
9400 * @ctxt: the XPath Parser context
9401 * @op: the XPath precompiled step operation
9402 * @indx: the index to collect
9403 * @first: pointer to the first element in document order
9404 * @last: pointer to the last element in document order
9405 *
9406 * This is the function implementing a step: based on the current list
9407 * of nodes, it builds up a new list, looking at all nodes under that
William M. Brack08171912003-12-29 02:52:11 +00009408 * axis and selecting them. It also does the predicate filtering
Daniel Veillardf06307e2001-07-03 10:35:50 +00009409 *
9410 * Pushes the new NodeSet resulting from the search.
9411 * Returns the number of node traversed
9412 */
9413static int
9414xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9415 xmlXPathStepOpPtr op, int indx,
9416 xmlNodePtr * first, xmlNodePtr * last)
9417{
William M. Brack78637da2003-07-31 14:47:38 +00009418 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9419 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9420 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009421 const xmlChar *prefix = op->value4;
9422 const xmlChar *name = op->value5;
9423 const xmlChar *URI = NULL;
9424 int n = 0, t = 0;
9425
9426 int i;
9427 xmlNodeSetPtr list;
9428 xmlXPathTraversalFunction next = NULL;
9429 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9430 xmlNodePtr cur = NULL;
9431 xmlXPathObjectPtr obj;
9432 xmlNodeSetPtr nodelist;
9433 xmlNodePtr tmp;
9434
9435 CHECK_TYPE0(XPATH_NODESET);
9436 obj = valuePop(ctxt);
9437 addNode = xmlXPathNodeSetAdd;
9438 if (prefix != NULL) {
9439 URI = xmlXPathNsLookup(ctxt->context, prefix);
9440 if (URI == NULL)
9441 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9442 }
9443#ifdef DEBUG_STEP_NTH
9444 xmlGenericError(xmlGenericErrorContext, "new step : ");
9445 if (first != NULL) {
9446 if (*first != NULL)
9447 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9448 (*first)->name);
9449 else
9450 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9451 }
9452 if (last != NULL) {
9453 if (*last != NULL)
9454 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9455 (*last)->name);
9456 else
9457 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9458 }
9459#endif
9460 switch (axis) {
9461 case AXIS_ANCESTOR:
9462#ifdef DEBUG_STEP_NTH
9463 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9464#endif
9465 first = NULL;
9466 next = xmlXPathNextAncestor;
9467 break;
9468 case AXIS_ANCESTOR_OR_SELF:
9469#ifdef DEBUG_STEP_NTH
9470 xmlGenericError(xmlGenericErrorContext,
9471 "axis 'ancestors-or-self' ");
9472#endif
9473 first = NULL;
9474 next = xmlXPathNextAncestorOrSelf;
9475 break;
9476 case AXIS_ATTRIBUTE:
9477#ifdef DEBUG_STEP_NTH
9478 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9479#endif
9480 first = NULL;
9481 last = NULL;
9482 next = xmlXPathNextAttribute;
9483 break;
9484 case AXIS_CHILD:
9485#ifdef DEBUG_STEP_NTH
9486 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9487#endif
9488 last = NULL;
9489 next = xmlXPathNextChild;
9490 break;
9491 case AXIS_DESCENDANT:
9492#ifdef DEBUG_STEP_NTH
9493 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9494#endif
9495 last = NULL;
9496 next = xmlXPathNextDescendant;
9497 break;
9498 case AXIS_DESCENDANT_OR_SELF:
9499#ifdef DEBUG_STEP_NTH
9500 xmlGenericError(xmlGenericErrorContext,
9501 "axis 'descendant-or-self' ");
9502#endif
9503 last = NULL;
9504 next = xmlXPathNextDescendantOrSelf;
9505 break;
9506 case AXIS_FOLLOWING:
9507#ifdef DEBUG_STEP_NTH
9508 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9509#endif
9510 last = NULL;
9511 next = xmlXPathNextFollowing;
9512 break;
9513 case AXIS_FOLLOWING_SIBLING:
9514#ifdef DEBUG_STEP_NTH
9515 xmlGenericError(xmlGenericErrorContext,
9516 "axis 'following-siblings' ");
9517#endif
9518 last = NULL;
9519 next = xmlXPathNextFollowingSibling;
9520 break;
9521 case AXIS_NAMESPACE:
9522#ifdef DEBUG_STEP_NTH
9523 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9524#endif
9525 last = NULL;
9526 first = NULL;
9527 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9528 break;
9529 case AXIS_PARENT:
9530#ifdef DEBUG_STEP_NTH
9531 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9532#endif
9533 first = NULL;
9534 next = xmlXPathNextParent;
9535 break;
9536 case AXIS_PRECEDING:
9537#ifdef DEBUG_STEP_NTH
9538 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9539#endif
9540 first = NULL;
9541 next = xmlXPathNextPrecedingInternal;
9542 break;
9543 case AXIS_PRECEDING_SIBLING:
9544#ifdef DEBUG_STEP_NTH
9545 xmlGenericError(xmlGenericErrorContext,
9546 "axis 'preceding-sibling' ");
9547#endif
9548 first = NULL;
9549 next = xmlXPathNextPrecedingSibling;
9550 break;
9551 case AXIS_SELF:
9552#ifdef DEBUG_STEP_NTH
9553 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9554#endif
9555 first = NULL;
9556 last = NULL;
9557 next = xmlXPathNextSelf;
9558 break;
9559 }
9560 if (next == NULL)
9561 return(0);
9562
9563 nodelist = obj->nodesetval;
9564 if (nodelist == NULL) {
9565 xmlXPathFreeObject(obj);
9566 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9567 return(0);
9568 }
9569 addNode = xmlXPathNodeSetAddUnique;
9570#ifdef DEBUG_STEP_NTH
9571 xmlGenericError(xmlGenericErrorContext,
9572 " context contains %d nodes\n", nodelist->nodeNr);
9573 switch (test) {
9574 case NODE_TEST_NONE:
9575 xmlGenericError(xmlGenericErrorContext,
9576 " searching for none !!!\n");
9577 break;
9578 case NODE_TEST_TYPE:
9579 xmlGenericError(xmlGenericErrorContext,
9580 " searching for type %d\n", type);
9581 break;
9582 case NODE_TEST_PI:
9583 xmlGenericError(xmlGenericErrorContext,
9584 " searching for PI !!!\n");
9585 break;
9586 case NODE_TEST_ALL:
9587 xmlGenericError(xmlGenericErrorContext,
9588 " searching for *\n");
9589 break;
9590 case NODE_TEST_NS:
9591 xmlGenericError(xmlGenericErrorContext,
9592 " searching for namespace %s\n",
9593 prefix);
9594 break;
9595 case NODE_TEST_NAME:
9596 xmlGenericError(xmlGenericErrorContext,
9597 " searching for name %s\n", name);
9598 if (prefix != NULL)
9599 xmlGenericError(xmlGenericErrorContext,
9600 " with namespace %s\n", prefix);
9601 break;
9602 }
9603 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9604#endif
9605 /*
9606 * 2.3 Node Tests
9607 * - For the attribute axis, the principal node type is attribute.
9608 * - For the namespace axis, the principal node type is namespace.
9609 * - For other axes, the principal node type is element.
9610 *
9611 * A node test * is true for any node of the
Daniel Veillardcbaf3992001-12-31 16:16:02 +00009612 * principal node type. For example, child::* will
Daniel Veillardf06307e2001-07-03 10:35:50 +00009613 * select all element children of the context node
9614 */
9615 tmp = ctxt->context->node;
9616 list = xmlXPathNodeSetCreate(NULL);
9617 for (i = 0; i < nodelist->nodeNr; i++) {
9618 ctxt->context->node = nodelist->nodeTab[i];
9619
9620 cur = NULL;
9621 n = 0;
9622 do {
9623 cur = next(ctxt, cur);
9624 if (cur == NULL)
9625 break;
9626 if ((first != NULL) && (*first == cur))
9627 break;
9628 if (((t % 256) == 0) &&
9629 (first != NULL) && (*first != NULL) &&
9630 (xmlXPathCmpNodes(*first, cur) >= 0))
9631 break;
9632 if ((last != NULL) && (*last == cur))
9633 break;
9634 if (((t % 256) == 0) &&
9635 (last != NULL) && (*last != NULL) &&
9636 (xmlXPathCmpNodes(cur, *last) >= 0))
9637 break;
9638 t++;
9639 switch (test) {
9640 case NODE_TEST_NONE:
9641 ctxt->context->node = tmp;
9642 STRANGE return(0);
9643 case NODE_TEST_TYPE:
9644 if ((cur->type == type) ||
9645 ((type == NODE_TYPE_NODE) &&
9646 ((cur->type == XML_DOCUMENT_NODE) ||
9647 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9648 (cur->type == XML_ELEMENT_NODE) ||
9649 (cur->type == XML_PI_NODE) ||
9650 (cur->type == XML_COMMENT_NODE) ||
9651 (cur->type == XML_CDATA_SECTION_NODE) ||
Daniel Veillard8606bbb2002-11-12 12:36:52 +00009652 (cur->type == XML_TEXT_NODE))) ||
9653 ((type == NODE_TYPE_TEXT) &&
9654 (cur->type == XML_CDATA_SECTION_NODE))) {
Daniel Veillardf06307e2001-07-03 10:35:50 +00009655 n++;
9656 if (n == indx)
9657 addNode(list, cur);
9658 }
9659 break;
9660 case NODE_TEST_PI:
9661 if (cur->type == XML_PI_NODE) {
9662 if ((name != NULL) &&
9663 (!xmlStrEqual(name, cur->name)))
9664 break;
9665 n++;
9666 if (n == indx)
9667 addNode(list, cur);
9668 }
9669 break;
9670 case NODE_TEST_ALL:
9671 if (axis == AXIS_ATTRIBUTE) {
9672 if (cur->type == XML_ATTRIBUTE_NODE) {
9673 n++;
9674 if (n == indx)
9675 addNode(list, cur);
9676 }
9677 } else if (axis == AXIS_NAMESPACE) {
9678 if (cur->type == XML_NAMESPACE_DECL) {
9679 n++;
9680 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009681 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9682 (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009683 }
9684 } else {
9685 if (cur->type == XML_ELEMENT_NODE) {
9686 if (prefix == NULL) {
9687 n++;
9688 if (n == indx)
9689 addNode(list, cur);
9690 } else if ((cur->ns != NULL) &&
9691 (xmlStrEqual(URI, cur->ns->href))) {
9692 n++;
9693 if (n == indx)
9694 addNode(list, cur);
9695 }
9696 }
9697 }
9698 break;
9699 case NODE_TEST_NS:{
9700 TODO;
9701 break;
9702 }
9703 case NODE_TEST_NAME:
9704 switch (cur->type) {
9705 case XML_ELEMENT_NODE:
9706 if (xmlStrEqual(name, cur->name)) {
9707 if (prefix == NULL) {
9708 if (cur->ns == NULL) {
9709 n++;
9710 if (n == indx)
9711 addNode(list, cur);
9712 }
9713 } else {
9714 if ((cur->ns != NULL) &&
9715 (xmlStrEqual(URI,
9716 cur->ns->href))) {
9717 n++;
9718 if (n == indx)
9719 addNode(list, cur);
9720 }
9721 }
9722 }
9723 break;
9724 case XML_ATTRIBUTE_NODE:{
9725 xmlAttrPtr attr = (xmlAttrPtr) cur;
9726
9727 if (xmlStrEqual(name, attr->name)) {
9728 if (prefix == NULL) {
9729 if ((attr->ns == NULL) ||
9730 (attr->ns->prefix == NULL)) {
9731 n++;
9732 if (n == indx)
9733 addNode(list, cur);
9734 }
9735 } else {
9736 if ((attr->ns != NULL) &&
9737 (xmlStrEqual(URI,
9738 attr->ns->
9739 href))) {
9740 n++;
9741 if (n == indx)
9742 addNode(list, cur);
9743 }
9744 }
9745 }
9746 break;
9747 }
9748 case XML_NAMESPACE_DECL:
9749 if (cur->type == XML_NAMESPACE_DECL) {
9750 xmlNsPtr ns = (xmlNsPtr) cur;
9751
9752 if ((ns->prefix != NULL) && (name != NULL)
9753 && (xmlStrEqual(ns->prefix, name))) {
9754 n++;
9755 if (n == indx)
Daniel Veillard044fc6b2002-03-04 17:09:44 +00009756 xmlXPathNodeSetAddNs(list,
9757 ctxt->context->node, (xmlNsPtr) cur);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009758 }
9759 }
9760 break;
9761 default:
9762 break;
9763 }
9764 break;
9765 break;
9766 }
9767 } while (n < indx);
9768 }
9769 ctxt->context->node = tmp;
9770#ifdef DEBUG_STEP_NTH
9771 xmlGenericError(xmlGenericErrorContext,
9772 "\nExamined %d nodes, found %d nodes at that step\n",
9773 t, list->nodeNr);
9774#endif
Daniel Veillardf06307e2001-07-03 10:35:50 +00009775 valuePush(ctxt, xmlXPathWrapNodeSet(list));
Daniel Veillard0ab5cab2001-08-14 16:43:10 +00009776 if ((obj->boolval) && (obj->user != NULL)) {
9777 ctxt->value->boolval = 1;
9778 ctxt->value->user = obj->user;
9779 obj->user = NULL;
9780 obj->boolval = 0;
9781 }
9782 xmlXPathFreeObject(obj);
Daniel Veillardf06307e2001-07-03 10:35:50 +00009783 return(t);
9784}
9785
9786/**
9787 * xmlXPathCompOpEvalFirst:
9788 * @ctxt: the XPath parser context with the compiled expression
9789 * @op: an XPath compiled operation
9790 * @first: the first elem found so far
9791 *
9792 * Evaluate the Precompiled XPath operation searching only the first
9793 * element in document order
9794 *
9795 * Returns the number of examined objects.
9796 */
9797static int
9798xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9799 xmlXPathStepOpPtr op, xmlNodePtr * first)
9800{
9801 int total = 0, cur;
9802 xmlXPathCompExprPtr comp;
9803 xmlXPathObjectPtr arg1, arg2;
9804
Daniel Veillard556c6682001-10-06 09:59:51 +00009805 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009806 comp = ctxt->comp;
9807 switch (op->op) {
9808 case XPATH_OP_END:
9809 return (0);
9810 case XPATH_OP_UNION:
9811 total =
9812 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9813 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009814 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009815 if ((ctxt->value != NULL)
9816 && (ctxt->value->type == XPATH_NODESET)
9817 && (ctxt->value->nodesetval != NULL)
9818 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9819 /*
9820 * limit tree traversing to first node in the result
9821 */
9822 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9823 *first = ctxt->value->nodesetval->nodeTab[0];
9824 }
9825 cur =
9826 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9827 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009828 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009829 CHECK_TYPE0(XPATH_NODESET);
9830 arg2 = valuePop(ctxt);
9831
9832 CHECK_TYPE0(XPATH_NODESET);
9833 arg1 = valuePop(ctxt);
9834
9835 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9836 arg2->nodesetval);
9837 valuePush(ctxt, arg1);
9838 xmlXPathFreeObject(arg2);
9839 /* optimizer */
9840 if (total > cur)
9841 xmlXPathCompSwap(op);
9842 return (total + cur);
9843 case XPATH_OP_ROOT:
9844 xmlXPathRoot(ctxt);
9845 return (0);
9846 case XPATH_OP_NODE:
9847 if (op->ch1 != -1)
9848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009849 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009850 if (op->ch2 != -1)
9851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009852 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009853 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9854 return (total);
9855 case XPATH_OP_RESET:
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 ctxt->context->node = NULL;
9863 return (total);
9864 case XPATH_OP_COLLECT:{
9865 if (op->ch1 == -1)
9866 return (total);
9867
9868 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009869 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009870
9871 /*
9872 * Optimization for [n] selection where n is a number
9873 */
9874 if ((op->ch2 != -1) &&
9875 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9876 (comp->steps[op->ch2].ch1 == -1) &&
9877 (comp->steps[op->ch2].ch2 != -1) &&
9878 (comp->steps[comp->steps[op->ch2].ch2].op ==
9879 XPATH_OP_VALUE)) {
9880 xmlXPathObjectPtr val;
9881
9882 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9883 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9884 int indx = (int) val->floatval;
9885
9886 if (val->floatval == (float) indx) {
9887 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9888 first, NULL);
9889 return (total);
9890 }
9891 }
9892 }
9893 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9894 return (total);
9895 }
9896 case XPATH_OP_VALUE:
9897 valuePush(ctxt,
9898 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9899 return (0);
9900 case XPATH_OP_SORT:
9901 if (op->ch1 != -1)
9902 total +=
9903 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9904 first);
Daniel Veillard556c6682001-10-06 09:59:51 +00009905 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009906 if ((ctxt->value != NULL)
9907 && (ctxt->value->type == XPATH_NODESET)
9908 && (ctxt->value->nodesetval != NULL))
9909 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9910 return (total);
9911 default:
9912 return (xmlXPathCompOpEval(ctxt, op));
9913 }
9914}
9915
9916/**
9917 * xmlXPathCompOpEvalLast:
9918 * @ctxt: the XPath parser context with the compiled expression
9919 * @op: an XPath compiled operation
9920 * @last: the last elem found so far
9921 *
9922 * Evaluate the Precompiled XPath operation searching only the last
9923 * element in document order
9924 *
William M. Brack08171912003-12-29 02:52:11 +00009925 * Returns the number of nodes traversed
Daniel Veillardf06307e2001-07-03 10:35:50 +00009926 */
9927static int
9928xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9929 xmlNodePtr * last)
9930{
9931 int total = 0, cur;
9932 xmlXPathCompExprPtr comp;
9933 xmlXPathObjectPtr arg1, arg2;
William M. Brackce4fc562004-01-22 02:47:18 +00009934 xmlNodePtr bak;
9935 xmlDocPtr bakd;
9936 int pp;
9937 int cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009938
Daniel Veillard556c6682001-10-06 09:59:51 +00009939 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009940 comp = ctxt->comp;
9941 switch (op->op) {
9942 case XPATH_OP_END:
9943 return (0);
9944 case XPATH_OP_UNION:
William M. Brackce4fc562004-01-22 02:47:18 +00009945 bakd = ctxt->context->doc;
9946 bak = ctxt->context->node;
9947 pp = ctxt->context->proximityPosition;
9948 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009949 total =
9950 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009951 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009952 if ((ctxt->value != NULL)
9953 && (ctxt->value->type == XPATH_NODESET)
9954 && (ctxt->value->nodesetval != NULL)
9955 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9956 /*
9957 * limit tree traversing to first node in the result
9958 */
9959 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9960 *last =
9961 ctxt->value->nodesetval->nodeTab[ctxt->value->
9962 nodesetval->nodeNr -
9963 1];
9964 }
William M. Brackce4fc562004-01-22 02:47:18 +00009965 ctxt->context->doc = bakd;
9966 ctxt->context->node = bak;
9967 ctxt->context->proximityPosition = pp;
9968 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009969 cur =
9970 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
Daniel Veillard556c6682001-10-06 09:59:51 +00009971 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009972 if ((ctxt->value != NULL)
9973 && (ctxt->value->type == XPATH_NODESET)
9974 && (ctxt->value->nodesetval != NULL)
9975 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9976 }
9977 CHECK_TYPE0(XPATH_NODESET);
9978 arg2 = valuePop(ctxt);
9979
9980 CHECK_TYPE0(XPATH_NODESET);
9981 arg1 = valuePop(ctxt);
9982
9983 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9984 arg2->nodesetval);
9985 valuePush(ctxt, arg1);
9986 xmlXPathFreeObject(arg2);
9987 /* optimizer */
9988 if (total > cur)
9989 xmlXPathCompSwap(op);
9990 return (total + cur);
9991 case XPATH_OP_ROOT:
9992 xmlXPathRoot(ctxt);
9993 return (0);
9994 case XPATH_OP_NODE:
9995 if (op->ch1 != -1)
9996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +00009997 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +00009998 if (op->ch2 != -1)
9999 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010000 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010001 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10002 return (total);
10003 case XPATH_OP_RESET:
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 ctxt->context->node = NULL;
10011 return (total);
10012 case XPATH_OP_COLLECT:{
10013 if (op->ch1 == -1)
10014 return (0);
10015
10016 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010017 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010018
10019 /*
10020 * Optimization for [n] selection where n is a number
10021 */
10022 if ((op->ch2 != -1) &&
10023 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10024 (comp->steps[op->ch2].ch1 == -1) &&
10025 (comp->steps[op->ch2].ch2 != -1) &&
10026 (comp->steps[comp->steps[op->ch2].ch2].op ==
10027 XPATH_OP_VALUE)) {
10028 xmlXPathObjectPtr val;
10029
10030 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10031 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10032 int indx = (int) val->floatval;
10033
10034 if (val->floatval == (float) indx) {
10035 total +=
10036 xmlXPathNodeCollectAndTestNth(ctxt, op,
10037 indx, NULL,
10038 last);
10039 return (total);
10040 }
10041 }
10042 }
10043 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
10044 return (total);
10045 }
10046 case XPATH_OP_VALUE:
10047 valuePush(ctxt,
10048 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10049 return (0);
10050 case XPATH_OP_SORT:
10051 if (op->ch1 != -1)
10052 total +=
10053 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10054 last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010055 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010056 if ((ctxt->value != NULL)
10057 && (ctxt->value->type == XPATH_NODESET)
10058 && (ctxt->value->nodesetval != NULL))
10059 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10060 return (total);
10061 default:
10062 return (xmlXPathCompOpEval(ctxt, op));
10063 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010064}
10065
Owen Taylor3473f882001-02-23 17:55:21 +000010066/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010067 * xmlXPathCompOpEval:
10068 * @ctxt: the XPath parser context with the compiled expression
10069 * @op: an XPath compiled operation
10070 *
10071 * Evaluate the Precompiled XPath operation
William M. Brack08171912003-12-29 02:52:11 +000010072 * Returns the number of nodes traversed
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010073 */
Daniel Veillardf06307e2001-07-03 10:35:50 +000010074static int
10075xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10076{
10077 int total = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010078 int equal, ret;
10079 xmlXPathCompExprPtr comp;
10080 xmlXPathObjectPtr arg1, arg2;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010081 xmlNodePtr bak;
10082 xmlDocPtr bakd;
William M. Brack6000af52002-06-28 11:43:13 +000010083 int pp;
William M. Brack692092b2002-06-28 15:01:24 +000010084 int cs;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010085
Daniel Veillard556c6682001-10-06 09:59:51 +000010086 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010087 comp = ctxt->comp;
10088 switch (op->op) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010089 case XPATH_OP_END:
10090 return (0);
10091 case XPATH_OP_AND:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010092 bakd = ctxt->context->doc;
10093 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010094 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010095 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010096 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010097 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010098 xmlXPathBooleanFunction(ctxt, 1);
10099 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10100 return (total);
10101 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010102 ctxt->context->doc = bakd;
10103 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010104 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010105 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010107 if (ctxt->error) {
10108 xmlXPathFreeObject(arg2);
10109 return(0);
10110 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010111 xmlXPathBooleanFunction(ctxt, 1);
10112 arg1 = valuePop(ctxt);
10113 arg1->boolval &= arg2->boolval;
10114 valuePush(ctxt, arg1);
10115 xmlXPathFreeObject(arg2);
10116 return (total);
10117 case XPATH_OP_OR:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010118 bakd = ctxt->context->doc;
10119 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010120 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010121 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010122 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010123 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010124 xmlXPathBooleanFunction(ctxt, 1);
10125 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10126 return (total);
10127 arg2 = valuePop(ctxt);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010128 ctxt->context->doc = bakd;
10129 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010130 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010131 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010132 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010133 if (ctxt->error) {
10134 xmlXPathFreeObject(arg2);
10135 return(0);
10136 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010137 xmlXPathBooleanFunction(ctxt, 1);
10138 arg1 = valuePop(ctxt);
10139 arg1->boolval |= arg2->boolval;
10140 valuePush(ctxt, arg1);
10141 xmlXPathFreeObject(arg2);
10142 return (total);
10143 case XPATH_OP_EQUAL:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010144 bakd = ctxt->context->doc;
10145 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010146 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010147 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010149 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010150 ctxt->context->doc = bakd;
10151 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010152 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010153 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010154 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010155 CHECK_ERROR0;
William M. Brack0c022ad2002-07-12 00:56:01 +000010156 if (op->value)
10157 equal = xmlXPathEqualValues(ctxt);
10158 else
10159 equal = xmlXPathNotEqualValues(ctxt);
10160 valuePush(ctxt, xmlXPathNewBoolean(equal));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010161 return (total);
10162 case XPATH_OP_CMP:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010163 bakd = ctxt->context->doc;
10164 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010165 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010166 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010168 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010169 ctxt->context->doc = bakd;
10170 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010171 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010172 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010174 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010175 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10176 valuePush(ctxt, xmlXPathNewBoolean(ret));
10177 return (total);
10178 case XPATH_OP_PLUS:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010179 bakd = ctxt->context->doc;
10180 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010181 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010182 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010183 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010184 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010185 if (op->ch2 != -1) {
10186 ctxt->context->doc = bakd;
10187 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010188 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010189 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010190 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010191 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010192 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010193 if (op->value == 0)
10194 xmlXPathSubValues(ctxt);
10195 else if (op->value == 1)
10196 xmlXPathAddValues(ctxt);
10197 else if (op->value == 2)
10198 xmlXPathValueFlipSign(ctxt);
10199 else if (op->value == 3) {
10200 CAST_TO_NUMBER;
10201 CHECK_TYPE0(XPATH_NUMBER);
10202 }
10203 return (total);
10204 case XPATH_OP_MULT:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010205 bakd = ctxt->context->doc;
10206 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010207 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010208 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010209 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010210 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010211 ctxt->context->doc = bakd;
10212 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010213 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010214 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010216 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010217 if (op->value == 0)
10218 xmlXPathMultValues(ctxt);
10219 else if (op->value == 1)
10220 xmlXPathDivValues(ctxt);
10221 else if (op->value == 2)
10222 xmlXPathModValues(ctxt);
10223 return (total);
10224 case XPATH_OP_UNION:
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010225 bakd = ctxt->context->doc;
10226 bak = ctxt->context->node;
William M. Brack6000af52002-06-28 11:43:13 +000010227 pp = ctxt->context->proximityPosition;
William M. Brack692092b2002-06-28 15:01:24 +000010228 cs = ctxt->context->contextSize;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010229 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010230 CHECK_ERROR0;
Daniel Veillard7089d6b2002-03-29 17:28:10 +000010231 ctxt->context->doc = bakd;
10232 ctxt->context->node = bak;
William M. Brack6000af52002-06-28 11:43:13 +000010233 ctxt->context->proximityPosition = pp;
William M. Brack692092b2002-06-28 15:01:24 +000010234 ctxt->context->contextSize = cs;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010236 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010237 CHECK_TYPE0(XPATH_NODESET);
10238 arg2 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010239
Daniel Veillardf06307e2001-07-03 10:35:50 +000010240 CHECK_TYPE0(XPATH_NODESET);
10241 arg1 = valuePop(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010242
Daniel Veillardf06307e2001-07-03 10:35:50 +000010243 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10244 arg2->nodesetval);
10245 valuePush(ctxt, arg1);
10246 xmlXPathFreeObject(arg2);
10247 return (total);
10248 case XPATH_OP_ROOT:
10249 xmlXPathRoot(ctxt);
10250 return (total);
10251 case XPATH_OP_NODE:
10252 if (op->ch1 != -1)
10253 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010254 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010255 if (op->ch2 != -1)
10256 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010257 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010258 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10259 return (total);
10260 case XPATH_OP_RESET:
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 ctxt->context->node = NULL;
10268 return (total);
10269 case XPATH_OP_COLLECT:{
10270 if (op->ch1 == -1)
10271 return (total);
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010272
Daniel Veillardf06307e2001-07-03 10:35:50 +000010273 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010274 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010275
Daniel Veillardf06307e2001-07-03 10:35:50 +000010276 /*
10277 * Optimization for [n] selection where n is a number
10278 */
10279 if ((op->ch2 != -1) &&
10280 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10281 (comp->steps[op->ch2].ch1 == -1) &&
10282 (comp->steps[op->ch2].ch2 != -1) &&
10283 (comp->steps[comp->steps[op->ch2].ch2].op ==
10284 XPATH_OP_VALUE)) {
10285 xmlXPathObjectPtr val;
Daniel Veillard42596ad2001-05-22 16:57:14 +000010286
Daniel Veillardf06307e2001-07-03 10:35:50 +000010287 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10288 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10289 int indx = (int) val->floatval;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010290
Daniel Veillardf06307e2001-07-03 10:35:50 +000010291 if (val->floatval == (float) indx) {
10292 total +=
10293 xmlXPathNodeCollectAndTestNth(ctxt, op,
10294 indx, NULL,
10295 NULL);
10296 return (total);
10297 }
10298 }
10299 }
10300 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10301 return (total);
10302 }
10303 case XPATH_OP_VALUE:
10304 valuePush(ctxt,
10305 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10306 return (total);
10307 case XPATH_OP_VARIABLE:{
Daniel Veillard556c6682001-10-06 09:59:51 +000010308 xmlXPathObjectPtr val;
10309
Daniel Veillardf06307e2001-07-03 10:35:50 +000010310 if (op->ch1 != -1)
10311 total +=
10312 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010313 if (op->value5 == NULL) {
10314 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10315 if (val == NULL) {
10316 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10317 return(0);
10318 }
10319 valuePush(ctxt, val);
10320 } else {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010321 const xmlChar *URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010322
Daniel Veillardf06307e2001-07-03 10:35:50 +000010323 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10324 if (URI == NULL) {
10325 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010326 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010327 op->value4, op->value5);
10328 return (total);
10329 }
Daniel Veillard556c6682001-10-06 09:59:51 +000010330 val = xmlXPathVariableLookupNS(ctxt->context,
10331 op->value4, URI);
10332 if (val == NULL) {
10333 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10334 return(0);
10335 }
10336 valuePush(ctxt, val);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010337 }
10338 return (total);
10339 }
10340 case XPATH_OP_FUNCTION:{
10341 xmlXPathFunction func;
10342 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard556c6682001-10-06 09:59:51 +000010343 int i;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010344
10345 if (op->ch1 != -1)
10346 total +=
10347 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010348 if (ctxt->valueNr < op->value) {
10349 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010350 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010351 ctxt->error = XPATH_INVALID_OPERAND;
10352 return (total);
10353 }
10354 for (i = 0; i < op->value; i++)
10355 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10356 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010357 "xmlXPathCompOpEval: parameter error\n");
Daniel Veillard556c6682001-10-06 09:59:51 +000010358 ctxt->error = XPATH_INVALID_OPERAND;
10359 return (total);
10360 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010361 if (op->cache != NULL)
10362 func = (xmlXPathFunction) op->cache;
10363 else {
10364 const xmlChar *URI = NULL;
10365
10366 if (op->value5 == NULL)
10367 func =
10368 xmlXPathFunctionLookup(ctxt->context,
10369 op->value4);
10370 else {
10371 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10372 if (URI == NULL) {
10373 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010374 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010375 op->value4, op->value5);
10376 return (total);
10377 }
10378 func = xmlXPathFunctionLookupNS(ctxt->context,
10379 op->value4, URI);
10380 }
10381 if (func == NULL) {
10382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010383 "xmlXPathCompOpEval: function %s not found\n",
Daniel Veillardf06307e2001-07-03 10:35:50 +000010384 op->value4);
10385 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardf06307e2001-07-03 10:35:50 +000010386 }
10387 op->cache = (void *) func;
10388 op->cacheURI = (void *) URI;
10389 }
10390 oldFunc = ctxt->context->function;
10391 oldFuncURI = ctxt->context->functionURI;
10392 ctxt->context->function = op->value4;
10393 ctxt->context->functionURI = op->cacheURI;
10394 func(ctxt, op->value);
10395 ctxt->context->function = oldFunc;
10396 ctxt->context->functionURI = oldFuncURI;
10397 return (total);
10398 }
10399 case XPATH_OP_ARG:
Daniel Veillard088bf112002-05-14 11:03:59 +000010400 bakd = ctxt->context->doc;
10401 bak = ctxt->context->node;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010402 if (op->ch1 != -1)
10403 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard088bf112002-05-14 11:03:59 +000010404 ctxt->context->doc = bakd;
10405 ctxt->context->node = bak;
Daniel Veillard556c6682001-10-06 09:59:51 +000010406 CHECK_ERROR0;
William M. Brack72ee48d2003-12-30 08:30:19 +000010407 if (op->ch2 != -1) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010408 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
William M. Brack72ee48d2003-12-30 08:30:19 +000010409 ctxt->context->doc = bakd;
10410 ctxt->context->node = bak;
10411 CHECK_ERROR0;
10412 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010413 return (total);
10414 case XPATH_OP_PREDICATE:
10415 case XPATH_OP_FILTER:{
10416 xmlXPathObjectPtr res;
10417 xmlXPathObjectPtr obj, tmp;
10418 xmlNodeSetPtr newset = NULL;
10419 xmlNodeSetPtr oldset;
10420 xmlNodePtr oldnode;
William M. Brack3794b9e2004-07-13 15:06:20 +000010421 xmlDocPtr oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010422 int i;
10423
10424 /*
10425 * Optimization for ()[1] selection i.e. the first elem
10426 */
10427 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10428 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10429 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10430 xmlXPathObjectPtr val;
10431
10432 val = comp->steps[op->ch2].value4;
10433 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10434 (val->floatval == 1.0)) {
10435 xmlNodePtr first = NULL;
10436
10437 total +=
10438 xmlXPathCompOpEvalFirst(ctxt,
10439 &comp->steps[op->ch1],
10440 &first);
Daniel Veillard556c6682001-10-06 09:59:51 +000010441 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010442 /*
10443 * The nodeset should be in document order,
10444 * Keep only the first value
10445 */
10446 if ((ctxt->value != NULL) &&
10447 (ctxt->value->type == XPATH_NODESET) &&
10448 (ctxt->value->nodesetval != NULL) &&
10449 (ctxt->value->nodesetval->nodeNr > 1))
10450 ctxt->value->nodesetval->nodeNr = 1;
10451 return (total);
10452 }
10453 }
10454 /*
10455 * Optimization for ()[last()] selection i.e. the last elem
10456 */
10457 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10458 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10459 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10460 int f = comp->steps[op->ch2].ch1;
10461
10462 if ((f != -1) &&
10463 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10464 (comp->steps[f].value5 == NULL) &&
10465 (comp->steps[f].value == 0) &&
10466 (comp->steps[f].value4 != NULL) &&
10467 (xmlStrEqual
10468 (comp->steps[f].value4, BAD_CAST "last"))) {
10469 xmlNodePtr last = NULL;
10470
10471 total +=
10472 xmlXPathCompOpEvalLast(ctxt,
10473 &comp->steps[op->ch1],
10474 &last);
Daniel Veillard556c6682001-10-06 09:59:51 +000010475 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010476 /*
10477 * The nodeset should be in document order,
10478 * Keep only the last value
10479 */
10480 if ((ctxt->value != NULL) &&
10481 (ctxt->value->type == XPATH_NODESET) &&
10482 (ctxt->value->nodesetval != NULL) &&
10483 (ctxt->value->nodesetval->nodeTab != NULL) &&
10484 (ctxt->value->nodesetval->nodeNr > 1)) {
10485 ctxt->value->nodesetval->nodeTab[0] =
10486 ctxt->value->nodesetval->nodeTab[ctxt->
10487 value->
10488 nodesetval->
10489 nodeNr -
10490 1];
10491 ctxt->value->nodesetval->nodeNr = 1;
10492 }
10493 return (total);
10494 }
10495 }
10496
10497 if (op->ch1 != -1)
10498 total +=
10499 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010500 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010501 if (op->ch2 == -1)
10502 return (total);
10503 if (ctxt->value == NULL)
10504 return (total);
10505
10506 oldnode = ctxt->context->node;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010507
10508#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010509 /*
10510 * Hum are we filtering the result of an XPointer expression
10511 */
10512 if (ctxt->value->type == XPATH_LOCATIONSET) {
10513 xmlLocationSetPtr newlocset = NULL;
10514 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010515
Daniel Veillardf06307e2001-07-03 10:35:50 +000010516 /*
10517 * Extract the old locset, and then evaluate the result of the
10518 * expression for all the element in the locset. use it to grow
10519 * up a new locset.
10520 */
10521 CHECK_TYPE0(XPATH_LOCATIONSET);
10522 obj = valuePop(ctxt);
10523 oldlocset = obj->user;
10524 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010525
Daniel Veillardf06307e2001-07-03 10:35:50 +000010526 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10527 ctxt->context->contextSize = 0;
10528 ctxt->context->proximityPosition = 0;
10529 if (op->ch2 != -1)
10530 total +=
10531 xmlXPathCompOpEval(ctxt,
10532 &comp->steps[op->ch2]);
10533 res = valuePop(ctxt);
10534 if (res != NULL)
10535 xmlXPathFreeObject(res);
10536 valuePush(ctxt, obj);
10537 CHECK_ERROR0;
10538 return (total);
10539 }
10540 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010541
Daniel Veillardf06307e2001-07-03 10:35:50 +000010542 for (i = 0; i < oldlocset->locNr; i++) {
10543 /*
10544 * Run the evaluation with a node list made of a
10545 * single item in the nodelocset.
10546 */
10547 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010548 ctxt->context->contextSize = oldlocset->locNr;
10549 ctxt->context->proximityPosition = i + 1;
William M. Brackf7eb7942003-12-31 07:59:17 +000010550 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10551 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010552
Daniel Veillardf06307e2001-07-03 10:35:50 +000010553 if (op->ch2 != -1)
10554 total +=
10555 xmlXPathCompOpEval(ctxt,
10556 &comp->steps[op->ch2]);
10557 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010558
Daniel Veillardf06307e2001-07-03 10:35:50 +000010559 /*
10560 * The result of the evaluation need to be tested to
10561 * decided whether the filter succeeded or not
10562 */
10563 res = valuePop(ctxt);
10564 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10565 xmlXPtrLocationSetAdd(newlocset,
10566 xmlXPathObjectCopy
10567 (oldlocset->locTab[i]));
10568 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010569
Daniel Veillardf06307e2001-07-03 10:35:50 +000010570 /*
10571 * Cleanup
10572 */
10573 if (res != NULL)
10574 xmlXPathFreeObject(res);
10575 if (ctxt->value == tmp) {
10576 res = valuePop(ctxt);
10577 xmlXPathFreeObject(res);
10578 }
10579
10580 ctxt->context->node = NULL;
10581 }
10582
10583 /*
10584 * The result is used as the new evaluation locset.
10585 */
10586 xmlXPathFreeObject(obj);
10587 ctxt->context->node = NULL;
10588 ctxt->context->contextSize = -1;
10589 ctxt->context->proximityPosition = -1;
10590 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10591 ctxt->context->node = oldnode;
10592 return (total);
10593 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010594#endif /* LIBXML_XPTR_ENABLED */
10595
Daniel Veillardf06307e2001-07-03 10:35:50 +000010596 /*
10597 * Extract the old set, and then evaluate the result of the
10598 * expression for all the element in the set. use it to grow
10599 * up a new set.
10600 */
10601 CHECK_TYPE0(XPATH_NODESET);
10602 obj = valuePop(ctxt);
10603 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +000010604
Daniel Veillardf06307e2001-07-03 10:35:50 +000010605 oldnode = ctxt->context->node;
William M. Brack3794b9e2004-07-13 15:06:20 +000010606 oldDoc = ctxt->context->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010607 ctxt->context->node = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010608
Daniel Veillardf06307e2001-07-03 10:35:50 +000010609 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10610 ctxt->context->contextSize = 0;
10611 ctxt->context->proximityPosition = 0;
William M. Brack8fad8bf2004-06-02 08:26:25 +000010612/*
Daniel Veillardf06307e2001-07-03 10:35:50 +000010613 if (op->ch2 != -1)
10614 total +=
10615 xmlXPathCompOpEval(ctxt,
10616 &comp->steps[op->ch2]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010617 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010618 res = valuePop(ctxt);
10619 if (res != NULL)
10620 xmlXPathFreeObject(res);
William M. Brack8fad8bf2004-06-02 08:26:25 +000010621*/
Daniel Veillardf06307e2001-07-03 10:35:50 +000010622 valuePush(ctxt, obj);
10623 ctxt->context->node = oldnode;
10624 CHECK_ERROR0;
10625 } else {
10626 /*
10627 * Initialize the new set.
William M. Brack3794b9e2004-07-13 15:06:20 +000010628 * Also set the xpath document in case things like
10629 * key() evaluation are attempted on the predicate
Daniel Veillardf06307e2001-07-03 10:35:50 +000010630 */
10631 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010632
Daniel Veillardf06307e2001-07-03 10:35:50 +000010633 for (i = 0; i < oldset->nodeNr; i++) {
10634 /*
10635 * Run the evaluation with a node list made of
10636 * a single item in the nodeset.
10637 */
10638 ctxt->context->node = oldset->nodeTab[i];
William M. Brack3794b9e2004-07-13 15:06:20 +000010639 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
10640 (oldset->nodeTab[i]->doc != NULL))
10641 ctxt->context->doc = oldset->nodeTab[i]->doc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010642 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10643 valuePush(ctxt, tmp);
10644 ctxt->context->contextSize = oldset->nodeNr;
10645 ctxt->context->proximityPosition = i + 1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010646
Daniel Veillardf06307e2001-07-03 10:35:50 +000010647 if (op->ch2 != -1)
10648 total +=
10649 xmlXPathCompOpEval(ctxt,
10650 &comp->steps[op->ch2]);
10651 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010652
Daniel Veillardf06307e2001-07-03 10:35:50 +000010653 /*
William M. Brack08171912003-12-29 02:52:11 +000010654 * The result of the evaluation needs to be tested to
10655 * decide whether the filter succeeded or not
Daniel Veillardf06307e2001-07-03 10:35:50 +000010656 */
10657 res = valuePop(ctxt);
10658 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10659 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10660 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010661
Daniel Veillardf06307e2001-07-03 10:35:50 +000010662 /*
10663 * Cleanup
10664 */
10665 if (res != NULL)
10666 xmlXPathFreeObject(res);
10667 if (ctxt->value == tmp) {
10668 res = valuePop(ctxt);
10669 xmlXPathFreeObject(res);
10670 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010671
Daniel Veillardf06307e2001-07-03 10:35:50 +000010672 ctxt->context->node = NULL;
10673 }
10674
10675 /*
10676 * The result is used as the new evaluation set.
10677 */
10678 xmlXPathFreeObject(obj);
10679 ctxt->context->node = NULL;
10680 ctxt->context->contextSize = -1;
10681 ctxt->context->proximityPosition = -1;
William M. Brack3794b9e2004-07-13 15:06:20 +000010682 /* may want to move this past the '}' later */
10683 ctxt->context->doc = oldDoc;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010684 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10685 }
10686 ctxt->context->node = oldnode;
10687 return (total);
10688 }
10689 case XPATH_OP_SORT:
10690 if (op->ch1 != -1)
10691 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillard556c6682001-10-06 09:59:51 +000010692 CHECK_ERROR0;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010693 if ((ctxt->value != NULL) &&
10694 (ctxt->value->type == XPATH_NODESET) &&
10695 (ctxt->value->nodesetval != NULL))
10696 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10697 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010698#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardf06307e2001-07-03 10:35:50 +000010699 case XPATH_OP_RANGETO:{
10700 xmlXPathObjectPtr range;
10701 xmlXPathObjectPtr res, obj;
10702 xmlXPathObjectPtr tmp;
William M. Brack08171912003-12-29 02:52:11 +000010703 xmlLocationSetPtr newlocset = NULL;
10704 xmlLocationSetPtr oldlocset;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010705 xmlNodeSetPtr oldset;
William M. Brack72ee48d2003-12-30 08:30:19 +000010706 int i, j;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010707
Daniel Veillardf06307e2001-07-03 10:35:50 +000010708 if (op->ch1 != -1)
10709 total +=
10710 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10711 if (op->ch2 == -1)
10712 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010713
William M. Brack08171912003-12-29 02:52:11 +000010714 if (ctxt->value->type == XPATH_LOCATIONSET) {
10715 /*
10716 * Extract the old locset, and then evaluate the result of the
10717 * expression for all the element in the locset. use it to grow
10718 * up a new locset.
10719 */
10720 CHECK_TYPE0(XPATH_LOCATIONSET);
10721 obj = valuePop(ctxt);
10722 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010723
William M. Brack08171912003-12-29 02:52:11 +000010724 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
William M. Brack72ee48d2003-12-30 08:30:19 +000010725 ctxt->context->node = NULL;
William M. Brack08171912003-12-29 02:52:11 +000010726 ctxt->context->contextSize = 0;
10727 ctxt->context->proximityPosition = 0;
10728 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
10729 res = valuePop(ctxt);
10730 if (res != NULL)
10731 xmlXPathFreeObject(res);
10732 valuePush(ctxt, obj);
10733 CHECK_ERROR0;
10734 return (total);
10735 }
10736 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010737
William M. Brack08171912003-12-29 02:52:11 +000010738 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillardf06307e2001-07-03 10:35:50 +000010739 /*
William M. Brack08171912003-12-29 02:52:11 +000010740 * Run the evaluation with a node list made of a
10741 * single item in the nodelocset.
Daniel Veillardf06307e2001-07-03 10:35:50 +000010742 */
William M. Brackf7eb7942003-12-31 07:59:17 +000010743 ctxt->context->node = oldlocset->locTab[i]->user;
10744 ctxt->context->contextSize = oldlocset->locNr;
10745 ctxt->context->proximityPosition = i + 1;
Daniel Veillardf06307e2001-07-03 10:35:50 +000010746 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10747 valuePush(ctxt, tmp);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010748
Daniel Veillardf06307e2001-07-03 10:35:50 +000010749 if (op->ch2 != -1)
10750 total +=
10751 xmlXPathCompOpEval(ctxt,
10752 &comp->steps[op->ch2]);
10753 CHECK_ERROR0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010754
Daniel Veillardf06307e2001-07-03 10:35:50 +000010755 res = valuePop(ctxt);
William M. Brack72ee48d2003-12-30 08:30:19 +000010756 if (res->type == XPATH_LOCATIONSET) {
10757 xmlLocationSetPtr rloc =
10758 (xmlLocationSetPtr)res->user;
10759 for (j=0; j<rloc->locNr; j++) {
10760 range = xmlXPtrNewRange(
10761 oldlocset->locTab[i]->user,
10762 oldlocset->locTab[i]->index,
10763 rloc->locTab[j]->user2,
10764 rloc->locTab[j]->index2);
10765 if (range != NULL) {
10766 xmlXPtrLocationSetAdd(newlocset, range);
10767 }
10768 }
10769 } else {
10770 range = xmlXPtrNewRangeNodeObject(
10771 (xmlNodePtr)oldlocset->locTab[i]->user, res);
10772 if (range != NULL) {
10773 xmlXPtrLocationSetAdd(newlocset,range);
10774 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010775 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010776
Daniel Veillardf06307e2001-07-03 10:35:50 +000010777 /*
10778 * Cleanup
10779 */
10780 if (res != NULL)
10781 xmlXPathFreeObject(res);
10782 if (ctxt->value == tmp) {
10783 res = valuePop(ctxt);
10784 xmlXPathFreeObject(res);
10785 }
10786
10787 ctxt->context->node = NULL;
10788 }
William M. Brack72ee48d2003-12-30 08:30:19 +000010789 } else { /* Not a location set */
William M. Brack08171912003-12-29 02:52:11 +000010790 CHECK_TYPE0(XPATH_NODESET);
10791 obj = valuePop(ctxt);
10792 oldset = obj->nodesetval;
10793 ctxt->context->node = NULL;
10794
10795 newlocset = xmlXPtrLocationSetCreate(NULL);
10796
10797 if (oldset != NULL) {
10798 for (i = 0; i < oldset->nodeNr; i++) {
10799 /*
10800 * Run the evaluation with a node list made of a single item
10801 * in the nodeset.
10802 */
10803 ctxt->context->node = oldset->nodeTab[i];
10804 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10805 valuePush(ctxt, tmp);
10806
10807 if (op->ch2 != -1)
10808 total +=
10809 xmlXPathCompOpEval(ctxt,
10810 &comp->steps[op->ch2]);
10811 CHECK_ERROR0;
10812
William M. Brack08171912003-12-29 02:52:11 +000010813 res = valuePop(ctxt);
10814 range =
10815 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10816 res);
10817 if (range != NULL) {
10818 xmlXPtrLocationSetAdd(newlocset, range);
10819 }
10820
10821 /*
10822 * Cleanup
10823 */
10824 if (res != NULL)
10825 xmlXPathFreeObject(res);
10826 if (ctxt->value == tmp) {
10827 res = valuePop(ctxt);
10828 xmlXPathFreeObject(res);
10829 }
10830
10831 ctxt->context->node = NULL;
10832 }
10833 }
Daniel Veillardf06307e2001-07-03 10:35:50 +000010834 }
10835
10836 /*
10837 * The result is used as the new evaluation set.
10838 */
10839 xmlXPathFreeObject(obj);
10840 ctxt->context->node = NULL;
10841 ctxt->context->contextSize = -1;
10842 ctxt->context->proximityPosition = -1;
William M. Brack08171912003-12-29 02:52:11 +000010843 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillardf06307e2001-07-03 10:35:50 +000010844 return (total);
10845 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010846#endif /* LIBXML_XPTR_ENABLED */
10847 }
10848 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf06307e2001-07-03 10:35:50 +000010849 "XPath: unknown precompiled operation %d\n", op->op);
10850 return (total);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010851}
10852
10853/**
10854 * xmlXPathRunEval:
10855 * @ctxt: the XPath parser context with the compiled expression
10856 *
10857 * Evaluate the Precompiled XPath expression in the given context.
10858 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010859static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010860xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10861 xmlXPathCompExprPtr comp;
10862
10863 if ((ctxt == NULL) || (ctxt->comp == NULL))
10864 return;
10865
10866 if (ctxt->valueTab == NULL) {
10867 /* Allocate the value stack */
10868 ctxt->valueTab = (xmlXPathObjectPtr *)
10869 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10870 if (ctxt->valueTab == NULL) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +000010871 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010872 xmlFree(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010873 }
10874 ctxt->valueNr = 0;
10875 ctxt->valueMax = 10;
10876 ctxt->value = NULL;
10877 }
10878 comp = ctxt->comp;
Aleksey Sanin29b6f762002-05-05 06:59:57 +000010879 if(comp->last < 0) {
10880 xmlGenericError(xmlGenericErrorContext,
10881 "xmlXPathRunEval: last is less than zero\n");
10882 return;
10883 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +000010884 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10885}
10886
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010887/************************************************************************
10888 * *
10889 * Public interfaces *
10890 * *
10891 ************************************************************************/
10892
10893/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010894 * xmlXPathEvalPredicate:
10895 * @ctxt: the XPath context
10896 * @res: the Predicate Expression evaluation result
10897 *
10898 * Evaluate a predicate result for the current node.
10899 * A PredicateExpr is evaluated by evaluating the Expr and converting
10900 * the result to a boolean. If the result is a number, the result will
10901 * be converted to true if the number is equal to the position of the
10902 * context node in the context node list (as returned by the position
10903 * function) and will be converted to false otherwise; if the result
10904 * is not a number, then the result will be converted as if by a call
10905 * to the boolean function.
10906 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010907 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010908 */
10909int
10910xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10911 if (res == NULL) return(0);
10912 switch (res->type) {
10913 case XPATH_BOOLEAN:
10914 return(res->boolval);
10915 case XPATH_NUMBER:
10916 return(res->floatval == ctxt->proximityPosition);
10917 case XPATH_NODESET:
10918 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +000010919 if (res->nodesetval == NULL)
10920 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +000010921 return(res->nodesetval->nodeNr != 0);
10922 case XPATH_STRING:
10923 return((res->stringval != NULL) &&
10924 (xmlStrlen(res->stringval) != 0));
10925 default:
10926 STRANGE
10927 }
10928 return(0);
10929}
10930
10931/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010932 * xmlXPathEvaluatePredicateResult:
10933 * @ctxt: the XPath Parser context
10934 * @res: the Predicate Expression evaluation result
10935 *
10936 * Evaluate a predicate result for the current node.
10937 * A PredicateExpr is evaluated by evaluating the Expr and converting
10938 * the result to a boolean. If the result is a number, the result will
10939 * be converted to true if the number is equal to the position of the
10940 * context node in the context node list (as returned by the position
10941 * function) and will be converted to false otherwise; if the result
10942 * is not a number, then the result will be converted as if by a call
10943 * to the boolean function.
10944 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000010945 * Returns 1 if predicate is true, 0 otherwise
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010946 */
10947int
10948xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10949 xmlXPathObjectPtr res) {
10950 if (res == NULL) return(0);
10951 switch (res->type) {
10952 case XPATH_BOOLEAN:
10953 return(res->boolval);
10954 case XPATH_NUMBER:
Daniel Veillard9ea62312004-04-29 14:04:09 +000010955#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
Daniel Veillard7c4eb632004-04-19 21:29:12 +000010956 return((res->floatval == ctxt->context->proximityPosition) &&
10957 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
Daniel Veillard2582a332004-04-18 19:49:46 +000010958#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010959 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard2582a332004-04-18 19:49:46 +000010960#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010961 case XPATH_NODESET:
10962 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +000010963 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +000010964 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010965 return(res->nodesetval->nodeNr != 0);
10966 case XPATH_STRING:
10967 return((res->stringval != NULL) &&
10968 (xmlStrlen(res->stringval) != 0));
William M. Brack08171912003-12-29 02:52:11 +000010969#ifdef LIBXML_XPTR_ENABLED
10970 case XPATH_LOCATIONSET:{
10971 xmlLocationSetPtr ptr = res->user;
10972 if (ptr == NULL)
10973 return(0);
10974 return (ptr->locNr != 0);
10975 }
10976#endif
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000010977 default:
10978 STRANGE
10979 }
10980 return(0);
10981}
10982
10983/**
Daniel Veillard4773df22004-01-23 13:15:13 +000010984 * xmlXPathCtxtCompile:
10985 * @ctxt: an XPath context
10986 * @str: the XPath expression
10987 *
10988 * Compile an XPath expression
10989 *
10990 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10991 * the caller has to free the object.
10992 */
10993xmlXPathCompExprPtr
10994xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
10995 xmlXPathParserContextPtr pctxt;
10996 xmlXPathCompExprPtr comp;
10997
10998 xmlXPathInit();
10999
11000 pctxt = xmlXPathNewParserContext(str, ctxt);
11001 xmlXPathCompileExpr(pctxt);
11002
11003 if( pctxt->error != XPATH_EXPRESSION_OK )
11004 {
11005 xmlXPathFreeParserContext(pctxt);
11006 return (0);
11007 }
11008
11009 if (*pctxt->cur != 0) {
11010 /*
11011 * aleksey: in some cases this line prints *second* error message
11012 * (see bug #78858) and probably this should be fixed.
11013 * However, we are not sure that all error messages are printed
11014 * out in other places. It's not critical so we leave it as-is for now
11015 */
11016 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11017 comp = NULL;
11018 } else {
11019 comp = pctxt->comp;
11020 pctxt->comp = NULL;
11021 }
11022 xmlXPathFreeParserContext(pctxt);
11023 if (comp != NULL) {
11024 comp->expr = xmlStrdup(str);
11025#ifdef DEBUG_EVAL_COUNTS
11026 comp->string = xmlStrdup(str);
11027 comp->nb = 0;
11028#endif
11029 }
11030 return(comp);
11031}
11032
11033/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011034 * xmlXPathCompile:
11035 * @str: the XPath expression
11036 *
11037 * Compile an XPath expression
11038 *
Daniel Veillard591b4be2003-02-09 23:33:36 +000011039 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011040 * the caller has to free the object.
11041 */
11042xmlXPathCompExprPtr
11043xmlXPathCompile(const xmlChar *str) {
Daniel Veillard4773df22004-01-23 13:15:13 +000011044 return(xmlXPathCtxtCompile(NULL, str));
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011045}
11046
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011047/**
11048 * xmlXPathCompiledEval:
11049 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +000011050 * @ctx: the XPath context
11051 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011052 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +000011053 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011054 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Owen Taylor3473f882001-02-23 17:55:21 +000011055 * the caller has to free the object.
11056 */
11057xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011058xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +000011059 xmlXPathParserContextPtr ctxt;
11060 xmlXPathObjectPtr res, tmp, init = NULL;
11061 int stack = 0;
Daniel Veillard81463942001-10-16 12:34:39 +000011062#ifndef LIBXML_THREAD_ENABLED
11063 static int reentance = 0;
11064#endif
Owen Taylor3473f882001-02-23 17:55:21 +000011065
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011066 if ((comp == NULL) || (ctx == NULL))
11067 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +000011068 xmlXPathInit();
11069
11070 CHECK_CONTEXT(ctx)
11071
Daniel Veillard81463942001-10-16 12:34:39 +000011072#ifndef LIBXML_THREAD_ENABLED
11073 reentance++;
11074 if (reentance > 1)
11075 xmlXPathDisableOptimizer = 1;
11076#endif
11077
Daniel Veillardf06307e2001-07-03 10:35:50 +000011078#ifdef DEBUG_EVAL_COUNTS
11079 comp->nb++;
11080 if ((comp->string != NULL) && (comp->nb > 100)) {
11081 fprintf(stderr, "100 x %s\n", comp->string);
11082 comp->nb = 0;
11083 }
11084#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011085 ctxt = xmlXPathCompParserContext(comp, ctx);
11086 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011087
11088 if (ctxt->value == NULL) {
11089 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011090 "xmlXPathCompiledEval: evaluation failed\n");
Owen Taylor3473f882001-02-23 17:55:21 +000011091 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +000011092 } else {
11093 res = valuePop(ctxt);
11094 }
11095
Daniel Veillardf06307e2001-07-03 10:35:50 +000011096
Owen Taylor3473f882001-02-23 17:55:21 +000011097 do {
11098 tmp = valuePop(ctxt);
11099 if (tmp != NULL) {
11100 if (tmp != init)
11101 stack++;
11102 xmlXPathFreeObject(tmp);
11103 }
11104 } while (tmp != NULL);
11105 if ((stack != 0) && (res != NULL)) {
11106 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011107 "xmlXPathCompiledEval: %d object left on the stack\n",
Owen Taylor3473f882001-02-23 17:55:21 +000011108 stack);
11109 }
11110 if (ctxt->error != XPATH_EXPRESSION_OK) {
11111 xmlXPathFreeObject(res);
11112 res = NULL;
11113 }
11114
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011115
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011116 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011117 xmlXPathFreeParserContext(ctxt);
Daniel Veillard81463942001-10-16 12:34:39 +000011118#ifndef LIBXML_THREAD_ENABLED
11119 reentance--;
11120#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011121 return(res);
11122}
11123
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011124/**
11125 * xmlXPathEvalExpr:
11126 * @ctxt: the XPath Parser context
11127 *
11128 * Parse and evaluate an XPath expression in the given context,
11129 * then push the result on the context stack
11130 */
11131void
11132xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
11133 xmlXPathCompileExpr(ctxt);
Aleksey Sanin50fe8b12002-05-07 16:21:36 +000011134 CHECK_ERROR;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +000011135 xmlXPathRunEval(ctxt);
11136}
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011137
11138/**
11139 * xmlXPathEval:
11140 * @str: the XPath expression
11141 * @ctx: the XPath context
11142 *
11143 * Evaluate the XPath Location Path in the given context.
11144 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +000011145 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011146 * the caller has to free the object.
11147 */
11148xmlXPathObjectPtr
11149xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
11150 xmlXPathParserContextPtr ctxt;
11151 xmlXPathObjectPtr res, tmp, init = NULL;
11152 int stack = 0;
11153
11154 xmlXPathInit();
11155
11156 CHECK_CONTEXT(ctx)
11157
11158 ctxt = xmlXPathNewParserContext(str, ctx);
11159 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +000011160
11161 if (ctxt->value == NULL) {
11162 xmlGenericError(xmlGenericErrorContext,
11163 "xmlXPathEval: evaluation failed\n");
11164 res = NULL;
11165 } else if (*ctxt->cur != 0) {
11166 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11167 res = NULL;
11168 } else {
11169 res = valuePop(ctxt);
11170 }
11171
11172 do {
11173 tmp = valuePop(ctxt);
11174 if (tmp != NULL) {
11175 if (tmp != init)
11176 stack++;
11177 xmlXPathFreeObject(tmp);
11178 }
11179 } while (tmp != NULL);
11180 if ((stack != 0) && (res != NULL)) {
11181 xmlGenericError(xmlGenericErrorContext,
11182 "xmlXPathEval: %d object left on the stack\n",
11183 stack);
11184 }
11185 if (ctxt->error != XPATH_EXPRESSION_OK) {
11186 xmlXPathFreeObject(res);
11187 res = NULL;
11188 }
11189
Owen Taylor3473f882001-02-23 17:55:21 +000011190 xmlXPathFreeParserContext(ctxt);
11191 return(res);
11192}
11193
11194/**
11195 * xmlXPathEvalExpression:
11196 * @str: the XPath expression
11197 * @ctxt: the XPath context
11198 *
11199 * Evaluate the XPath expression in the given context.
11200 *
11201 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
11202 * the caller has to free the object.
11203 */
11204xmlXPathObjectPtr
11205xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
11206 xmlXPathParserContextPtr pctxt;
11207 xmlXPathObjectPtr res, tmp;
11208 int stack = 0;
11209
11210 xmlXPathInit();
11211
11212 CHECK_CONTEXT(ctxt)
11213
11214 pctxt = xmlXPathNewParserContext(str, ctxt);
11215 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +000011216
11217 if (*pctxt->cur != 0) {
11218 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11219 res = NULL;
11220 } else {
11221 res = valuePop(pctxt);
11222 }
11223 do {
11224 tmp = valuePop(pctxt);
11225 if (tmp != NULL) {
11226 xmlXPathFreeObject(tmp);
11227 stack++;
11228 }
11229 } while (tmp != NULL);
11230 if ((stack != 0) && (res != NULL)) {
11231 xmlGenericError(xmlGenericErrorContext,
11232 "xmlXPathEvalExpression: %d object left on the stack\n",
11233 stack);
11234 }
11235 xmlXPathFreeParserContext(pctxt);
11236 return(res);
11237}
11238
Daniel Veillard42766c02002-08-22 20:52:17 +000011239/************************************************************************
11240 * *
11241 * Extra functions not pertaining to the XPath spec *
11242 * *
11243 ************************************************************************/
11244/**
11245 * xmlXPathEscapeUriFunction:
11246 * @ctxt: the XPath Parser context
11247 * @nargs: the number of arguments
11248 *
11249 * Implement the escape-uri() XPath function
11250 * string escape-uri(string $str, bool $escape-reserved)
11251 *
11252 * This function applies the URI escaping rules defined in section 2 of [RFC
11253 * 2396] to the string supplied as $uri-part, which typically represents all
11254 * or part of a URI. The effect of the function is to replace any special
11255 * character in the string by an escape sequence of the form %xx%yy...,
11256 * where xxyy... is the hexadecimal representation of the octets used to
11257 * represent the character in UTF-8.
11258 *
11259 * The set of characters that are escaped depends on the setting of the
11260 * boolean argument $escape-reserved.
11261 *
11262 * If $escape-reserved is true, all characters are escaped other than lower
11263 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
11264 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
11265 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
11266 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
11267 * A-F).
11268 *
11269 * If $escape-reserved is false, the behavior differs in that characters
11270 * referred to in [RFC 2396] as reserved characters are not escaped. These
11271 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
11272 *
11273 * [RFC 2396] does not define whether escaped URIs should use lower case or
11274 * upper case for hexadecimal digits. To ensure that escaped URIs can be
11275 * compared using string comparison functions, this function must always use
11276 * the upper-case letters A-F.
11277 *
11278 * Generally, $escape-reserved should be set to true when escaping a string
11279 * that is to form a single part of a URI, and to false when escaping an
11280 * entire URI or URI reference.
11281 *
11282 * In the case of non-ascii characters, the string is encoded according to
11283 * utf-8 and then converted according to RFC 2396.
11284 *
11285 * Examples
11286 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
11287 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
11288 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
11289 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
11290 *
11291 */
Daniel Veillard118aed72002-09-24 14:13:13 +000011292static void
Daniel Veillard42766c02002-08-22 20:52:17 +000011293xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
11294 xmlXPathObjectPtr str;
11295 int escape_reserved;
11296 xmlBufferPtr target;
11297 xmlChar *cptr;
11298 xmlChar escape[4];
11299
11300 CHECK_ARITY(2);
11301
11302 escape_reserved = xmlXPathPopBoolean(ctxt);
11303
11304 CAST_TO_STRING;
11305 str = valuePop(ctxt);
11306
11307 target = xmlBufferCreate();
11308
11309 escape[0] = '%';
11310 escape[3] = 0;
11311
11312 if (target) {
11313 for (cptr = str->stringval; *cptr; cptr++) {
11314 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11315 (*cptr >= 'a' && *cptr <= 'z') ||
11316 (*cptr >= '0' && *cptr <= '9') ||
11317 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11318 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11319 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11320 (*cptr == '%' &&
11321 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11322 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11323 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11324 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11325 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11326 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11327 (!escape_reserved &&
11328 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11329 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11330 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11331 *cptr == ','))) {
11332 xmlBufferAdd(target, cptr, 1);
11333 } else {
11334 if ((*cptr >> 4) < 10)
11335 escape[1] = '0' + (*cptr >> 4);
11336 else
11337 escape[1] = 'A' - 10 + (*cptr >> 4);
11338 if ((*cptr & 0xF) < 10)
11339 escape[2] = '0' + (*cptr & 0xF);
11340 else
11341 escape[2] = 'A' - 10 + (*cptr & 0xF);
11342
11343 xmlBufferAdd(target, &escape[0], 3);
11344 }
11345 }
11346 }
11347 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11348 xmlBufferFree(target);
11349 xmlXPathFreeObject(str);
11350}
11351
Owen Taylor3473f882001-02-23 17:55:21 +000011352/**
11353 * xmlXPathRegisterAllFunctions:
11354 * @ctxt: the XPath context
11355 *
11356 * Registers all default XPath functions in this context
11357 */
11358void
11359xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11360{
11361 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11362 xmlXPathBooleanFunction);
11363 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11364 xmlXPathCeilingFunction);
11365 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11366 xmlXPathCountFunction);
11367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11368 xmlXPathConcatFunction);
11369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11370 xmlXPathContainsFunction);
11371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11372 xmlXPathIdFunction);
11373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11374 xmlXPathFalseFunction);
11375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11376 xmlXPathFloorFunction);
11377 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11378 xmlXPathLastFunction);
11379 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11380 xmlXPathLangFunction);
11381 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11382 xmlXPathLocalNameFunction);
11383 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11384 xmlXPathNotFunction);
11385 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11386 xmlXPathNameFunction);
11387 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11388 xmlXPathNamespaceURIFunction);
11389 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11390 xmlXPathNormalizeFunction);
11391 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11392 xmlXPathNumberFunction);
11393 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11394 xmlXPathPositionFunction);
11395 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11396 xmlXPathRoundFunction);
11397 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11398 xmlXPathStringFunction);
11399 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11400 xmlXPathStringLengthFunction);
11401 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11402 xmlXPathStartsWithFunction);
11403 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11404 xmlXPathSubstringFunction);
11405 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11406 xmlXPathSubstringBeforeFunction);
11407 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11408 xmlXPathSubstringAfterFunction);
11409 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11410 xmlXPathSumFunction);
11411 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11412 xmlXPathTrueFunction);
11413 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11414 xmlXPathTranslateFunction);
Daniel Veillard42766c02002-08-22 20:52:17 +000011415
11416 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11417 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11418 xmlXPathEscapeUriFunction);
Owen Taylor3473f882001-02-23 17:55:21 +000011419}
11420
11421#endif /* LIBXML_XPATH_ENABLED */